NFC: NCI: move generic spi driver to a module
[deliverable/linux.git] / net / nfc / nci / spi.c
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
21 #include <linux/module.h>
22
23 #include <linux/export.h>
24 #include <linux/spi/spi.h>
25 #include <linux/crc-ccitt.h>
26 #include <net/nfc/nci_core.h>
27
28 #define NCI_SPI_ACK_SHIFT 6
29 #define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
30
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
43 static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb,
44 int cs_change)
45 {
46 struct spi_message m;
47 struct spi_transfer t;
48
49 memset(&t, 0, sizeof(struct spi_transfer));
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;
60 t.delay_usecs = nspi->xfer_udelay;
61
62 spi_message_init(&m);
63 spi_message_add_tail(&t, &m);
64
65 return spi_sync(nspi->spi, &m);
66 }
67
68 int nci_spi_send(struct nci_spi *nspi,
69 struct completion *write_handshake_completion,
70 struct sk_buff *skb)
71 {
72 unsigned int payload_len = skb->len;
73 unsigned char *hdr;
74 int ret;
75 long completion_rc;
76
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;
80 hdr[1] = nspi->acknowledge_mode;
81 hdr[2] = payload_len >> 8;
82 hdr[3] = payload_len & 0xFF;
83
84 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
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
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;
97
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 }
105
106 ret = __nci_spi_send(nspi, skb, 0);
107 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
108 goto done;
109
110 reinit_completion(&nspi->req_completion);
111 completion_rc = wait_for_completion_interruptible_timeout(
112 &nspi->req_completion,
113 NCI_SPI_SEND_TIMEOUT);
114
115 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
116 ret = -EIO;
117
118 done:
119 kfree_skb(skb);
120
121 return ret;
122 }
123 EXPORT_SYMBOL_GPL(nci_spi_send);
124
125 /* ---- Interface to NCI SPI drivers ---- */
126
127 /**
128 * nci_spi_allocate_spi - allocate a new nci spi
129 *
130 * @spi: SPI device
131 * @acknowledge_mode: Acknowledge mode used by the NFC device
132 * @delay: delay between transactions in us
133 * @ndev: nci dev to send incoming nci frames to
134 */
135 struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
136 u8 acknowledge_mode, unsigned int delay,
137 struct nci_dev *ndev)
138 {
139 struct nci_spi *nspi;
140
141 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
142 if (!nspi)
143 return NULL;
144
145 nspi->acknowledge_mode = acknowledge_mode;
146 nspi->xfer_udelay = delay;
147
148 nspi->spi = spi;
149 nspi->ndev = ndev;
150 init_completion(&nspi->req_completion);
151
152 return nspi;
153 }
154 EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
155
156 static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
157 {
158 struct sk_buff *skb;
159 unsigned char *hdr;
160 u16 crc;
161 int ret;
162
163 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
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
176 ret = __nci_spi_send(nspi, skb, 0);
177
178 kfree_skb(skb);
179
180 return ret;
181 }
182
183 static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
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);
193
194 memset(&tx, 0, sizeof(struct spi_transfer));
195 req[0] = NCI_SPI_DIRECT_READ;
196 req[1] = nspi->acknowledge_mode;
197 tx.tx_buf = req;
198 tx.len = 2;
199 tx.cs_change = 0;
200 spi_message_add_tail(&tx, &m);
201
202 memset(&rx, 0, sizeof(struct spi_transfer));
203 rx.rx_buf = resp_hdr;
204 rx.len = 2;
205 rx.cs_change = 1;
206 spi_message_add_tail(&rx, &m);
207
208 ret = spi_sync(nspi->spi, &m);
209 if (ret)
210 return NULL;
211
212 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
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
218 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
219 if (!skb)
220 return NULL;
221
222 spi_message_init(&m);
223
224 memset(&rx, 0, sizeof(struct spi_transfer));
225 rx.rx_buf = skb_put(skb, rx_len);
226 rx.len = rx_len;
227 rx.cs_change = 0;
228 rx.delay_usecs = nspi->xfer_udelay;
229 spi_message_add_tail(&rx, &m);
230
231 ret = spi_sync(nspi->spi, &m);
232 if (ret)
233 goto receive_error;
234
235 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
236 *skb_push(skb, 1) = resp_hdr[1];
237 *skb_push(skb, 1) = resp_hdr[0];
238 }
239
240 return skb;
241
242 receive_error:
243 kfree_skb(skb);
244
245 return NULL;
246 }
247
248 static 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
262 static 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 /**
275 * nci_spi_read - read frame from NCI SPI drivers
276 *
277 * @nspi: The nci spi
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 *
283 * It returns an allocated skb containing the frame on success, or NULL.
284 */
285 struct sk_buff *nci_spi_read(struct nci_spi *nspi)
286 {
287 struct sk_buff *skb;
288
289 /* Retrieve frame from SPI */
290 skb = __nci_spi_read(nspi);
291 if (!skb)
292 goto done;
293
294 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
295 if (!nci_spi_check_crc(skb)) {
296 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
297 goto done;
298 }
299
300 /* In case of acknowledged mode: if ACK or NACK received,
301 * unblock completion of latest frame sent.
302 */
303 nspi->req_result = nci_spi_get_ack(skb);
304 if (nspi->req_result)
305 complete(&nspi->req_completion);
306 }
307
308 /* If there is no payload (ACK/NACK only frame),
309 * free the socket buffer
310 */
311 if (!skb->len) {
312 kfree_skb(skb);
313 skb = NULL;
314 goto done;
315 }
316
317 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
318 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
319
320 done:
321
322 return skb;
323 }
324 EXPORT_SYMBOL_GPL(nci_spi_read);
325
326 MODULE_LICENSE("GPL");
This page took 0.03777 seconds and 5 git commands to generate.