Merge remote-tracking branch 'ipvs-next/master'
[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;
2bd83245 61 t.speed_hz = nspi->xfer_speed_hz;
ee9596d4
FD
62
63 spi_message_init(&m);
64 spi_message_add_tail(&t, &m);
65
fa544fff 66 return spi_sync(nspi->spi, &m);
ee9596d4
FD
67}
68
2bed2785
EL
69int nci_spi_send(struct nci_spi *nspi,
70 struct completion *write_handshake_completion,
71 struct sk_buff *skb)
8a00a61b 72{
ee9596d4
FD
73 unsigned int payload_len = skb->len;
74 unsigned char *hdr;
75 int ret;
76 long completion_rc;
77
ee9596d4
FD
78 /* add the NCI SPI header to the start of the buffer */
79 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
80 hdr[0] = NCI_SPI_DIRECT_WRITE;
fa544fff 81 hdr[1] = nspi->acknowledge_mode;
ee9596d4
FD
82 hdr[2] = payload_len >> 8;
83 hdr[3] = payload_len & 0xFF;
84
fa544fff 85 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
ee9596d4
FD
86 u16 crc;
87
88 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
89 *skb_put(skb, 1) = crc >> 8;
90 *skb_put(skb, 1) = crc & 0xFF;
91 }
92
2bed2785
EL
93 if (write_handshake_completion) {
94 /* Trick SPI driver to raise chip select */
95 ret = __nci_spi_send(nspi, NULL, 1);
96 if (ret)
97 goto done;
ee9596d4 98
2bed2785
EL
99 /* wait for NFC chip hardware handshake to complete */
100 if (wait_for_completion_timeout(write_handshake_completion,
101 msecs_to_jiffies(1000)) == 0) {
102 ret = -ETIME;
103 goto done;
104 }
105 }
ee9596d4 106
2bed2785 107 ret = __nci_spi_send(nspi, skb, 0);
fa544fff 108 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
ee9596d4
FD
109 goto done;
110
9bec44bf 111 reinit_completion(&nspi->req_completion);
d5937511 112 completion_rc = wait_for_completion_interruptible_timeout(
fa544fff 113 &nspi->req_completion,
d5937511 114 NCI_SPI_SEND_TIMEOUT);
ee9596d4 115
fa544fff 116 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
ee9596d4
FD
117 ret = -EIO;
118
119done:
2bed2785
EL
120 kfree_skb(skb);
121
ee9596d4 122 return ret;
8a00a61b 123}
fa544fff 124EXPORT_SYMBOL_GPL(nci_spi_send);
8a00a61b
FD
125
126/* ---- Interface to NCI SPI drivers ---- */
127
128/**
fa544fff 129 * nci_spi_allocate_spi - allocate a new nci spi
8a00a61b
FD
130 *
131 * @spi: SPI device
fa544fff 132 * @acknowledge_mode: Acknowledge mode used by the NFC device
8a00a61b 133 * @delay: delay between transactions in us
fa544fff 134 * @ndev: nci dev to send incoming nci frames to
8a00a61b 135 */
fa544fff 136struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
fa544fff
EL
137 u8 acknowledge_mode, unsigned int delay,
138 struct nci_dev *ndev)
8a00a61b 139{
fa544fff 140 struct nci_spi *nspi;
8a00a61b 141
fa544fff
EL
142 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
143 if (!nspi)
8a00a61b
FD
144 return NULL;
145
fa544fff
EL
146 nspi->acknowledge_mode = acknowledge_mode;
147 nspi->xfer_udelay = delay;
2bd83245
VC
148 /* Use controller max SPI speed by default */
149 nspi->xfer_speed_hz = 0;
645d5087 150 nspi->spi = spi;
fa544fff 151 nspi->ndev = ndev;
9bec44bf 152 init_completion(&nspi->req_completion);
8a00a61b 153
fa544fff 154 return nspi;
8a00a61b 155}
fa544fff 156EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
391d8a2d 157
fa544fff 158static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
391d8a2d
FD
159{
160 struct sk_buff *skb;
161 unsigned char *hdr;
162 u16 crc;
163 int ret;
164
fa544fff 165 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
391d8a2d
FD
166
167 /* add the NCI SPI header to the start of the buffer */
168 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
169 hdr[0] = NCI_SPI_DIRECT_WRITE;
170 hdr[1] = NCI_SPI_CRC_ENABLED;
171 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
172 hdr[3] = 0;
173
174 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
175 *skb_put(skb, 1) = crc >> 8;
176 *skb_put(skb, 1) = crc & 0xFF;
177
2bed2785 178 ret = __nci_spi_send(nspi, skb, 0);
391d8a2d
FD
179
180 kfree_skb(skb);
181
182 return ret;
183}
184
22d4aae5 185static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
391d8a2d
FD
186{
187 struct sk_buff *skb;
188 struct spi_message m;
189 unsigned char req[2], resp_hdr[2];
190 struct spi_transfer tx, rx;
191 unsigned short rx_len = 0;
192 int ret;
193
194 spi_message_init(&m);
a4ada6ca
EL
195
196 memset(&tx, 0, sizeof(struct spi_transfer));
391d8a2d 197 req[0] = NCI_SPI_DIRECT_READ;
fa544fff 198 req[1] = nspi->acknowledge_mode;
391d8a2d
FD
199 tx.tx_buf = req;
200 tx.len = 2;
201 tx.cs_change = 0;
2bd83245 202 tx.speed_hz = nspi->xfer_speed_hz;
391d8a2d 203 spi_message_add_tail(&tx, &m);
a4ada6ca
EL
204
205 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
206 rx.rx_buf = resp_hdr;
207 rx.len = 2;
208 rx.cs_change = 1;
2bd83245 209 rx.speed_hz = nspi->xfer_speed_hz;
391d8a2d 210 spi_message_add_tail(&rx, &m);
a4ada6ca 211
fa544fff 212 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
213 if (ret)
214 return NULL;
215
fa544fff 216 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
391d8a2d
FD
217 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
218 resp_hdr[1] + NCI_SPI_CRC_LEN;
219 else
220 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
221
fa544fff 222 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
391d8a2d
FD
223 if (!skb)
224 return NULL;
225
226 spi_message_init(&m);
a4ada6ca
EL
227
228 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
229 rx.rx_buf = skb_put(skb, rx_len);
230 rx.len = rx_len;
231 rx.cs_change = 0;
fa544fff 232 rx.delay_usecs = nspi->xfer_udelay;
2bd83245 233 rx.speed_hz = nspi->xfer_speed_hz;
391d8a2d 234 spi_message_add_tail(&rx, &m);
a4ada6ca 235
fa544fff 236 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
237 if (ret)
238 goto receive_error;
239
fa544fff 240 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d
FD
241 *skb_push(skb, 1) = resp_hdr[1];
242 *skb_push(skb, 1) = resp_hdr[0];
243 }
244
245 return skb;
246
247receive_error:
248 kfree_skb(skb);
249
250 return NULL;
251}
252
253static int nci_spi_check_crc(struct sk_buff *skb)
254{
255 u16 crc_data = (skb->data[skb->len - 2] << 8) |
256 skb->data[skb->len - 1];
257 int ret;
258
259 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
260 == crc_data);
261
262 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
263
264 return ret;
265}
266
267static u8 nci_spi_get_ack(struct sk_buff *skb)
268{
269 u8 ret;
270
271 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
272
273 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
274 skb_pull(skb, 2);
275
276 return ret;
277}
278
279/**
22d4aae5 280 * nci_spi_read - read frame from NCI SPI drivers
391d8a2d 281 *
fa544fff 282 * @nspi: The nci spi
391d8a2d
FD
283 * Context: can sleep
284 *
285 * This call may only be used from a context that may sleep. The sleep
286 * is non-interruptible, and has no timeout.
287 *
22d4aae5 288 * It returns an allocated skb containing the frame on success, or NULL.
391d8a2d 289 */
22d4aae5 290struct sk_buff *nci_spi_read(struct nci_spi *nspi)
391d8a2d
FD
291{
292 struct sk_buff *skb;
391d8a2d 293
391d8a2d 294 /* Retrieve frame from SPI */
22d4aae5
EL
295 skb = __nci_spi_read(nspi);
296 if (!skb)
391d8a2d 297 goto done;
391d8a2d 298
fa544fff 299 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d 300 if (!nci_spi_check_crc(skb)) {
fa544fff 301 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
391d8a2d
FD
302 goto done;
303 }
304
305 /* In case of acknowledged mode: if ACK or NACK received,
306 * unblock completion of latest frame sent.
307 */
fa544fff
EL
308 nspi->req_result = nci_spi_get_ack(skb);
309 if (nspi->req_result)
310 complete(&nspi->req_completion);
391d8a2d
FD
311 }
312
313 /* If there is no payload (ACK/NACK only frame),
314 * free the socket buffer
315 */
22d4aae5 316 if (!skb->len) {
391d8a2d 317 kfree_skb(skb);
22d4aae5 318 skb = NULL;
391d8a2d
FD
319 goto done;
320 }
321
fa544fff
EL
322 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
323 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
391d8a2d 324
391d8a2d 325done:
391d8a2d 326
22d4aae5 327 return skb;
391d8a2d 328}
22d4aae5 329EXPORT_SYMBOL_GPL(nci_spi_read);
fcd9d046
VC
330
331MODULE_LICENSE("GPL");
This page took 0.164207 seconds and 5 git commands to generate.