aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2014-05-25 16:35:38 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2014-07-22 18:49:28 -0400
commit35630df68d6030daf12dde12ed07bbe26324e6ac (patch)
treeda7a3c8ed7ed6d31d9f9f02582be7d673c21716a
parent55537c7e7d76417303c32f84a8dd1a12e02c4409 (diff)
NFC: st21nfcb: Add driver for STMicroelectronics ST21NFCB NFC chip
Add driver for STMicroelectronics ST21NFCB NFC controller. ST21NFCB is using NCI protocol and a proprietary low level transport protocol called NDLC used on top. NDLC: The protocol defines 2 types of frame: - One type carrying NCI data (referred as DATAFRAME frames). - One type carrying protocol information used for flow control and error control mechanisms (referred as SUPERVISOR frames). After each frame transmission to the NFC controller, the device host SHALL waitfor an ACK (SUPERVISOR frame) reception before sending a new frame. The NFC controller MAY send a frame at anytime to the device host. The NFC controller MAY send a specific WAIT supervisor frame to indicate to device host that a NCI data packet has been received but that it could take significant time before the NFC controller sends an ACK and thus allows next data reception. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/nfc/Kconfig2
-rw-r--r--drivers/nfc/Makefile3
-rw-r--r--drivers/nfc/st21nfcb/Kconfig22
-rw-r--r--drivers/nfc/st21nfcb/Makefile8
-rw-r--r--drivers/nfc/st21nfcb/i2c.c462
-rw-r--r--drivers/nfc/st21nfcb/ndlc.c298
-rw-r--r--drivers/nfc/st21nfcb/ndlc.h55
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.c129
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.h38
-rw-r--r--include/linux/platform_data/st21nfcb.h32
10 files changed, 1047 insertions, 2 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 26c66a126551..7929fac13e1c 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -72,5 +72,5 @@ source "drivers/nfc/pn544/Kconfig"
72source "drivers/nfc/microread/Kconfig" 72source "drivers/nfc/microread/Kconfig"
73source "drivers/nfc/nfcmrvl/Kconfig" 73source "drivers/nfc/nfcmrvl/Kconfig"
74source "drivers/nfc/st21nfca/Kconfig" 74source "drivers/nfc/st21nfca/Kconfig"
75 75source "drivers/nfc/st21nfcb/Kconfig"
76endmenu 76endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 23225b0287fd..6b23a2c6e34a 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NFC_SIM) += nfcsim.o
11obj-$(CONFIG_NFC_PORT100) += port100.o 11obj-$(CONFIG_NFC_PORT100) += port100.o
12obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ 12obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
13obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o 13obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
14obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ 14obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
15obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
15 16
16ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG 17ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig
new file mode 100644
index 000000000000..e0322dd03a70
--- /dev/null
+++ b/drivers/nfc/st21nfcb/Kconfig
@@ -0,0 +1,22 @@
1config NFC_ST21NFCB
2 tristate "STMicroelectronics ST21NFCB NFC driver"
3 depends on NFC_NCI
4 default n
5 ---help---
6 STMicroelectronics ST21NFCB core driver. It implements the chipset
7 NCI logic and hooks into the NFC kernel APIs. Physical layers will
8 register against it.
9
10 To compile this driver as a module, choose m here. The module will
11 be called st21nfcb.
12 Say N if unsure.
13
14config NFC_ST21NFCB_I2C
15 tristate "NFC ST21NFCB i2c support"
16 depends on NFC_ST21NFCB && I2C
17 ---help---
18 This module adds support for the STMicroelectronics st21nfcb i2c interface.
19 Select this if your platform is using the i2c bus.
20
21 If you choose to build a module, it'll be called st21nfcb_i2c.
22 Say N if unsure.
diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile
new file mode 100644
index 000000000000..13d9f03b2fea
--- /dev/null
+++ b/drivers/nfc/st21nfcb/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for ST21NFCB NCI based NFC driver
3#
4
5st21nfcb_i2c-objs = i2c.o
6
7obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb.o ndlc.o
8obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c
new file mode 100644
index 000000000000..0f690baaef7a
--- /dev/null
+++ b/drivers/nfc/st21nfcb/i2c.c
@@ -0,0 +1,462 @@
1/*
2 * I2C Link Layer for ST21NFCB NCI based Driver
3 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/crc-ccitt.h>
21#include <linux/module.h>
22#include <linux/i2c.h>
23#include <linux/gpio.h>
24#include <linux/of_irq.h>
25#include <linux/of_gpio.h>
26#include <linux/miscdevice.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/nfc.h>
30#include <linux/firmware.h>
31#include <linux/unaligned/access_ok.h>
32#include <linux/platform_data/st21nfcb.h>
33
34#include <net/nfc/nci.h>
35#include <net/nfc/llc.h>
36#include <net/nfc/nfc.h>
37
38#include "ndlc.h"
39
40#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
41
42/* ndlc header */
43#define ST21NFCB_FRAME_HEADROOM 1
44#define ST21NFCB_FRAME_TAILROOM 0
45
46#define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
47#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
48
49#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c"
50
51static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = {
52 {ST21NFCB_NCI_DRIVER_NAME, 0},
53 {}
54};
55MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table);
56
57struct st21nfcb_i2c_phy {
58 struct i2c_client *i2c_dev;
59 struct llt_ndlc *ndlc;
60
61 unsigned int gpio_irq;
62 unsigned int gpio_reset;
63 unsigned int irq_polarity;
64
65 int powered;
66
67 /*
68 * < 0 if hardware error occured (e.g. i2c err)
69 * and prevents normal operation.
70 */
71 int hard_fault;
72};
73
74#define I2C_DUMP_SKB(info, skb) \
75do { \
76 pr_debug("%s:\n", info); \
77 print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \
78 16, 1, (skb)->data, (skb)->len, 0); \
79} while (0)
80
81static int st21nfcb_nci_i2c_enable(void *phy_id)
82{
83 struct st21nfcb_i2c_phy *phy = phy_id;
84
85 gpio_set_value(phy->gpio_reset, 0);
86 usleep_range(10000, 15000);
87 gpio_set_value(phy->gpio_reset, 1);
88 phy->powered = 1;
89 usleep_range(80000, 85000);
90
91 return 0;
92}
93
94static void st21nfcb_nci_i2c_disable(void *phy_id)
95{
96 struct st21nfcb_i2c_phy *phy = phy_id;
97
98 pr_info("\n");
99
100 phy->powered = 0;
101 /* reset chip in order to flush clf */
102 gpio_set_value(phy->gpio_reset, 0);
103 usleep_range(10000, 15000);
104 gpio_set_value(phy->gpio_reset, 1);
105}
106
107static void st21nfcb_nci_remove_header(struct sk_buff *skb)
108{
109 skb_pull(skb, ST21NFCB_FRAME_HEADROOM);
110}
111
112/*
113 * Writing a frame must not return the number of written bytes.
114 * It must return either zero for success, or <0 for error.
115 * In addition, it must not alter the skb
116 */
117static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
118{
119 int r = -1;
120 struct st21nfcb_i2c_phy *phy = phy_id;
121 struct i2c_client *client = phy->i2c_dev;
122
123 I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb);
124
125 if (phy->hard_fault != 0)
126 return phy->hard_fault;
127
128 r = i2c_master_send(client, skb->data, skb->len);
129 if (r == -EREMOTEIO) { /* Retry, chip was in standby */
130 usleep_range(1000, 4000);
131 r = i2c_master_send(client, skb->data, skb->len);
132 }
133
134 if (r >= 0) {
135 if (r != skb->len)
136 r = -EREMOTEIO;
137 else
138 r = 0;
139 }
140
141 st21nfcb_nci_remove_header(skb);
142
143 return r;
144}
145
146/*
147 * Reads an ndlc frame and returns it in a newly allocated sk_buff.
148 * returns:
149 * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at
150 * end of read)
151 * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF
152 * at end of read)
153 * -EREMOTEIO : i2c read error (fatal)
154 * -EBADMSG : frame was incorrect and discarded
155 * (value returned from st21nfcb_nci_i2c_repack)
156 * -EIO : if no ST21NFCB_SOF_EOF is found after reaching
157 * the read length end sequence
158 */
159static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
160 struct sk_buff **skb)
161{
162 int r;
163 u8 len;
164 u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE];
165 struct i2c_client *client = phy->i2c_dev;
166
167 r = i2c_master_recv(client, buf, 4);
168 if (r == -EREMOTEIO) { /* Retry, chip was in standby */
169 usleep_range(1000, 4000);
170 r = i2c_master_recv(client, buf, 4);
171 } else if (r != 4) {
172 nfc_err(&client->dev, "cannot read ndlc & nci header\n");
173 return -EREMOTEIO;
174 }
175
176 len = be16_to_cpu(*(__be16 *) (buf + 2));
177 if (len > ST21NFCB_NCI_I2C_MAX_SIZE) {
178 nfc_err(&client->dev, "invalid frame len\n");
179 return -EBADMSG;
180 }
181
182 *skb = alloc_skb(4 + len, GFP_KERNEL);
183 if (*skb == NULL)
184 return -ENOMEM;
185
186 skb_reserve(*skb, 4);
187 skb_put(*skb, 4);
188 memcpy((*skb)->data, buf, 4);
189
190 if (!len)
191 return 0;
192
193 r = i2c_master_recv(client, buf, len);
194 if (r != len) {
195 kfree_skb(*skb);
196 return -EREMOTEIO;
197 }
198
199 skb_put(*skb, len);
200 memcpy((*skb)->data + 4, buf, len);
201
202 I2C_DUMP_SKB("i2c frame read", *skb);
203
204 return 0;
205}
206
207/*
208 * Reads an ndlc frame from the chip.
209 *
210 * On ST21NFCB, IRQ goes in idle state when read starts.
211 */
212static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
213{
214 struct st21nfcb_i2c_phy *phy = phy_id;
215 struct i2c_client *client;
216 struct sk_buff *skb = NULL;
217 int r;
218
219 if (!phy || irq != phy->i2c_dev->irq) {
220 WARN_ON_ONCE(1);
221 return IRQ_NONE;
222 }
223
224 client = phy->i2c_dev;
225 dev_dbg(&client->dev, "IRQ\n");
226
227 if (phy->hard_fault)
228 return IRQ_HANDLED;
229
230 if (!phy->powered) {
231 st21nfcb_nci_i2c_disable(phy);
232 return IRQ_HANDLED;
233 }
234
235 r = st21nfcb_nci_i2c_read(phy, &skb);
236 if (r == -EREMOTEIO) {
237 phy->hard_fault = r;
238 ndlc_recv(phy->ndlc, NULL);
239 return IRQ_HANDLED;
240 } else if (r == -ENOMEM || r == -EBADMSG) {
241 return IRQ_HANDLED;
242 }
243
244 ndlc_recv(phy->ndlc, skb);
245
246 return IRQ_HANDLED;
247}
248
249static struct nfc_phy_ops i2c_phy_ops = {
250 .write = st21nfcb_nci_i2c_write,
251 .enable = st21nfcb_nci_i2c_enable,
252 .disable = st21nfcb_nci_i2c_disable,
253};
254
255#ifdef CONFIG_OF
256static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
257{
258 struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
259 struct device_node *pp;
260 int gpio;
261 int r;
262
263 pp = client->dev.of_node;
264 if (!pp)
265 return -ENODEV;
266
267 /* Get GPIO from device tree */
268 gpio = of_get_named_gpio(pp, "reset-gpios", 0);
269 if (gpio < 0) {
270 nfc_err(&client->dev,
271 "Failed to retrieve reset-gpios from device tree\n");
272 return gpio;
273 }
274
275 /* GPIO request and configuration */
276 r = devm_gpio_request(&client->dev, gpio, "clf_reset");
277 if (r) {
278 nfc_err(&client->dev, "Failed to request reset pin\n");
279 return -ENODEV;
280 }
281
282 r = gpio_direction_output(gpio, 1);
283 if (r) {
284 nfc_err(&client->dev,
285 "Failed to set reset pin direction as output\n");
286 return -ENODEV;
287 }
288 phy->gpio_reset = gpio;
289
290 /* IRQ */
291 r = irq_of_parse_and_map(pp, 0);
292 if (r < 0) {
293 nfc_err(&client->dev,
294 "Unable to get irq, error: %d\n", r);
295 return r;
296 }
297
298 phy->irq_polarity = irq_get_trigger_type(r);
299 client->irq = r;
300
301 return 0;
302}
303#else
304static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
305{
306 return -ENODEV;
307}
308#endif
309
310static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
311{
312 struct st21nfcb_nfc_platform_data *pdata;
313 struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
314 int r;
315 int irq;
316
317 pdata = client->dev.platform_data;
318 if (pdata == NULL) {
319 nfc_err(&client->dev, "No platform data\n");
320 return -EINVAL;
321 }
322
323 /* store for later use */
324 phy->gpio_irq = pdata->gpio_irq;
325 phy->gpio_reset = pdata->gpio_reset;
326 phy->irq_polarity = pdata->irq_polarity;
327
328 r = devm_gpio_request(&client->dev, phy->gpio_irq, "wake_up");
329 if (r) {
330 pr_err("%s : gpio_request failed\n", __FILE__);
331 return -ENODEV;
332 }
333
334 r = gpio_direction_input(phy->gpio_irq);
335 if (r) {
336 pr_err("%s : gpio_direction_input failed\n", __FILE__);
337 return -ENODEV;
338 }
339
340 r = devm_gpio_request(&client->dev,
341 phy->gpio_reset, "clf_reset");
342 if (r) {
343 pr_err("%s : reset gpio_request failed\n", __FILE__);
344 return -ENODEV;
345 }
346
347 r = gpio_direction_output(phy->gpio_reset, 1);
348 if (r) {
349 pr_err("%s : reset gpio_direction_output failed\n",
350 __FILE__);
351 return -ENODEV;
352 }
353
354 /* IRQ */
355 irq = gpio_to_irq(phy->gpio_irq);
356 if (irq < 0) {
357 nfc_err(&client->dev,
358 "Unable to get irq number for GPIO %d error %d\n",
359 phy->gpio_irq, r);
360 return -ENODEV;
361 }
362 client->irq = irq;
363
364 return 0;
365}
366
367static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
368 const struct i2c_device_id *id)
369{
370 struct st21nfcb_i2c_phy *phy;
371 struct st21nfcb_nfc_platform_data *pdata;
372 int r;
373
374 dev_dbg(&client->dev, "%s\n", __func__);
375 dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
376
377 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
378 nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
379 return -ENODEV;
380 }
381
382 phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy),
383 GFP_KERNEL);
384 if (!phy) {
385 nfc_err(&client->dev,
386 "Cannot allocate memory for st21nfcb i2c phy.\n");
387 return -ENOMEM;
388 }
389
390 phy->i2c_dev = client;
391
392 i2c_set_clientdata(client, phy);
393
394 pdata = client->dev.platform_data;
395 if (!pdata && client->dev.of_node) {
396 r = st21nfcb_nci_i2c_of_request_resources(client);
397 if (r) {
398 nfc_err(&client->dev, "No platform data\n");
399 return r;
400 }
401 } else if (pdata) {
402 r = st21nfcb_nci_i2c_request_resources(client);
403 if (r) {
404 nfc_err(&client->dev,
405 "Cannot get platform resources\n");
406 return r;
407 }
408 } else {
409 nfc_err(&client->dev,
410 "st21nfcb platform resources not available\n");
411 return -ENODEV;
412 }
413
414 r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
415 st21nfcb_nci_irq_thread_fn,
416 phy->irq_polarity | IRQF_ONESHOT,
417 ST21NFCB_NCI_DRIVER_NAME, phy);
418 if (r < 0) {
419 nfc_err(&client->dev, "Unable to register IRQ handler\n");
420 return r;
421 }
422
423 return ndlc_probe(phy, &i2c_phy_ops, &client->dev,
424 ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
425 &phy->ndlc);
426}
427
428static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
429{
430 struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
431
432 dev_dbg(&client->dev, "%s\n", __func__);
433
434 ndlc_remove(phy->ndlc);
435
436 if (phy->powered)
437 st21nfcb_nci_i2c_disable(phy);
438
439 return 0;
440}
441
442static const struct of_device_id of_st21nfcb_i2c_match[] = {
443 { .compatible = "st,st21nfcb_i2c", },
444 {}
445};
446
447static struct i2c_driver st21nfcb_nci_i2c_driver = {
448 .driver = {
449 .owner = THIS_MODULE,
450 .name = ST21NFCB_NCI_I2C_DRIVER_NAME,
451 .owner = THIS_MODULE,
452 .of_match_table = of_match_ptr(of_st21nfcb_i2c_match),
453 },
454 .probe = st21nfcb_nci_i2c_probe,
455 .id_table = st21nfcb_nci_i2c_id_table,
456 .remove = st21nfcb_nci_i2c_remove,
457};
458
459module_i2c_driver(st21nfcb_nci_i2c_driver);
460
461MODULE_LICENSE("GPL");
462MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c
new file mode 100644
index 000000000000..83c97c36112b
--- /dev/null
+++ b/drivers/nfc/st21nfcb/ndlc.c
@@ -0,0 +1,298 @@
1/*
2 * Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip
3 *
4 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/sched.h>
20#include <net/nfc/nci_core.h>
21
22#include "ndlc.h"
23#include "st21nfcb.h"
24
25#define NDLC_TIMER_T1 100
26#define NDLC_TIMER_T1_WAIT 400
27#define NDLC_TIMER_T2 1200
28
29#define PCB_TYPE_DATAFRAME 0x80
30#define PCB_TYPE_SUPERVISOR 0xc0
31#define PCB_TYPE_MASK PCB_TYPE_SUPERVISOR
32
33#define PCB_SYNC_ACK 0x20
34#define PCB_SYNC_NACK 0x10
35#define PCB_SYNC_WAIT 0x30
36#define PCB_SYNC_NOINFO 0x00
37#define PCB_SYNC_MASK PCB_SYNC_WAIT
38
39#define PCB_DATAFRAME_RETRANSMIT_YES 0x00
40#define PCB_DATAFRAME_RETRANSMIT_NO 0x04
41#define PCB_DATAFRAME_RETRANSMIT_MASK PCB_DATAFRAME_RETRANSMIT_NO
42
43#define PCB_SUPERVISOR_RETRANSMIT_YES 0x00
44#define PCB_SUPERVISOR_RETRANSMIT_NO 0x02
45#define PCB_SUPERVISOR_RETRANSMIT_MASK PCB_SUPERVISOR_RETRANSMIT_NO
46
47#define PCB_FRAME_CRC_INFO_PRESENT 0x08
48#define PCB_FRAME_CRC_INFO_NOTPRESENT 0x00
49#define PCB_FRAME_CRC_INFO_MASK PCB_FRAME_CRC_INFO_PRESENT
50
51#define NDLC_DUMP_SKB(info, skb) \
52do { \
53 pr_debug("%s:\n", info); \
54 print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \
55 16, 1, skb->data, skb->len, 0); \
56} while (0)
57
58int ndlc_open(struct llt_ndlc *ndlc)
59{
60 /* toggle reset pin */
61 ndlc->ops->enable(ndlc->phy_id);
62 return 0;
63}
64EXPORT_SYMBOL(ndlc_open);
65
66void ndlc_close(struct llt_ndlc *ndlc)
67{
68 /* toggle reset pin */
69 ndlc->ops->disable(ndlc->phy_id);
70}
71EXPORT_SYMBOL(ndlc_close);
72
73int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb)
74{
75 /* add ndlc header */
76 u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO |
77 PCB_FRAME_CRC_INFO_NOTPRESENT;
78
79 *skb_push(skb, 1) = pcb;
80 skb_queue_tail(&ndlc->send_q, skb);
81
82 schedule_work(&ndlc->sm_work);
83
84 return 0;
85}
86EXPORT_SYMBOL(ndlc_send);
87
88static void llt_ndlc_send_queue(struct llt_ndlc *ndlc)
89{
90 struct sk_buff *skb;
91 int r;
92 unsigned long time_sent;
93
94 if (ndlc->send_q.qlen)
95 pr_debug("sendQlen=%d unackQlen=%d\n",
96 ndlc->send_q.qlen, ndlc->ack_pending_q.qlen);
97
98 while (ndlc->send_q.qlen) {
99 skb = skb_dequeue(&ndlc->send_q);
100 NDLC_DUMP_SKB("ndlc frame written", skb);
101 r = ndlc->ops->write(ndlc->phy_id, skb);
102 if (r < 0) {
103 ndlc->hard_fault = r;
104 break;
105 }
106 time_sent = jiffies;
107 *(unsigned long *)skb->cb = time_sent;
108
109 skb_queue_tail(&ndlc->ack_pending_q, skb);
110
111 /* start timer t1 for ndlc aknowledge */
112 ndlc->t1_active = true;
113 mod_timer(&ndlc->t1_timer, time_sent +
114 msecs_to_jiffies(NDLC_TIMER_T1));
115 }
116}
117
118static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
119{
120 struct sk_buff *skb;
121 u8 pcb;
122
123 while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) {
124 pcb = skb->data[0];
125 switch (pcb & PCB_TYPE_MASK) {
126 case PCB_TYPE_SUPERVISOR:
127 skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) |
128 PCB_SUPERVISOR_RETRANSMIT_YES;
129 break;
130 case PCB_TYPE_DATAFRAME:
131 skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) |
132 PCB_DATAFRAME_RETRANSMIT_YES;
133 break;
134 default:
135 pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
136 kfree_skb(skb);
137 break;
138 }
139 skb_queue_head(&ndlc->send_q, skb);
140 }
141}
142
143static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc)
144{
145 struct sk_buff *skb;
146 u8 pcb;
147 unsigned long time_sent;
148
149 if (ndlc->rcv_q.qlen)
150 pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen);
151
152 while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) {
153 pcb = skb->data[0];
154 skb_pull(skb, 1);
155 if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) {
156 switch (pcb & PCB_SYNC_MASK) {
157 case PCB_SYNC_ACK:
158 del_timer_sync(&ndlc->t1_timer);
159 del_timer_sync(&ndlc->t2_timer);
160 ndlc->t2_active = false;
161 ndlc->t1_active = false;
162 break;
163 case PCB_SYNC_NACK:
164 llt_ndlc_requeue_data_pending(ndlc);
165 llt_ndlc_send_queue(ndlc);
166 /* start timer t1 for ndlc aknowledge */
167 time_sent = jiffies;
168 ndlc->t1_active = true;
169 mod_timer(&ndlc->t1_timer, time_sent +
170 msecs_to_jiffies(NDLC_TIMER_T1));
171 break;
172 case PCB_SYNC_WAIT:
173 time_sent = jiffies;
174 ndlc->t1_active = true;
175 mod_timer(&ndlc->t1_timer, time_sent +
176 msecs_to_jiffies(NDLC_TIMER_T1_WAIT));
177 break;
178 default:
179 pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
180 kfree_skb(skb);
181 break;
182 }
183 } else {
184 nci_recv_frame(ndlc->ndev, skb);
185 }
186 }
187}
188
189static void llt_ndlc_sm_work(struct work_struct *work)
190{
191 struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work);
192
193 llt_ndlc_send_queue(ndlc);
194 llt_ndlc_rcv_queue(ndlc);
195
196 if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) {
197 pr_debug
198 ("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n");
199 ndlc->t1_active = false;
200
201 llt_ndlc_requeue_data_pending(ndlc);
202 llt_ndlc_send_queue(ndlc);
203 }
204
205 if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) {
206 pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n");
207 ndlc->t2_active = false;
208 ndlc->t1_active = false;
209 del_timer_sync(&ndlc->t1_timer);
210
211 ndlc_close(ndlc);
212 ndlc->hard_fault = -EREMOTEIO;
213 }
214}
215
216void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb)
217{
218 if (skb == NULL) {
219 pr_err("NULL Frame -> link is dead\n");
220 ndlc->hard_fault = -EREMOTEIO;
221 ndlc_close(ndlc);
222 } else {
223 NDLC_DUMP_SKB("incoming frame", skb);
224 skb_queue_tail(&ndlc->rcv_q, skb);
225 }
226
227 schedule_work(&ndlc->sm_work);
228}
229EXPORT_SYMBOL(ndlc_recv);
230
231static void ndlc_t1_timeout(unsigned long data)
232{
233 struct llt_ndlc *ndlc = (struct llt_ndlc *)data;
234
235 pr_debug("\n");
236
237 schedule_work(&ndlc->sm_work);
238}
239
240static void ndlc_t2_timeout(unsigned long data)
241{
242 struct llt_ndlc *ndlc = (struct llt_ndlc *)data;
243
244 pr_debug("\n");
245
246 schedule_work(&ndlc->sm_work);
247}
248
249int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
250 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id)
251{
252 struct llt_ndlc *ndlc;
253
254 ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL);
255 if (!ndlc) {
256 nfc_err(dev, "Cannot allocate memory for ndlc.\n");
257 return -ENOMEM;
258 }
259 ndlc->ops = phy_ops;
260 ndlc->phy_id = phy_id;
261 ndlc->dev = dev;
262
263 *ndlc_id = ndlc;
264
265 /* start timers */
266 init_timer(&ndlc->t1_timer);
267 ndlc->t1_timer.data = (unsigned long)ndlc;
268 ndlc->t1_timer.function = ndlc_t1_timeout;
269
270 init_timer(&ndlc->t2_timer);
271 ndlc->t2_timer.data = (unsigned long)ndlc;
272 ndlc->t2_timer.function = ndlc_t2_timeout;
273
274 skb_queue_head_init(&ndlc->rcv_q);
275 skb_queue_head_init(&ndlc->send_q);
276 skb_queue_head_init(&ndlc->ack_pending_q);
277
278 INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
279
280 return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom);
281}
282EXPORT_SYMBOL(ndlc_probe);
283
284void ndlc_remove(struct llt_ndlc *ndlc)
285{
286 /* cancel timers */
287 del_timer_sync(&ndlc->t1_timer);
288 del_timer_sync(&ndlc->t2_timer);
289 ndlc->t2_active = false;
290 ndlc->t1_active = false;
291
292 skb_queue_purge(&ndlc->rcv_q);
293 skb_queue_purge(&ndlc->send_q);
294
295 st21nfcb_nci_remove(ndlc->ndev);
296 kfree(ndlc);
297}
298EXPORT_SYMBOL(ndlc_remove);
diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st21nfcb/ndlc.h
new file mode 100644
index 000000000000..c30a2f0faa5f
--- /dev/null
+++ b/drivers/nfc/st21nfcb/ndlc.h
@@ -0,0 +1,55 @@
1/*
2 * NCI based Driver for STMicroelectronics NFC Chip
3 *
4 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __LOCAL_NDLC_H_
20#define __LOCAL_NDLC_H_
21
22#include <linux/skbuff.h>
23#include <net/nfc/nfc.h>
24
25/* Low Level Transport description */
26struct llt_ndlc {
27 struct nci_dev *ndev;
28 struct nfc_phy_ops *ops;
29 void *phy_id;
30
31 struct timer_list t1_timer;
32 bool t1_active;
33
34 struct timer_list t2_timer;
35 bool t2_active;
36
37 struct sk_buff_head rcv_q;
38 struct sk_buff_head send_q;
39 struct sk_buff_head ack_pending_q;
40
41 struct work_struct sm_work;
42
43 struct device *dev;
44
45 int hard_fault;
46};
47
48int ndlc_open(struct llt_ndlc *ndlc);
49void ndlc_close(struct llt_ndlc *ndlc);
50int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
51void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
52int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
53 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id);
54void ndlc_remove(struct llt_ndlc *ndlc);
55#endif /* __LOCAL_NDLC_H__ */
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
new file mode 100644
index 000000000000..4d95863e3063
--- /dev/null
+++ b/drivers/nfc/st21nfcb/st21nfcb.c
@@ -0,0 +1,129 @@
1/*
2 * NCI based Driver for STMicroelectronics NFC Chip
3 *
4 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/nfc.h>
21#include <net/nfc/nci.h>
22#include <net/nfc/nci_core.h>
23
24#include "st21nfcb.h"
25#include "ndlc.h"
26
27#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
28
29static int st21nfcb_nci_open(struct nci_dev *ndev)
30{
31 struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
32 int r;
33
34 if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags))
35 return 0;
36
37 r = ndlc_open(info->ndlc);
38 if (r)
39 clear_bit(ST21NFCB_NCI_RUNNING, &info->flags);
40
41 return r;
42}
43
44static int st21nfcb_nci_close(struct nci_dev *ndev)
45{
46 struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
47
48 if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags))
49 return 0;
50
51 ndlc_close(info->ndlc);
52
53 return 0;
54}
55
56static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
57{
58 struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
59
60 skb->dev = (void *)ndev;
61
62 if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags))
63 return -EBUSY;
64
65 return ndlc_send(info->ndlc, skb);
66}
67
68static struct nci_ops st21nfcb_nci_ops = {
69 .open = st21nfcb_nci_open,
70 .close = st21nfcb_nci_close,
71 .send = st21nfcb_nci_send,
72};
73
74int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
75 int phy_tailroom)
76{
77 struct st21nfcb_nci_info *info;
78 int r;
79 u32 protocols;
80
81 info = devm_kzalloc(ndlc->dev,
82 sizeof(struct st21nfcb_nci_info), GFP_KERNEL);
83 if (!info)
84 return -ENOMEM;
85
86 protocols = NFC_PROTO_JEWEL_MASK
87 | NFC_PROTO_MIFARE_MASK
88 | NFC_PROTO_FELICA_MASK
89 | NFC_PROTO_ISO14443_MASK
90 | NFC_PROTO_ISO14443_B_MASK
91 | NFC_PROTO_NFC_DEP_MASK;
92
93 ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
94 phy_headroom, phy_tailroom);
95 if (!ndlc->ndev) {
96 pr_err("Cannot allocate nfc ndev\n");
97 r = -ENOMEM;
98 goto err_alloc_ndev;
99 }
100 info->ndlc = ndlc;
101
102 nci_set_drvdata(ndlc->ndev, info);
103
104 r = nci_register_device(ndlc->ndev);
105 if (r)
106 goto err_regdev;
107
108 return r;
109err_regdev:
110 nci_free_device(ndlc->ndev);
111
112err_alloc_ndev:
113 kfree(info);
114 return r;
115}
116EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
117
118void st21nfcb_nci_remove(struct nci_dev *ndev)
119{
120 struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
121
122 nci_unregister_device(ndev);
123 nci_free_device(ndev);
124 kfree(info);
125}
126EXPORT_SYMBOL_GPL(st21nfcb_nci_remove);
127
128MODULE_LICENSE("GPL");
129MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h
new file mode 100644
index 000000000000..4bbbebb9f34d
--- /dev/null
+++ b/drivers/nfc/st21nfcb/st21nfcb.h
@@ -0,0 +1,38 @@
1/*
2 * NCI based Driver for STMicroelectronics NFC Chip
3 *
4 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __LOCAL_ST21NFCB_H_
20#define __LOCAL_ST21NFCB_H_
21
22#include <net/nfc/nci_core.h>
23
24#include "ndlc.h"
25
26/* Define private flags: */
27#define ST21NFCB_NCI_RUNNING 1
28
29struct st21nfcb_nci_info {
30 struct llt_ndlc *ndlc;
31 unsigned long flags;
32};
33
34void st21nfcb_nci_remove(struct nci_dev *ndev);
35int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
36 int phy_tailroom);
37
38#endif /* __LOCAL_ST21NFCB_H_ */
diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h
new file mode 100644
index 000000000000..2a7b769c714d
--- /dev/null
+++ b/include/linux/platform_data/st21nfcb.h
@@ -0,0 +1,32 @@
1/*
2 * Driver include for the ST21NFCB NFC chip.
3 *
4 * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _ST21NFCA_HCI_H_
20#define _ST21NFCA_HCI_H_
21
22#include <linux/i2c.h>
23
24#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci"
25
26struct st21nfcb_nfc_platform_data {
27 unsigned int gpio_irq;
28 unsigned int gpio_reset;
29 unsigned int irq_polarity;
30};
31
32#endif /* _ST21NFCA_HCI_H_ */