NFC: NCI: move generic spi driver to a module
[deliverable/linux.git] / net / nfc / nci / spi.c
CommitLineData
8a00a61b
FD
1/*
2 * Copyright (C) 2013 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 */
18
19#define pr_fmt(fmt) "nci_spi: %s: " fmt, __func__
20
fcd9d046
VC
21#include <linux/module.h>
22
8a00a61b
FD
23#include <linux/export.h>
24#include <linux/spi/spi.h>
ee9596d4 25#include <linux/crc-ccitt.h>
8a00a61b
FD
26#include <net/nfc/nci_core.h>
27
391d8a2d
FD
28#define NCI_SPI_ACK_SHIFT 6
29#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
8a00a61b 30
ee9596d4
FD
31#define NCI_SPI_SEND_TIMEOUT (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
32 NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
33
34#define NCI_SPI_DIRECT_WRITE 0x01
35#define NCI_SPI_DIRECT_READ 0x02
36
37#define ACKNOWLEDGE_NONE 0
38#define ACKNOWLEDGE_ACK 1
39#define ACKNOWLEDGE_NACK 2
40
41#define CRC_INIT 0xFFFF
42
2bed2785
EL
43static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb,
44 int cs_change)
ee9596d4
FD
45{
46 struct spi_message m;
47 struct spi_transfer t;
48
a4ada6ca 49 memset(&t, 0, sizeof(struct spi_transfer));
2bed2785
EL
50 /* a NULL skb means we just want the SPI chip select line to raise */
51 if (skb) {
52 t.tx_buf = skb->data;
53 t.len = skb->len;
54 } else {
55 /* still set tx_buf non NULL to make the driver happy */
56 t.tx_buf = &t;
57 t.len = 0;
58 }
59 t.cs_change = cs_change;
fa544fff 60 t.delay_usecs = nspi->xfer_udelay;
ee9596d4
FD
61
62 spi_message_init(&m);
63 spi_message_add_tail(&t, &m);
64
fa544fff 65 return spi_sync(nspi->spi, &m);
ee9596d4
FD
66}
67
2bed2785
EL
68int nci_spi_send(struct nci_spi *nspi,
69 struct completion *write_handshake_completion,
70 struct sk_buff *skb)
8a00a61b 71{
ee9596d4
FD
72 unsigned int payload_len = skb->len;
73 unsigned char *hdr;
74 int ret;
75 long completion_rc;
76
ee9596d4
FD
77 /* add the NCI SPI header to the start of the buffer */
78 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
79 hdr[0] = NCI_SPI_DIRECT_WRITE;
fa544fff 80 hdr[1] = nspi->acknowledge_mode;
ee9596d4
FD
81 hdr[2] = payload_len >> 8;
82 hdr[3] = payload_len & 0xFF;
83
fa544fff 84 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
ee9596d4
FD
85 u16 crc;
86
87 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
88 *skb_put(skb, 1) = crc >> 8;
89 *skb_put(skb, 1) = crc & 0xFF;
90 }
91
2bed2785
EL
92 if (write_handshake_completion) {
93 /* Trick SPI driver to raise chip select */
94 ret = __nci_spi_send(nspi, NULL, 1);
95 if (ret)
96 goto done;
ee9596d4 97
2bed2785
EL
98 /* wait for NFC chip hardware handshake to complete */
99 if (wait_for_completion_timeout(write_handshake_completion,
100 msecs_to_jiffies(1000)) == 0) {
101 ret = -ETIME;
102 goto done;
103 }
104 }
ee9596d4 105
2bed2785 106 ret = __nci_spi_send(nspi, skb, 0);
fa544fff 107 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
ee9596d4
FD
108 goto done;
109
9bec44bf 110 reinit_completion(&nspi->req_completion);
d5937511 111 completion_rc = wait_for_completion_interruptible_timeout(
fa544fff 112 &nspi->req_completion,
d5937511 113 NCI_SPI_SEND_TIMEOUT);
ee9596d4 114
fa544fff 115 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
ee9596d4
FD
116 ret = -EIO;
117
118done:
2bed2785
EL
119 kfree_skb(skb);
120
ee9596d4 121 return ret;
8a00a61b 122}
fa544fff 123EXPORT_SYMBOL_GPL(nci_spi_send);
8a00a61b
FD
124
125/* ---- Interface to NCI SPI drivers ---- */
126
127/**
fa544fff 128 * nci_spi_allocate_spi - allocate a new nci spi
8a00a61b
FD
129 *
130 * @spi: SPI device
fa544fff 131 * @acknowledge_mode: Acknowledge mode used by the NFC device
8a00a61b 132 * @delay: delay between transactions in us
fa544fff 133 * @ndev: nci dev to send incoming nci frames to
8a00a61b 134 */
fa544fff 135struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
fa544fff
EL
136 u8 acknowledge_mode, unsigned int delay,
137 struct nci_dev *ndev)
8a00a61b 138{
fa544fff 139 struct nci_spi *nspi;
8a00a61b 140
fa544fff
EL
141 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
142 if (!nspi)
8a00a61b
FD
143 return NULL;
144
fa544fff
EL
145 nspi->acknowledge_mode = acknowledge_mode;
146 nspi->xfer_udelay = delay;
8a00a61b 147
645d5087 148 nspi->spi = spi;
fa544fff 149 nspi->ndev = ndev;
9bec44bf 150 init_completion(&nspi->req_completion);
8a00a61b 151
fa544fff 152 return nspi;
8a00a61b 153}
fa544fff 154EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
391d8a2d 155
fa544fff 156static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
391d8a2d
FD
157{
158 struct sk_buff *skb;
159 unsigned char *hdr;
160 u16 crc;
161 int ret;
162
fa544fff 163 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
391d8a2d
FD
164
165 /* add the NCI SPI header to the start of the buffer */
166 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
167 hdr[0] = NCI_SPI_DIRECT_WRITE;
168 hdr[1] = NCI_SPI_CRC_ENABLED;
169 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
170 hdr[3] = 0;
171
172 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
173 *skb_put(skb, 1) = crc >> 8;
174 *skb_put(skb, 1) = crc & 0xFF;
175
2bed2785 176 ret = __nci_spi_send(nspi, skb, 0);
391d8a2d
FD
177
178 kfree_skb(skb);
179
180 return ret;
181}
182
22d4aae5 183static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
391d8a2d
FD
184{
185 struct sk_buff *skb;
186 struct spi_message m;
187 unsigned char req[2], resp_hdr[2];
188 struct spi_transfer tx, rx;
189 unsigned short rx_len = 0;
190 int ret;
191
192 spi_message_init(&m);
a4ada6ca
EL
193
194 memset(&tx, 0, sizeof(struct spi_transfer));
391d8a2d 195 req[0] = NCI_SPI_DIRECT_READ;
fa544fff 196 req[1] = nspi->acknowledge_mode;
391d8a2d
FD
197 tx.tx_buf = req;
198 tx.len = 2;
199 tx.cs_change = 0;
200 spi_message_add_tail(&tx, &m);
a4ada6ca
EL
201
202 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
203 rx.rx_buf = resp_hdr;
204 rx.len = 2;
205 rx.cs_change = 1;
206 spi_message_add_tail(&rx, &m);
a4ada6ca 207
fa544fff 208 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
209 if (ret)
210 return NULL;
211
fa544fff 212 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
391d8a2d
FD
213 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
214 resp_hdr[1] + NCI_SPI_CRC_LEN;
215 else
216 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
217
fa544fff 218 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
391d8a2d
FD
219 if (!skb)
220 return NULL;
221
222 spi_message_init(&m);
a4ada6ca
EL
223
224 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
225 rx.rx_buf = skb_put(skb, rx_len);
226 rx.len = rx_len;
227 rx.cs_change = 0;
fa544fff 228 rx.delay_usecs = nspi->xfer_udelay;
391d8a2d 229 spi_message_add_tail(&rx, &m);
a4ada6ca 230
fa544fff 231 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
232 if (ret)
233 goto receive_error;
234
fa544fff 235 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d
FD
236 *skb_push(skb, 1) = resp_hdr[1];
237 *skb_push(skb, 1) = resp_hdr[0];
238 }
239
240 return skb;
241
242receive_error:
243 kfree_skb(skb);
244
245 return NULL;
246}
247
248static int nci_spi_check_crc(struct sk_buff *skb)
249{
250 u16 crc_data = (skb->data[skb->len - 2] << 8) |
251 skb->data[skb->len - 1];
252 int ret;
253
254 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
255 == crc_data);
256
257 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
258
259 return ret;
260}
261
262static u8 nci_spi_get_ack(struct sk_buff *skb)
263{
264 u8 ret;
265
266 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
267
268 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
269 skb_pull(skb, 2);
270
271 return ret;
272}
273
274/**
22d4aae5 275 * nci_spi_read - read frame from NCI SPI drivers
391d8a2d 276 *
fa544fff 277 * @nspi: The nci spi
391d8a2d
FD
278 * Context: can sleep
279 *
280 * This call may only be used from a context that may sleep. The sleep
281 * is non-interruptible, and has no timeout.
282 *
22d4aae5 283 * It returns an allocated skb containing the frame on success, or NULL.
391d8a2d 284 */
22d4aae5 285struct sk_buff *nci_spi_read(struct nci_spi *nspi)
391d8a2d
FD
286{
287 struct sk_buff *skb;
391d8a2d 288
391d8a2d 289 /* Retrieve frame from SPI */
22d4aae5
EL
290 skb = __nci_spi_read(nspi);
291 if (!skb)
391d8a2d 292 goto done;
391d8a2d 293
fa544fff 294 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d 295 if (!nci_spi_check_crc(skb)) {
fa544fff 296 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
391d8a2d
FD
297 goto done;
298 }
299
300 /* In case of acknowledged mode: if ACK or NACK received,
301 * unblock completion of latest frame sent.
302 */
fa544fff
EL
303 nspi->req_result = nci_spi_get_ack(skb);
304 if (nspi->req_result)
305 complete(&nspi->req_completion);
391d8a2d
FD
306 }
307
308 /* If there is no payload (ACK/NACK only frame),
309 * free the socket buffer
310 */
22d4aae5 311 if (!skb->len) {
391d8a2d 312 kfree_skb(skb);
22d4aae5 313 skb = NULL;
391d8a2d
FD
314 goto done;
315 }
316
fa544fff
EL
317 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
318 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
391d8a2d 319
391d8a2d 320done:
391d8a2d 321
22d4aae5 322 return skb;
391d8a2d 323}
22d4aae5 324EXPORT_SYMBOL_GPL(nci_spi_read);
fcd9d046
VC
325
326MODULE_LICENSE("GPL");
This page took 0.186296 seconds and 5 git commands to generate.