NFC: netlink: SE API implementation
[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
21#include <linux/export.h>
22#include <linux/spi/spi.h>
ee9596d4 23#include <linux/crc-ccitt.h>
8a00a61b
FD
24#include <linux/nfc.h>
25#include <net/nfc/nci_core.h>
26
391d8a2d
FD
27#define NCI_SPI_ACK_SHIFT 6
28#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
8a00a61b 29
ee9596d4
FD
30#define NCI_SPI_SEND_TIMEOUT (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
31 NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
32
33#define NCI_SPI_DIRECT_WRITE 0x01
34#define NCI_SPI_DIRECT_READ 0x02
35
36#define ACKNOWLEDGE_NONE 0
37#define ACKNOWLEDGE_ACK 1
38#define ACKNOWLEDGE_NACK 2
39
40#define CRC_INIT 0xFFFF
41
fa544fff 42static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
ee9596d4
FD
43{
44 struct spi_message m;
45 struct spi_transfer t;
46
47 t.tx_buf = skb->data;
48 t.len = skb->len;
49 t.cs_change = 0;
fa544fff 50 t.delay_usecs = nspi->xfer_udelay;
ee9596d4
FD
51
52 spi_message_init(&m);
53 spi_message_add_tail(&t, &m);
54
fa544fff 55 return spi_sync(nspi->spi, &m);
ee9596d4
FD
56}
57
fa544fff 58int nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
8a00a61b 59{
ee9596d4
FD
60 unsigned int payload_len = skb->len;
61 unsigned char *hdr;
62 int ret;
63 long completion_rc;
64
fa544fff 65 nspi->ops->deassert_int(nspi);
ee9596d4
FD
66
67 /* add the NCI SPI header to the start of the buffer */
68 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
69 hdr[0] = NCI_SPI_DIRECT_WRITE;
fa544fff 70 hdr[1] = nspi->acknowledge_mode;
ee9596d4
FD
71 hdr[2] = payload_len >> 8;
72 hdr[3] = payload_len & 0xFF;
73
fa544fff 74 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
ee9596d4
FD
75 u16 crc;
76
77 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
78 *skb_put(skb, 1) = crc >> 8;
79 *skb_put(skb, 1) = crc & 0xFF;
80 }
81
fa544fff 82 ret = __nci_spi_send(nspi, skb);
ee9596d4
FD
83
84 kfree_skb(skb);
fa544fff 85 nspi->ops->assert_int(nspi);
ee9596d4 86
fa544fff 87 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
ee9596d4
FD
88 goto done;
89
fa544fff 90 init_completion(&nspi->req_completion);
d5937511 91 completion_rc = wait_for_completion_interruptible_timeout(
fa544fff 92 &nspi->req_completion,
d5937511 93 NCI_SPI_SEND_TIMEOUT);
ee9596d4 94
fa544fff 95 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
ee9596d4
FD
96 ret = -EIO;
97
98done:
99 return ret;
8a00a61b 100}
fa544fff 101EXPORT_SYMBOL_GPL(nci_spi_send);
8a00a61b
FD
102
103/* ---- Interface to NCI SPI drivers ---- */
104
105/**
fa544fff 106 * nci_spi_allocate_spi - allocate a new nci spi
8a00a61b
FD
107 *
108 * @spi: SPI device
109 * @ops: device operations
fa544fff 110 * @acknowledge_mode: Acknowledge mode used by the NFC device
8a00a61b 111 * @delay: delay between transactions in us
fa544fff 112 * @ndev: nci dev to send incoming nci frames to
8a00a61b 113 */
fa544fff
EL
114struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
115 struct nci_spi_ops *ops,
116 u8 acknowledge_mode, unsigned int delay,
117 struct nci_dev *ndev)
8a00a61b 118{
fa544fff 119 struct nci_spi *nspi;
8a00a61b 120
fa544fff 121 if (!ops->assert_int || !ops->deassert_int)
8a00a61b
FD
122 return NULL;
123
fa544fff
EL
124 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
125 if (!nspi)
8a00a61b
FD
126 return NULL;
127
fa544fff
EL
128 nspi->ops = ops;
129 nspi->acknowledge_mode = acknowledge_mode;
130 nspi->xfer_udelay = delay;
8a00a61b 131
645d5087 132 nspi->spi = spi;
fa544fff 133 nspi->ndev = ndev;
8a00a61b 134
fa544fff 135 return nspi;
8a00a61b 136}
fa544fff 137EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
391d8a2d 138
fa544fff 139static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
391d8a2d
FD
140{
141 struct sk_buff *skb;
142 unsigned char *hdr;
143 u16 crc;
144 int ret;
145
fa544fff 146 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
391d8a2d
FD
147
148 /* add the NCI SPI header to the start of the buffer */
149 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
150 hdr[0] = NCI_SPI_DIRECT_WRITE;
151 hdr[1] = NCI_SPI_CRC_ENABLED;
152 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
153 hdr[3] = 0;
154
155 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
156 *skb_put(skb, 1) = crc >> 8;
157 *skb_put(skb, 1) = crc & 0xFF;
158
fa544fff 159 ret = __nci_spi_send(nspi, skb);
391d8a2d
FD
160
161 kfree_skb(skb);
162
163 return ret;
164}
165
fa544fff 166static struct sk_buff *__nci_spi_recv_frame(struct nci_spi *nspi)
391d8a2d
FD
167{
168 struct sk_buff *skb;
169 struct spi_message m;
170 unsigned char req[2], resp_hdr[2];
171 struct spi_transfer tx, rx;
172 unsigned short rx_len = 0;
173 int ret;
174
175 spi_message_init(&m);
176 req[0] = NCI_SPI_DIRECT_READ;
fa544fff 177 req[1] = nspi->acknowledge_mode;
391d8a2d
FD
178 tx.tx_buf = req;
179 tx.len = 2;
180 tx.cs_change = 0;
181 spi_message_add_tail(&tx, &m);
182 rx.rx_buf = resp_hdr;
183 rx.len = 2;
184 rx.cs_change = 1;
185 spi_message_add_tail(&rx, &m);
fa544fff 186 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
187
188 if (ret)
189 return NULL;
190
fa544fff 191 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
391d8a2d
FD
192 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
193 resp_hdr[1] + NCI_SPI_CRC_LEN;
194 else
195 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
196
fa544fff 197 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
391d8a2d
FD
198 if (!skb)
199 return NULL;
200
201 spi_message_init(&m);
202 rx.rx_buf = skb_put(skb, rx_len);
203 rx.len = rx_len;
204 rx.cs_change = 0;
fa544fff 205 rx.delay_usecs = nspi->xfer_udelay;
391d8a2d 206 spi_message_add_tail(&rx, &m);
fa544fff 207 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
208
209 if (ret)
210 goto receive_error;
211
fa544fff 212 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d
FD
213 *skb_push(skb, 1) = resp_hdr[1];
214 *skb_push(skb, 1) = resp_hdr[0];
215 }
216
217 return skb;
218
219receive_error:
220 kfree_skb(skb);
221
222 return NULL;
223}
224
225static int nci_spi_check_crc(struct sk_buff *skb)
226{
227 u16 crc_data = (skb->data[skb->len - 2] << 8) |
228 skb->data[skb->len - 1];
229 int ret;
230
231 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
232 == crc_data);
233
234 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
235
236 return ret;
237}
238
239static u8 nci_spi_get_ack(struct sk_buff *skb)
240{
241 u8 ret;
242
243 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
244
245 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
246 skb_pull(skb, 2);
247
248 return ret;
249}
250
251/**
252 * nci_spi_recv_frame - receive frame from NCI SPI drivers
253 *
fa544fff 254 * @nspi: The nci spi
391d8a2d
FD
255 * Context: can sleep
256 *
257 * This call may only be used from a context that may sleep. The sleep
258 * is non-interruptible, and has no timeout.
259 *
260 * It returns zero on success, else a negative error code.
261 */
fa544fff 262int nci_spi_recv_frame(struct nci_spi *nspi)
391d8a2d
FD
263{
264 struct sk_buff *skb;
265 int ret = 0;
266
fa544fff 267 nspi->ops->deassert_int(nspi);
391d8a2d
FD
268
269 /* Retrieve frame from SPI */
fa544fff 270 skb = __nci_spi_recv_frame(nspi);
391d8a2d
FD
271 if (!skb) {
272 ret = -EIO;
273 goto done;
274 }
275
fa544fff 276 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d 277 if (!nci_spi_check_crc(skb)) {
fa544fff 278 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
391d8a2d
FD
279 goto done;
280 }
281
282 /* In case of acknowledged mode: if ACK or NACK received,
283 * unblock completion of latest frame sent.
284 */
fa544fff
EL
285 nspi->req_result = nci_spi_get_ack(skb);
286 if (nspi->req_result)
287 complete(&nspi->req_completion);
391d8a2d
FD
288 }
289
290 /* If there is no payload (ACK/NACK only frame),
291 * free the socket buffer
292 */
293 if (skb->len == 0) {
294 kfree_skb(skb);
295 goto done;
296 }
297
fa544fff
EL
298 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
299 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
391d8a2d
FD
300
301 /* Forward skb to NCI core layer */
fa544fff 302 ret = nci_recv_frame(nspi->ndev, skb);
391d8a2d
FD
303
304done:
fa544fff 305 nspi->ops->assert_int(nspi);
391d8a2d
FD
306
307 return ret;
308}
309EXPORT_SYMBOL_GPL(nci_spi_recv_frame);
This page took 0.056312 seconds and 5 git commands to generate.