blob: f1d426f10cceac10b0befc9f1c98caa6ad5b7793 [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
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200108 init_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;
Frederic Danis8a00a612013-05-29 15:35:02 +0200148
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200149 return nspi;
Frederic Danis8a00a612013-05-29 15:35:02 +0200150}
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200151EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
Frederic Danis8a00a612013-05-29 15:35:02 +0200152
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200153static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
Frederic Danis391d8a22013-05-29 15:35:04 +0200154{
155 struct sk_buff *skb;
156 unsigned char *hdr;
157 u16 crc;
158 int ret;
159
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200160 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
Frederic Danis391d8a22013-05-29 15:35:04 +0200161
162 /* add the NCI SPI header to the start of the buffer */
163 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
164 hdr[0] = NCI_SPI_DIRECT_WRITE;
165 hdr[1] = NCI_SPI_CRC_ENABLED;
166 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
167 hdr[3] = 0;
168
169 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
170 *skb_put(skb, 1) = crc >> 8;
171 *skb_put(skb, 1) = crc & 0xFF;
172
Eric Lapuyade2bed2782013-09-23 17:56:43 +0200173 ret = __nci_spi_send(nspi, skb, 0);
Frederic Danis391d8a22013-05-29 15:35:04 +0200174
175 kfree_skb(skb);
176
177 return ret;
178}
179
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200180static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
Frederic Danis391d8a22013-05-29 15:35:04 +0200181{
182 struct sk_buff *skb;
183 struct spi_message m;
184 unsigned char req[2], resp_hdr[2];
185 struct spi_transfer tx, rx;
186 unsigned short rx_len = 0;
187 int ret;
188
189 spi_message_init(&m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200190
191 memset(&tx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200192 req[0] = NCI_SPI_DIRECT_READ;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200193 req[1] = nspi->acknowledge_mode;
Frederic Danis391d8a22013-05-29 15:35:04 +0200194 tx.tx_buf = req;
195 tx.len = 2;
196 tx.cs_change = 0;
197 spi_message_add_tail(&tx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200198
199 memset(&rx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200200 rx.rx_buf = resp_hdr;
201 rx.len = 2;
202 rx.cs_change = 1;
203 spi_message_add_tail(&rx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200204
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200205 ret = spi_sync(nspi->spi, &m);
Frederic Danis391d8a22013-05-29 15:35:04 +0200206 if (ret)
207 return NULL;
208
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200209 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
Frederic Danis391d8a22013-05-29 15:35:04 +0200210 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
211 resp_hdr[1] + NCI_SPI_CRC_LEN;
212 else
213 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
214
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200215 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
Frederic Danis391d8a22013-05-29 15:35:04 +0200216 if (!skb)
217 return NULL;
218
219 spi_message_init(&m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200220
221 memset(&rx, 0, sizeof(struct spi_transfer));
Frederic Danis391d8a22013-05-29 15:35:04 +0200222 rx.rx_buf = skb_put(skb, rx_len);
223 rx.len = rx_len;
224 rx.cs_change = 0;
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200225 rx.delay_usecs = nspi->xfer_udelay;
Frederic Danis391d8a22013-05-29 15:35:04 +0200226 spi_message_add_tail(&rx, &m);
Eric Lapuyadea4ada6c2013-09-23 18:02:43 +0200227
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200228 ret = spi_sync(nspi->spi, &m);
Frederic Danis391d8a22013-05-29 15:35:04 +0200229 if (ret)
230 goto receive_error;
231
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200232 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200233 *skb_push(skb, 1) = resp_hdr[1];
234 *skb_push(skb, 1) = resp_hdr[0];
235 }
236
237 return skb;
238
239receive_error:
240 kfree_skb(skb);
241
242 return NULL;
243}
244
245static int nci_spi_check_crc(struct sk_buff *skb)
246{
247 u16 crc_data = (skb->data[skb->len - 2] << 8) |
248 skb->data[skb->len - 1];
249 int ret;
250
251 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
252 == crc_data);
253
254 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
255
256 return ret;
257}
258
259static u8 nci_spi_get_ack(struct sk_buff *skb)
260{
261 u8 ret;
262
263 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
264
265 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
266 skb_pull(skb, 2);
267
268 return ret;
269}
270
271/**
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200272 * nci_spi_read - read frame from NCI SPI drivers
Frederic Danis391d8a22013-05-29 15:35:04 +0200273 *
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200274 * @nspi: The nci spi
Frederic Danis391d8a22013-05-29 15:35:04 +0200275 * Context: can sleep
276 *
277 * This call may only be used from a context that may sleep. The sleep
278 * is non-interruptible, and has no timeout.
279 *
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200280 * It returns an allocated skb containing the frame on success, or NULL.
Frederic Danis391d8a22013-05-29 15:35:04 +0200281 */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200282struct sk_buff *nci_spi_read(struct nci_spi *nspi)
Frederic Danis391d8a22013-05-29 15:35:04 +0200283{
284 struct sk_buff *skb;
Frederic Danis391d8a22013-05-29 15:35:04 +0200285
Frederic Danis391d8a22013-05-29 15:35:04 +0200286 /* Retrieve frame from SPI */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200287 skb = __nci_spi_read(nspi);
288 if (!skb)
Frederic Danis391d8a22013-05-29 15:35:04 +0200289 goto done;
Frederic Danis391d8a22013-05-29 15:35:04 +0200290
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200291 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200292 if (!nci_spi_check_crc(skb)) {
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200293 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
Frederic Danis391d8a22013-05-29 15:35:04 +0200294 goto done;
295 }
296
297 /* In case of acknowledged mode: if ACK or NACK received,
298 * unblock completion of latest frame sent.
299 */
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200300 nspi->req_result = nci_spi_get_ack(skb);
301 if (nspi->req_result)
302 complete(&nspi->req_completion);
Frederic Danis391d8a22013-05-29 15:35:04 +0200303 }
304
305 /* If there is no payload (ACK/NACK only frame),
306 * free the socket buffer
307 */
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200308 if (!skb->len) {
Frederic Danis391d8a22013-05-29 15:35:04 +0200309 kfree_skb(skb);
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200310 skb = NULL;
Frederic Danis391d8a22013-05-29 15:35:04 +0200311 goto done;
312 }
313
Eric Lapuyadefa544ff2013-09-05 11:02:21 +0200314 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
315 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
Frederic Danis391d8a22013-05-29 15:35:04 +0200316
Frederic Danis391d8a22013-05-29 15:35:04 +0200317done:
Frederic Danis391d8a22013-05-29 15:35:04 +0200318
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200319 return skb;
Frederic Danis391d8a22013-05-29 15:35:04 +0200320}
Eric Lapuyade22d4aae2013-09-23 17:56:31 +0200321EXPORT_SYMBOL_GPL(nci_spi_read);