blob: ec250e77763a1d1e23f0560c151972ce274f82bc [file] [log] [blame]
Frederic Danis8a00a612013-05-29 15:35:02 +02001/*
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/export.h>
22#include <linux/spi/spi.h>
Frederic Danisee9596d2013-05-29 15:35:03 +020023#include <linux/crc-ccitt.h>
Frederic Danis8a00a612013-05-29 15:35:02 +020024#include <net/nfc/nci_core.h>
25
Frederic Danis391d8a22013-05-29 15:35:04 +020026#define NCI_SPI_ACK_SHIFT 6
27#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
Frederic Danis8a00a612013-05-29 15:35:02 +020028
Frederic Danisee9596d2013-05-29 15:35:03 +020029#define NCI_SPI_SEND_TIMEOUT (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
30 NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
31
32#define NCI_SPI_DIRECT_WRITE 0x01
33#define NCI_SPI_DIRECT_READ 0x02
34
35#define ACKNOWLEDGE_NONE 0
36#define ACKNOWLEDGE_ACK 1
37#define ACKNOWLEDGE_NACK 2
38
39#define CRC_INIT 0xFFFF
40
Eric Lapuyade2bed2782013-09-23 17:56:43 +020041static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb,
42 int cs_change)
Frederic Danisee9596d2013-05-29 15:35:03 +020043{
44 struct spi_message m;
45 struct spi_transfer t;
46
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +020047 memset(&t, 0, sizeof(struct spi_transfer));
Eric Lapuyade2bed2782013-09-23 17:56:43 +020048 /* a NULL skb means we just want the SPI chip select line to raise */
49 if (skb) {
50 t.tx_buf = skb->data;
51 t.len = skb->len;
52 } else {
53 /* still set tx_buf non NULL to make the driver happy */
54 t.tx_buf = &t;
55 t.len = 0;
56 }
57 t.cs_change = cs_change;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +020058 t.delay_usecs = nspi->xfer_udelay;
Frederic Danisee9596d2013-05-29 15:35:03 +020059
60 spi_message_init(&m);
61 spi_message_add_tail(&t, &m);
62
Eric Lapuyadefa544ff2013-09-05 11:02:21 +020063 return spi_sync(nspi->spi, &m);
Frederic Danisee9596d2013-05-29 15:35:03 +020064}
65
Eric Lapuyade2bed2782013-09-23 17:56:43 +020066int nci_spi_send(struct nci_spi *nspi,
67 struct completion *write_handshake_completion,
68 struct sk_buff *skb)
Frederic Danis8a00a612013-05-29 15:35:02 +020069{
Frederic Danisee9596d2013-05-29 15:35:03 +020070 unsigned int payload_len = skb->len;
71 unsigned char *hdr;
72 int ret;
73 long completion_rc;
74
Frederic Danisee9596d2013-05-29 15:35:03 +020075 /* add the NCI SPI header to the start of the buffer */
76 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
77 hdr[0] = NCI_SPI_DIRECT_WRITE;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +020078 hdr[1] = nspi->acknowledge_mode;
Frederic Danisee9596d2013-05-29 15:35:03 +020079 hdr[2] = payload_len >> 8;
80 hdr[3] = payload_len & 0xFF;
81
Eric Lapuyadefa544ff2013-09-05 11:02:21 +020082 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
Frederic Danisee9596d2013-05-29 15:35:03 +020083 u16 crc;
84
85 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
86 *skb_put(skb, 1) = crc >> 8;
87 *skb_put(skb, 1) = crc & 0xFF;
88 }
89
Eric Lapuyade2bed2782013-09-23 17:56:43 +020090 if (write_handshake_completion) {
91 /* Trick SPI driver to raise chip select */
92 ret = __nci_spi_send(nspi, NULL, 1);
93 if (ret)
94 goto done;
Frederic Danisee9596d2013-05-29 15:35:03 +020095
Eric Lapuyade2bed2782013-09-23 17:56:43 +020096 /* wait for NFC chip hardware handshake to complete */
97 if (wait_for_completion_timeout(write_handshake_completion,
98 msecs_to_jiffies(1000)) == 0) {
99 ret = -ETIME;
100 goto done;
101 }
102 }
Frederic Danisee9596d2013-05-29 15:35:03 +0200103
Eric Lapuyade2bed2782013-09-23 17:56:43 +0200104 ret = __nci_spi_send(nspi, skb, 0);
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200105 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
Frederic Danisee9596d2013-05-29 15:35:03 +0200106 goto done;
107
Axel Lin9bec44b2014-02-13 13:25:48 +0800108 reinit_completion(&nspi->req_completion);
Eric Lapuyaded5937512013-09-02 12:35:39 +0200109 completion_rc = wait_for_completion_interruptible_timeout(
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200110 &nspi->req_completion,
Eric Lapuyaded5937512013-09-02 12:35:39 +0200111 NCI_SPI_SEND_TIMEOUT);
Frederic Danisee9596d2013-05-29 15:35:03 +0200112
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200113 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
Frederic Danisee9596d2013-05-29 15:35:03 +0200114 ret = -EIO;
115
116done:
Eric Lapuyade2bed2782013-09-23 17:56:43 +0200117 kfree_skb(skb);
118
Frederic Danisee9596d2013-05-29 15:35:03 +0200119 return ret;
Frederic Danis8a00a612013-05-29 15:35:02 +0200120}
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200121EXPORT_SYMBOL_GPL(nci_spi_send);
Frederic Danis8a00a612013-05-29 15:35:02 +0200122
123/* ---- Interface to NCI SPI drivers ---- */
124
125/**
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200126 * nci_spi_allocate_spi - allocate a new nci spi
Frederic Danis8a00a612013-05-29 15:35:02 +0200127 *
128 * @spi: SPI device
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200129 * @acknowledge_mode: Acknowledge mode used by the NFC device
Frederic Danis8a00a612013-05-29 15:35:02 +0200130 * @delay: delay between transactions in us
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200131 * @ndev: nci dev to send incoming nci frames to
Frederic Danis8a00a612013-05-29 15:35:02 +0200132 */
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200133struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200134 u8 acknowledge_mode, unsigned int delay,
135 struct nci_dev *ndev)
Frederic Danis8a00a612013-05-29 15:35:02 +0200136{
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200137 struct nci_spi *nspi;
Frederic Danis8a00a612013-05-29 15:35:02 +0200138
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200139 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
140 if (!nspi)
Frederic Danis8a00a612013-05-29 15:35:02 +0200141 return NULL;
142
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200143 nspi->acknowledge_mode = acknowledge_mode;
144 nspi->xfer_udelay = delay;
Frederic Danis8a00a612013-05-29 15:35:02 +0200145
Eric Lapuyade645d5082013-09-19 16:52:06 +0200146 nspi->spi = spi;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200147 nspi->ndev = ndev;
Axel Lin9bec44b2014-02-13 13:25:48 +0800148 init_completion(&nspi->req_completion);
Frederic Danis8a00a612013-05-29 15:35:02 +0200149
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200150 return nspi;
Frederic Danis8a00a612013-05-29 15:35:02 +0200151}
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200152EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
Frederic Danis8a00a612013-05-29 15:35:02 +0200153
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200154static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
Frederic Danis391d8a22013-05-29 15:35:04 +0200155{
156 struct sk_buff *skb;
157 unsigned char *hdr;
158 u16 crc;
159 int ret;
160
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200161 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
Frederic Danis391d8a22013-05-29 15:35:04 +0200162
163 /* add the NCI SPI header to the start of the buffer */
164 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
165 hdr[0] = NCI_SPI_DIRECT_WRITE;
166 hdr[1] = NCI_SPI_CRC_ENABLED;
167 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
168 hdr[3] = 0;
169
170 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
171 *skb_put(skb, 1) = crc >> 8;
172 *skb_put(skb, 1) = crc & 0xFF;
173
Eric Lapuyade2bed2782013-09-23 17:56:43 +0200174 ret = __nci_spi_send(nspi, skb, 0);
Frederic Danis391d8a22013-05-29 15:35:04 +0200175
176 kfree_skb(skb);
177
178 return ret;
179}
180
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200181static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
Frederic Danis391d8a22013-05-29 15:35:04 +0200182{
183 struct sk_buff *skb;
184 struct spi_message m;
185 unsigned char req[2], resp_hdr[2];
186 struct spi_transfer tx, rx;
187 unsigned short rx_len = 0;
188 int ret;
189
190 spi_message_init(&m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200191
192 memset(&tx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200193 req[0] = NCI_SPI_DIRECT_READ;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200194 req[1] = nspi->acknowledge_mode;
Frederic Danis391d8a22013-05-29 15:35:04 +0200195 tx.tx_buf = req;
196 tx.len = 2;
197 tx.cs_change = 0;
198 spi_message_add_tail(&tx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200199
200 memset(&rx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200201 rx.rx_buf = resp_hdr;
202 rx.len = 2;
203 rx.cs_change = 1;
204 spi_message_add_tail(&rx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200205
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200206 ret = spi_sync(nspi->spi, &m);
Frederic Danis391d8a22013-05-29 15:35:04 +0200207 if (ret)
208 return NULL;
209
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200210 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
Frederic Danis391d8a22013-05-29 15:35:04 +0200211 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
212 resp_hdr[1] + NCI_SPI_CRC_LEN;
213 else
214 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
215
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200216 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
Frederic Danis391d8a22013-05-29 15:35:04 +0200217 if (!skb)
218 return NULL;
219
220 spi_message_init(&m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200221
222 memset(&rx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200223 rx.rx_buf = skb_put(skb, rx_len);
224 rx.len = rx_len;
225 rx.cs_change = 0;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200226 rx.delay_usecs = nspi->xfer_udelay;
Frederic Danis391d8a22013-05-29 15:35:04 +0200227 spi_message_add_tail(&rx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200228
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200229 ret = spi_sync(nspi->spi, &m);
Frederic Danis391d8a22013-05-29 15:35:04 +0200230 if (ret)
231 goto receive_error;
232
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200233 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200234 *skb_push(skb, 1) = resp_hdr[1];
235 *skb_push(skb, 1) = resp_hdr[0];
236 }
237
238 return skb;
239
240receive_error:
241 kfree_skb(skb);
242
243 return NULL;
244}
245
246static int nci_spi_check_crc(struct sk_buff *skb)
247{
248 u16 crc_data = (skb->data[skb->len - 2] << 8) |
249 skb->data[skb->len - 1];
250 int ret;
251
252 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
253 == crc_data);
254
255 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
256
257 return ret;
258}
259
260static u8 nci_spi_get_ack(struct sk_buff *skb)
261{
262 u8 ret;
263
264 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
265
266 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
267 skb_pull(skb, 2);
268
269 return ret;
270}
271
272/**
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200273 * nci_spi_read - read frame from NCI SPI drivers
Frederic Danis391d8a22013-05-29 15:35:04 +0200274 *
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200275 * @nspi: The nci spi
Frederic Danis391d8a22013-05-29 15:35:04 +0200276 * Context: can sleep
277 *
278 * This call may only be used from a context that may sleep. The sleep
279 * is non-interruptible, and has no timeout.
280 *
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200281 * It returns an allocated skb containing the frame on success, or NULL.
Frederic Danis391d8a22013-05-29 15:35:04 +0200282 */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200283struct sk_buff *nci_spi_read(struct nci_spi *nspi)
Frederic Danis391d8a22013-05-29 15:35:04 +0200284{
285 struct sk_buff *skb;
Frederic Danis391d8a22013-05-29 15:35:04 +0200286
Frederic Danis391d8a22013-05-29 15:35:04 +0200287 /* Retrieve frame from SPI */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200288 skb = __nci_spi_read(nspi);
289 if (!skb)
Frederic Danis391d8a22013-05-29 15:35:04 +0200290 goto done;
Frederic Danis391d8a22013-05-29 15:35:04 +0200291
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200292 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200293 if (!nci_spi_check_crc(skb)) {
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200294 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
Frederic Danis391d8a22013-05-29 15:35:04 +0200295 goto done;
296 }
297
298 /* In case of acknowledged mode: if ACK or NACK received,
299 * unblock completion of latest frame sent.
300 */
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200301 nspi->req_result = nci_spi_get_ack(skb);
302 if (nspi->req_result)
303 complete(&nspi->req_completion);
Frederic Danis391d8a22013-05-29 15:35:04 +0200304 }
305
306 /* If there is no payload (ACK/NACK only frame),
307 * free the socket buffer
308 */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200309 if (!skb->len) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200310 kfree_skb(skb);
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200311 skb = NULL;
Frederic Danis391d8a22013-05-29 15:35:04 +0200312 goto done;
313 }
314
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200315 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
316 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
Frederic Danis391d8a22013-05-29 15:35:04 +0200317
Frederic Danis391d8a22013-05-29 15:35:04 +0200318done:
Frederic Danis391d8a22013-05-29 15:35:04 +0200319
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200320 return skb;
Frederic Danis391d8a22013-05-29 15:35:04 +0200321}
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200322EXPORT_SYMBOL_GPL(nci_spi_read);