aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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_ */