aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2015-08-14 16:33:37 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2015-08-16 18:35:08 -0400
commit2bc4d4f8c8f3ce863e3644736d1790b0684c7eb0 (patch)
tree53df6a874777e9415810b20631f715e10a015d89
parent8b706884eac958ec16518315053f77e052627084 (diff)
nfc: st-nci: Add spi phy support for st21nfcb
st21nfcb does support another phy than i2c: spi. st21nfcc does not support spi as the spi ios are used by the AMS RF booster. st21nfcb is not following NCI NFC Forum recommendations for spi but rely on ST prioritary protocol ndlc as for i2c. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/nfc/st-nci/Kconfig11
-rw-r--r--drivers/nfc/st-nci/Makefile3
-rw-r--r--drivers/nfc/st-nci/spi.c392
3 files changed, 406 insertions, 0 deletions
diff --git a/drivers/nfc/st-nci/Kconfig b/drivers/nfc/st-nci/Kconfig
index fc3904c946ee..e7c6db9c5860 100644
--- a/drivers/nfc/st-nci/Kconfig
+++ b/drivers/nfc/st-nci/Kconfig
@@ -21,3 +21,14 @@ config NFC_ST_NCI_I2C
21 21
22 If you choose to build a module, it'll be called st-nci_i2c. 22 If you choose to build a module, it'll be called st-nci_i2c.
23 Say N if unsure. 23 Say N if unsure.
24
25config NFC_ST_NCI_SPI
26 tristate "NFC ST NCI spi support"
27 depends on NFC_ST_NCI && SPI
28 ---help---
29 This module adds support for an SPI interface to the
30 STMicroelectronics NFC NCI chips familly.
31 Select this if your platform is using the spi bus.
32
33 If you choose to build a module, it'll be called st-nci_spi.
34 Say N if unsure.
diff --git a/drivers/nfc/st-nci/Makefile b/drivers/nfc/st-nci/Makefile
index 0df157df3a94..348ce76f2177 100644
--- a/drivers/nfc/st-nci/Makefile
+++ b/drivers/nfc/st-nci/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_NFC_ST_NCI) += st-nci.o
7 7
8st-nci_i2c-objs = i2c.o 8st-nci_i2c-objs = i2c.o
9obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o 9obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o
10
11st-nci_spi-objs = spi.o
12obj-$(CONFIG_NFC_ST_NCI_SPI) += st-nci_spi.o
diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
new file mode 100644
index 000000000000..598a58c4d6d1
--- /dev/null
+++ b/drivers/nfc/st-nci/spi.c
@@ -0,0 +1,392 @@
1/*
2 * SPI Link Layer for ST NCI based Driver
3 * Copyright (C) 2014-2015 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/module.h>
21#include <linux/spi/spi.h>
22#include <linux/gpio.h>
23#include <linux/of_irq.h>
24#include <linux/of_gpio.h>
25#include <linux/interrupt.h>
26#include <linux/delay.h>
27#include <linux/nfc.h>
28#include <linux/platform_data/st-nci.h>
29
30#include "ndlc.h"
31
32#define DRIVER_DESC "NCI NFC driver for ST_NCI"
33
34/* ndlc header */
35#define ST_NCI_FRAME_HEADROOM 1
36#define ST_NCI_FRAME_TAILROOM 0
37
38#define ST_NCI_SPI_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
39#define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */
40
41#define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
42
43static struct spi_device_id st_nci_spi_id_table[] = {
44 {ST_NCI_SPI_DRIVER_NAME, 0},
45 {}
46};
47MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
48
49struct st_nci_spi_phy {
50 struct spi_device *spi_dev;
51 struct llt_ndlc *ndlc;
52
53 unsigned int gpio_reset;
54 unsigned int irq_polarity;
55};
56
57#define SPI_DUMP_SKB(info, skb) \
58do { \
59 pr_debug("%s:\n", info); \
60 print_hex_dump(KERN_DEBUG, "spi: ", DUMP_PREFIX_OFFSET, \
61 16, 1, (skb)->data, (skb)->len, 0); \
62} while (0)
63
64static int st_nci_spi_enable(void *phy_id)
65{
66 struct st_nci_spi_phy *phy = phy_id;
67
68 gpio_set_value(phy->gpio_reset, 0);
69 usleep_range(10000, 15000);
70 gpio_set_value(phy->gpio_reset, 1);
71 usleep_range(80000, 85000);
72
73 if (phy->ndlc->powered == 0)
74 enable_irq(phy->spi_dev->irq);
75
76 return 0;
77}
78
79static void st_nci_spi_disable(void *phy_id)
80{
81 struct st_nci_spi_phy *phy = phy_id;
82
83 disable_irq_nosync(phy->spi_dev->irq);
84}
85
86/*
87 * Writing a frame must not return the number of written bytes.
88 * It must return either zero for success, or <0 for error.
89 * In addition, it must not alter the skb
90 */
91static int st_nci_spi_write(void *phy_id, struct sk_buff *skb)
92{
93 int r;
94 struct st_nci_spi_phy *phy = phy_id;
95 struct spi_device *dev = phy->spi_dev;
96 struct sk_buff *skb_rx;
97 u8 buf[ST_NCI_SPI_MAX_SIZE];
98 struct spi_transfer spi_xfer = {
99 .tx_buf = skb->data,
100 .rx_buf = buf,
101 .len = skb->len,
102 };
103
104 SPI_DUMP_SKB("st_nci_spi_write", skb);
105
106 if (phy->ndlc->hard_fault != 0)
107 return phy->ndlc->hard_fault;
108
109 r = spi_sync_transfer(dev, &spi_xfer, 1);
110 /*
111 * We may have received some valuable data on miso line.
112 * Send them back in the ndlc state machine.
113 */
114 if (!r) {
115 skb_rx = alloc_skb(skb->len, GFP_KERNEL);
116 if (!skb_rx) {
117 r = -ENOMEM;
118 goto exit;
119 }
120
121 skb_put(skb_rx, skb->len);
122 memcpy(skb_rx->data, buf, skb->len);
123 ndlc_recv(phy->ndlc, skb_rx);
124 }
125
126exit:
127 return r;
128}
129
130/*
131 * Reads an ndlc frame and returns it in a newly allocated sk_buff.
132 * returns:
133 * 0 : if received frame is complete
134 * -EREMOTEIO : i2c read error (fatal)
135 * -EBADMSG : frame was incorrect and discarded
136 * -ENOMEM : cannot allocate skb, frame dropped
137 */
138static int st_nci_spi_read(struct st_nci_spi_phy *phy,
139 struct sk_buff **skb)
140{
141 int r;
142 u8 len;
143 u8 buf[ST_NCI_SPI_MAX_SIZE];
144 struct spi_device *dev = phy->spi_dev;
145 struct spi_transfer spi_xfer = {
146 .rx_buf = buf,
147 .len = ST_NCI_SPI_MIN_SIZE,
148 };
149
150 r = spi_sync_transfer(dev, &spi_xfer, 1);
151 if (r < 0)
152 return -EREMOTEIO;
153
154 len = be16_to_cpu(*(__be16 *) (buf + 2));
155 if (len > ST_NCI_SPI_MAX_SIZE) {
156 nfc_err(&dev->dev, "invalid frame len\n");
157 phy->ndlc->hard_fault = 1;
158 return -EBADMSG;
159 }
160
161 *skb = alloc_skb(ST_NCI_SPI_MIN_SIZE + len, GFP_KERNEL);
162 if (*skb == NULL)
163 return -ENOMEM;
164
165 skb_reserve(*skb, ST_NCI_SPI_MIN_SIZE);
166 skb_put(*skb, ST_NCI_SPI_MIN_SIZE);
167 memcpy((*skb)->data, buf, ST_NCI_SPI_MIN_SIZE);
168
169 if (!len)
170 return 0;
171
172 spi_xfer.len = len;
173 r = spi_sync_transfer(dev, &spi_xfer, 1);
174 if (r < 0) {
175 kfree_skb(*skb);
176 return -EREMOTEIO;
177 }
178
179 skb_put(*skb, len);
180 memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len);
181
182 SPI_DUMP_SKB("spi frame read", *skb);
183
184 return 0;
185}
186
187/*
188 * Reads an ndlc frame from the chip.
189 *
190 * On ST21NFCB, IRQ goes in idle state when read starts.
191 */
192static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
193{
194 struct st_nci_spi_phy *phy = phy_id;
195 struct spi_device *dev;
196 struct sk_buff *skb = NULL;
197 int r;
198
199 if (!phy || !phy->ndlc || irq != phy->spi_dev->irq) {
200 WARN_ON_ONCE(1);
201 return IRQ_NONE;
202 }
203
204 dev = phy->spi_dev;
205 dev_dbg(&dev->dev, "IRQ\n");
206
207 if (phy->ndlc->hard_fault)
208 return IRQ_HANDLED;
209
210 if (!phy->ndlc->powered) {
211 st_nci_spi_disable(phy);
212 return IRQ_HANDLED;
213 }
214
215 r = st_nci_spi_read(phy, &skb);
216 if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
217 return IRQ_HANDLED;
218
219 ndlc_recv(phy->ndlc, skb);
220
221 return IRQ_HANDLED;
222}
223
224static struct nfc_phy_ops spi_phy_ops = {
225 .write = st_nci_spi_write,
226 .enable = st_nci_spi_enable,
227 .disable = st_nci_spi_disable,
228};
229
230#ifdef CONFIG_OF
231static int st_nci_spi_of_request_resources(struct spi_device *dev)
232{
233 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
234 struct device_node *pp;
235 int gpio;
236 int r;
237
238 pp = dev->dev.of_node;
239 if (!pp)
240 return -ENODEV;
241
242 /* Get GPIO from device tree */
243 gpio = of_get_named_gpio(pp, "reset-gpios", 0);
244 if (gpio < 0) {
245 nfc_err(&dev->dev,
246 "Failed to retrieve reset-gpios from device tree\n");
247 return gpio;
248 }
249
250 /* GPIO request and configuration */
251 r = devm_gpio_request_one(&dev->dev, gpio,
252 GPIOF_OUT_INIT_HIGH, "clf_reset");
253 if (r) {
254 nfc_err(&dev->dev, "Failed to request reset pin\n");
255 return r;
256 }
257 phy->gpio_reset = gpio;
258
259 phy->irq_polarity = irq_get_trigger_type(dev->irq);
260
261 return 0;
262}
263#else
264static int st_nci_spi_of_request_resources(struct spi_device *dev)
265{
266 return -ENODEV;
267}
268#endif
269
270static int st_nci_spi_request_resources(struct spi_device *dev)
271{
272 struct st_nci_nfc_platform_data *pdata;
273 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
274 int r;
275
276 pdata = dev->dev.platform_data;
277 if (pdata == NULL) {
278 nfc_err(&dev->dev, "No platform data\n");
279 return -EINVAL;
280 }
281
282 /* store for later use */
283 phy->gpio_reset = pdata->gpio_reset;
284 phy->irq_polarity = pdata->irq_polarity;
285
286 r = devm_gpio_request_one(&dev->dev,
287 phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
288 if (r) {
289 pr_err("%s : reset gpio_request failed\n", __FILE__);
290 return r;
291 }
292
293 return 0;
294}
295
296static int st_nci_spi_probe(struct spi_device *dev)
297{
298 struct st_nci_spi_phy *phy;
299 struct st_nci_nfc_platform_data *pdata;
300 int r;
301
302 dev_dbg(&dev->dev, "%s\n", __func__);
303 dev_dbg(&dev->dev, "IRQ: %d\n", dev->irq);
304
305 /* Check SPI platform functionnalities */
306 if (!dev) {
307 pr_debug("%s: dev is NULL. Device is not accessible.\n",
308 __func__);
309 return -ENODEV;
310 }
311
312 phy = devm_kzalloc(&dev->dev, sizeof(struct st_nci_spi_phy),
313 GFP_KERNEL);
314 if (!phy)
315 return -ENOMEM;
316
317 phy->spi_dev = dev;
318
319 spi_set_drvdata(dev, phy);
320
321 pdata = dev->dev.platform_data;
322 if (!pdata && dev->dev.of_node) {
323 r = st_nci_spi_of_request_resources(dev);
324 if (r) {
325 nfc_err(&dev->dev, "No platform data\n");
326 return r;
327 }
328 } else if (pdata) {
329 r = st_nci_spi_request_resources(dev);
330 if (r) {
331 nfc_err(&dev->dev,
332 "Cannot get platform resources\n");
333 return r;
334 }
335 } else {
336 nfc_err(&dev->dev,
337 "st_nci platform resources not available\n");
338 return -ENODEV;
339 }
340
341 r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
342 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
343 &phy->ndlc);
344 if (r < 0) {
345 nfc_err(&dev->dev, "Unable to register ndlc layer\n");
346 return r;
347 }
348
349 r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL,
350 st_nci_irq_thread_fn,
351 phy->irq_polarity | IRQF_ONESHOT,
352 ST_NCI_SPI_DRIVER_NAME, phy);
353 if (r < 0)
354 nfc_err(&dev->dev, "Unable to register IRQ handler\n");
355
356 return r;
357}
358
359static int st_nci_spi_remove(struct spi_device *dev)
360{
361 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
362
363 dev_dbg(&dev->dev, "%s\n", __func__);
364
365 ndlc_remove(phy->ndlc);
366
367 return 0;
368}
369
370#ifdef CONFIG_OF
371static const struct of_device_id of_st_nci_spi_match[] = {
372 { .compatible = "st,st21nfcb-spi", },
373 {}
374};
375MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
376#endif
377
378static struct spi_driver st_nci_spi_driver = {
379 .driver = {
380 .owner = THIS_MODULE,
381 .name = ST_NCI_SPI_DRIVER_NAME,
382 .of_match_table = of_match_ptr(of_st_nci_spi_match),
383 },
384 .probe = st_nci_spi_probe,
385 .id_table = st_nci_spi_id_table,
386 .remove = st_nci_spi_remove,
387};
388
389module_spi_driver(st_nci_spi_driver);
390
391MODULE_LICENSE("GPL");
392MODULE_DESCRIPTION(DRIVER_DESC);