aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClément Perrochaud <clement.perrochaud@nxp.com>2015-03-09 06:12:05 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2015-03-26 06:21:41 -0400
commit6be88670fc59d50426f90f734a36b90e1de7d148 (patch)
tree8296eaff5b2747937b4239fcee58f5fa380926dc
parentdece45855a8b0d1dcf48eb01d0822070ded6a4c8 (diff)
NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver
Add a module to the NXP-NCI driver to support NFC controllers with an I2C control interface, such as the NPC100. Signed-off-by: Clément Perrochaud <clement.perrochaud@effinnov.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--Documentation/devicetree/bindings/net/nfc/nxp-nci.txt35
-rw-r--r--drivers/nfc/nxp-nci/Kconfig12
-rw-r--r--drivers/nfc/nxp-nci/Makefile2
-rw-r--r--drivers/nfc/nxp-nci/i2c.c415
4 files changed, 464 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
new file mode 100644
index 000000000000..5b6cd9b3f628
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
@@ -0,0 +1,35 @@
1* NXP Semiconductors NXP NCI NFC Controllers
2
3Required properties:
4- compatible: Should be "nxp,nxp-nci-i2c".
5- clock-frequency: I²C work frequency.
6- reg: address on the bus
7- interrupt-parent: phandle for the interrupt gpio controller
8- interrupts: GPIO interrupt to which the chip is connected
9- enable-gpios: Output GPIO pin used for enabling/disabling the chip
10- firmware-gpios: Output GPIO pin used to enter firmware download mode
11
12Optional SoC Specific Properties:
13- pinctrl-names: Contains only one value - "default".
14- pintctrl-0: Specifies the pin control groups used for this controller.
15
16Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2):
17
18&i2c2 {
19
20 status = "okay";
21
22 npc100: npc100@29 {
23
24 compatible = "nxp,nxp-nci-i2c";
25
26 reg = <0x29>;
27 clock-frequency = <100000>;
28
29 interrupt-parent = <&gpio1>;
30 interrupts = <29 GPIO_ACTIVE_HIGH>;
31
32 enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
33 firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
34 };
35};
diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig
index 5f60c7cf02e8..37b40612520d 100644
--- a/drivers/nfc/nxp-nci/Kconfig
+++ b/drivers/nfc/nxp-nci/Kconfig
@@ -11,3 +11,15 @@ config NFC_NXP_NCI
11 To compile this driver as a module, choose m here. The module will 11 To compile this driver as a module, choose m here. The module will
12 be called nxp_nci. 12 be called nxp_nci.
13 Say N if unsure. 13 Say N if unsure.
14
15config NFC_NXP_NCI_I2C
16 tristate "NXP-NCI I2C support"
17 depends on NFC_NXP_NCI && I2C
18 ---help---
19 This module adds support for an I2C interface to the NXP NCI
20 chips.
21 Select this if your platform is using the I2C bus.
22
23 To compile this driver as a module, choose m here. The module will
24 be called nxp_nci_i2c.
25 Say Y if unsure.
diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile
index 8f1e32826961..c008be30bb18 100644
--- a/drivers/nfc/nxp-nci/Makefile
+++ b/drivers/nfc/nxp-nci/Makefile
@@ -3,7 +3,9 @@
3# 3#
4 4
5nxp-nci-objs = core.o firmware.o 5nxp-nci-objs = core.o firmware.o
6nxp-nci_i2c-objs = i2c.o
6 7
7obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o 8obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
9obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o
8 10
9ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG 11ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
new file mode 100644
index 000000000000..17bd67dbebf0
--- /dev/null
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -0,0 +1,415 @@
1/*
2 * I2C link layer for the NXP NCI driver
3 *
4 * Copyright (C) 2014 NXP Semiconductors All rights reserved.
5 *
6 * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
7 *
8 * Derived from PN544 device driver:
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2, as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#include <linux/delay.h>
27#include <linux/i2c.h>
28#include <linux/interrupt.h>
29#include <linux/miscdevice.h>
30#include <linux/module.h>
31#include <linux/nfc.h>
32#include <linux/of_gpio.h>
33#include <linux/of_irq.h>
34#include <linux/platform_data/nxp-nci.h>
35#include <linux/unaligned/access_ok.h>
36
37#include <net/nfc/nfc.h>
38
39#include "nxp-nci.h"
40
41#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c"
42
43#define NXP_NCI_I2C_MAX_PAYLOAD 32
44
45struct nxp_nci_i2c_phy {
46 struct i2c_client *i2c_dev;
47 struct nci_dev *ndev;
48
49 unsigned int gpio_en;
50 unsigned int gpio_fw;
51
52 int hard_fault; /*
53 * < 0 if hardware error occurred (e.g. i2c err)
54 * and prevents normal operation.
55 */
56};
57
58static int nxp_nci_i2c_set_mode(void *phy_id,
59 enum nxp_nci_mode mode)
60{
61 struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
62
63 gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
64 gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
65 usleep_range(10000, 15000);
66
67 if (mode == NXP_NCI_MODE_COLD)
68 phy->hard_fault = 0;
69
70 return 0;
71}
72
73static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
74{
75 int r;
76 struct nxp_nci_i2c_phy *phy = phy_id;
77 struct i2c_client *client = phy->i2c_dev;
78
79 if (phy->hard_fault != 0)
80 return phy->hard_fault;
81
82 r = i2c_master_send(client, skb->data, skb->len);
83 if (r == -EREMOTEIO) {
84 /* Retry, chip was in standby */
85 usleep_range(110000, 120000);
86 r = i2c_master_send(client, skb->data, skb->len);
87 }
88
89 if (r < 0) {
90 nfc_err(&client->dev, "Error %d on I2C send\n", r);
91 } else if (r != skb->len) {
92 nfc_err(&client->dev,
93 "Invalid length sent: %u (expected %u)\n",
94 r, skb->len);
95 r = -EREMOTEIO;
96 } else {
97 /* Success but return 0 and not number of bytes */
98 r = 0;
99 }
100
101 return r;
102}
103
104static struct nxp_nci_phy_ops i2c_phy_ops = {
105 .set_mode = nxp_nci_i2c_set_mode,
106 .write = nxp_nci_i2c_write,
107};
108
109static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
110 struct sk_buff **skb)
111{
112 struct i2c_client *client = phy->i2c_dev;
113 u16 header;
114 size_t frame_len;
115 int r;
116
117 r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN);
118 if (r < 0) {
119 goto fw_read_exit;
120 } else if (r != NXP_NCI_FW_HDR_LEN) {
121 nfc_err(&client->dev, "Incorrect header length: %u\n", r);
122 r = -EBADMSG;
123 goto fw_read_exit;
124 }
125
126 frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) +
127 NXP_NCI_FW_CRC_LEN;
128
129 *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
130 if (*skb == NULL) {
131 r = -ENOMEM;
132 goto fw_read_exit;
133 }
134
135 memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN);
136
137 r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
138 if (r != frame_len) {
139 nfc_err(&client->dev,
140 "Invalid frame length: %u (expected %zu)\n",
141 r, frame_len);
142 r = -EBADMSG;
143 goto fw_read_exit_free_skb;
144 }
145
146 return 0;
147
148fw_read_exit_free_skb:
149 kfree_skb(*skb);
150fw_read_exit:
151 return r;
152}
153
154static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
155 struct sk_buff **skb)
156{
157 struct nci_ctrl_hdr header; /* May actually be a data header */
158 struct i2c_client *client = phy->i2c_dev;
159 int r;
160
161 r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE);
162 if (r < 0) {
163 goto nci_read_exit;
164 } else if (r != NCI_CTRL_HDR_SIZE) {
165 nfc_err(&client->dev, "Incorrect header length: %u\n", r);
166 r = -EBADMSG;
167 goto nci_read_exit;
168 }
169
170 *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL);
171 if (*skb == NULL) {
172 r = -ENOMEM;
173 goto nci_read_exit;
174 }
175
176 memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header,
177 NCI_CTRL_HDR_SIZE);
178
179 r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
180 if (r != header.plen) {
181 nfc_err(&client->dev,
182 "Invalid frame payload length: %u (expected %u)\n",
183 r, header.plen);
184 r = -EBADMSG;
185 goto nci_read_exit_free_skb;
186 }
187
188 return 0;
189
190nci_read_exit_free_skb:
191 kfree_skb(*skb);
192nci_read_exit:
193 return r;
194}
195
196static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
197{
198 struct nxp_nci_i2c_phy *phy = phy_id;
199 struct i2c_client *client;
200 struct nxp_nci_info *info;
201
202 struct sk_buff *skb = NULL;
203 int r = 0;
204
205 if (!phy || !phy->ndev)
206 goto exit_irq_none;
207
208 client = phy->i2c_dev;
209
210 if (!client || irq != client->irq)
211 goto exit_irq_none;
212
213 info = nci_get_drvdata(phy->ndev);
214
215 if (!info)
216 goto exit_irq_none;
217
218 mutex_lock(&info->info_lock);
219
220 if (phy->hard_fault != 0)
221 goto exit_irq_handled;
222
223 switch (info->mode) {
224 case NXP_NCI_MODE_NCI:
225 r = nxp_nci_i2c_nci_read(phy, &skb);
226 break;
227 case NXP_NCI_MODE_FW:
228 r = nxp_nci_i2c_fw_read(phy, &skb);
229 break;
230 case NXP_NCI_MODE_COLD:
231 r = -EREMOTEIO;
232 break;
233 }
234
235 if (r == -EREMOTEIO) {
236 phy->hard_fault = r;
237 skb = NULL;
238 } else if (r < 0) {
239 nfc_err(&client->dev, "Read failed with error %d\n", r);
240 goto exit_irq_handled;
241 }
242
243 switch (info->mode) {
244 case NXP_NCI_MODE_NCI:
245 nci_recv_frame(phy->ndev, skb);
246 break;
247 case NXP_NCI_MODE_FW:
248 nxp_nci_fw_recv_frame(phy->ndev, skb);
249 break;
250 case NXP_NCI_MODE_COLD:
251 break;
252 }
253
254exit_irq_handled:
255 mutex_unlock(&info->info_lock);
256 return IRQ_HANDLED;
257exit_irq_none:
258 WARN_ON_ONCE(1);
259 return IRQ_NONE;
260}
261
262#ifdef CONFIG_OF
263
264static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
265{
266 struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
267 struct device_node *pp;
268 int r;
269
270 pp = client->dev.of_node;
271 if (!pp)
272 return -ENODEV;
273
274 r = of_get_named_gpio(pp, "enable-gpios", 0);
275 if (r == -EPROBE_DEFER)
276 r = of_get_named_gpio(pp, "enable-gpios", 0);
277 if (r < 0) {
278 nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r);
279 return r;
280 }
281 phy->gpio_en = r;
282
283 r = of_get_named_gpio(pp, "firmware-gpios", 0);
284 if (r == -EPROBE_DEFER)
285 r = of_get_named_gpio(pp, "firmware-gpios", 0);
286 if (r < 0) {
287 nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r);
288 return r;
289 }
290 phy->gpio_fw = r;
291
292 r = irq_of_parse_and_map(pp, 0);
293 if (r < 0) {
294 nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
295 return r;
296 }
297 client->irq = r;
298
299 return 0;
300}
301
302#else
303
304static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
305{
306 return -ENODEV;
307}
308
309#endif
310
311static int nxp_nci_i2c_probe(struct i2c_client *client,
312 const struct i2c_device_id *id)
313{
314 struct nxp_nci_i2c_phy *phy;
315 struct nxp_nci_nfc_platform_data *pdata;
316 int r;
317
318 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
319 nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
320 r = -ENODEV;
321 goto probe_exit;
322 }
323
324 phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy),
325 GFP_KERNEL);
326 if (!phy) {
327 r = -ENOMEM;
328 goto probe_exit;
329 }
330
331 phy->i2c_dev = client;
332 i2c_set_clientdata(client, phy);
333
334 pdata = client->dev.platform_data;
335
336 if (!pdata && client->dev.of_node) {
337 r = nxp_nci_i2c_parse_devtree(client);
338 if (r < 0) {
339 nfc_err(&client->dev, "Failed to get DT data\n");
340 goto probe_exit;
341 }
342 } else if (pdata) {
343 phy->gpio_en = pdata->gpio_en;
344 phy->gpio_fw = pdata->gpio_fw;
345 client->irq = pdata->irq;
346 } else {
347 nfc_err(&client->dev, "No platform data\n");
348 r = -EINVAL;
349 goto probe_exit;
350 }
351
352 r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en,
353 GPIOF_OUT_INIT_LOW, "nxp_nci_en");
354 if (r < 0)
355 goto probe_exit;
356
357 r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw,
358 GPIOF_OUT_INIT_LOW, "nxp_nci_fw");
359 if (r < 0)
360 goto probe_exit;
361
362 r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
363 NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
364 if (r < 0)
365 goto probe_exit;
366
367 r = request_threaded_irq(client->irq, NULL,
368 nxp_nci_i2c_irq_thread_fn,
369 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
370 NXP_NCI_I2C_DRIVER_NAME, phy);
371 if (r < 0)
372 nfc_err(&client->dev, "Unable to register IRQ handler\n");
373
374probe_exit:
375 return r;
376}
377
378static int nxp_nci_i2c_remove(struct i2c_client *client)
379{
380 struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
381
382 nxp_nci_remove(phy->ndev);
383 free_irq(client->irq, phy);
384
385 return 0;
386}
387
388static struct i2c_device_id nxp_nci_i2c_id_table[] = {
389 {"nxp-nci_i2c", 0},
390 {}
391};
392MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
393
394static const struct of_device_id of_nxp_nci_i2c_match[] = {
395 { .compatible = "nxp,nxp-nci-i2c", },
396 {},
397};
398MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
399
400static struct i2c_driver nxp_nci_i2c_driver = {
401 .driver = {
402 .name = NXP_NCI_I2C_DRIVER_NAME,
403 .owner = THIS_MODULE,
404 .of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
405 },
406 .probe = nxp_nci_i2c_probe,
407 .id_table = nxp_nci_i2c_id_table,
408 .remove = nxp_nci_i2c_remove,
409};
410
411module_i2c_driver(nxp_nci_i2c_driver);
412
413MODULE_LICENSE("GPL");
414MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
415MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");