xref: /openbmc/linux/drivers/nfc/nxp-nci/core.c (revision 8ab59da2)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Generic driver for NXP NCI NFC chips
4  *
5  * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
6  *
7  * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
8  *
9  * Derived from PN544 device driver:
10  * Copyright (C) 2012  Intel Corporation. All rights reserved.
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/module.h>
15 #include <linux/nfc.h>
16 
17 #include <net/nfc/nci_core.h>
18 
19 #include "nxp-nci.h"
20 
21 #define NXP_NCI_HDR_LEN	4
22 
23 #define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
24 			       NFC_PROTO_MIFARE_MASK | \
25 			       NFC_PROTO_FELICA_MASK | \
26 			       NFC_PROTO_ISO14443_MASK | \
27 			       NFC_PROTO_ISO14443_B_MASK | \
28 			       NFC_PROTO_NFC_DEP_MASK)
29 
30 #define NXP_NCI_RF_PLL_UNLOCKED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x21)
31 #define NXP_NCI_RF_TXLDO_ERROR_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x23)
32 
33 static int nxp_nci_open(struct nci_dev *ndev)
34 {
35 	struct nxp_nci_info *info = nci_get_drvdata(ndev);
36 	int r = 0;
37 
38 	mutex_lock(&info->info_lock);
39 
40 	if (info->mode != NXP_NCI_MODE_COLD) {
41 		r = -EBUSY;
42 		goto open_exit;
43 	}
44 
45 	if (info->phy_ops->set_mode)
46 		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI);
47 
48 	info->mode = NXP_NCI_MODE_NCI;
49 
50 open_exit:
51 	mutex_unlock(&info->info_lock);
52 	return r;
53 }
54 
55 static int nxp_nci_close(struct nci_dev *ndev)
56 {
57 	struct nxp_nci_info *info = nci_get_drvdata(ndev);
58 	int r = 0;
59 
60 	mutex_lock(&info->info_lock);
61 
62 	if (info->phy_ops->set_mode)
63 		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
64 
65 	info->mode = NXP_NCI_MODE_COLD;
66 
67 	mutex_unlock(&info->info_lock);
68 	return r;
69 }
70 
71 static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
72 {
73 	struct nxp_nci_info *info = nci_get_drvdata(ndev);
74 	int r;
75 
76 	if (!info->phy_ops->write)
77 		return -EOPNOTSUPP;
78 
79 	if (info->mode != NXP_NCI_MODE_NCI)
80 		return -EINVAL;
81 
82 	r = info->phy_ops->write(info->phy_id, skb);
83 	if (r < 0)
84 		kfree_skb(skb);
85 
86 	return r;
87 }
88 
89 static int nxp_nci_rf_pll_unlocked_ntf(struct nci_dev *ndev,
90 				       struct sk_buff *skb)
91 {
92 	nfc_err(&ndev->nfc_dev->dev,
93 		"PLL didn't lock. Missing or unstable clock?\n");
94 
95 	return 0;
96 }
97 
98 static int nxp_nci_rf_txldo_error_ntf(struct nci_dev *ndev,
99 				      struct sk_buff *skb)
100 {
101 	nfc_err(&ndev->nfc_dev->dev,
102 		"RF transmitter couldn't start. Bad power and/or configuration?\n");
103 
104 	return 0;
105 }
106 
107 static const struct nci_driver_ops nxp_nci_core_ops[] = {
108 	{
109 		.opcode = NXP_NCI_RF_PLL_UNLOCKED_NTF,
110 		.ntf = nxp_nci_rf_pll_unlocked_ntf,
111 	},
112 	{
113 		.opcode = NXP_NCI_RF_TXLDO_ERROR_NTF,
114 		.ntf = nxp_nci_rf_txldo_error_ntf,
115 	},
116 };
117 
118 static const struct nci_ops nxp_nci_ops = {
119 	.open = nxp_nci_open,
120 	.close = nxp_nci_close,
121 	.send = nxp_nci_send,
122 	.fw_download = nxp_nci_fw_download,
123 	.core_ops = nxp_nci_core_ops,
124 	.n_core_ops = ARRAY_SIZE(nxp_nci_core_ops),
125 };
126 
127 int nxp_nci_probe(void *phy_id, struct device *pdev,
128 		  const struct nxp_nci_phy_ops *phy_ops,
129 		  unsigned int max_payload,
130 		  struct nci_dev **ndev)
131 {
132 	struct nxp_nci_info *info;
133 	int r;
134 
135 	info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
136 	if (!info)
137 		return -ENOMEM;
138 
139 	info->phy_id = phy_id;
140 	info->pdev = pdev;
141 	info->phy_ops = phy_ops;
142 	info->max_payload = max_payload;
143 	INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
144 	init_completion(&info->fw_info.cmd_completion);
145 	mutex_init(&info->info_lock);
146 
147 	if (info->phy_ops->set_mode) {
148 		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
149 		if (r < 0)
150 			return r;
151 	}
152 
153 	info->mode = NXP_NCI_MODE_COLD;
154 
155 	info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
156 					 NXP_NCI_HDR_LEN, 0);
157 	if (!info->ndev)
158 		return -ENOMEM;
159 
160 	nci_set_parent_dev(info->ndev, pdev);
161 	nci_set_drvdata(info->ndev, info);
162 	r = nci_register_device(info->ndev);
163 	if (r < 0) {
164 		nci_free_device(info->ndev);
165 		return r;
166 	}
167 
168 	*ndev = info->ndev;
169 	return r;
170 }
171 EXPORT_SYMBOL(nxp_nci_probe);
172 
173 void nxp_nci_remove(struct nci_dev *ndev)
174 {
175 	struct nxp_nci_info *info = nci_get_drvdata(ndev);
176 
177 	if (info->mode == NXP_NCI_MODE_FW)
178 		nxp_nci_fw_work_complete(info, -ESHUTDOWN);
179 	cancel_work_sync(&info->fw_info.work);
180 
181 	mutex_lock(&info->info_lock);
182 
183 	if (info->phy_ops->set_mode)
184 		info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
185 
186 	nci_unregister_device(ndev);
187 	nci_free_device(ndev);
188 
189 	mutex_unlock(&info->info_lock);
190 }
191 EXPORT_SYMBOL(nxp_nci_remove);
192 
193 MODULE_LICENSE("GPL");
194 MODULE_DESCRIPTION("NXP NCI NFC driver");
195 MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
196