xref: /openbmc/linux/net/nfc/nci/spi.c (revision ee8a99bd)
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>
23 #include <linux/crc-ccitt.h>
24 #include <linux/nfc.h>
25 #include <net/nfc/nci_core.h>
26 
27 #define NCI_SPI_HDR_LEN			4
28 #define NCI_SPI_CRC_LEN			2
29 #define NCI_SPI_ACK_SHIFT		6
30 #define NCI_SPI_MSB_PAYLOAD_MASK	0x3F
31 
32 #define NCI_SPI_SEND_TIMEOUT	(NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
33 					NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
34 
35 #define NCI_SPI_DIRECT_WRITE	0x01
36 #define NCI_SPI_DIRECT_READ	0x02
37 
38 #define ACKNOWLEDGE_NONE	0
39 #define ACKNOWLEDGE_ACK		1
40 #define ACKNOWLEDGE_NACK	2
41 
42 #define CRC_INIT		0xFFFF
43 
44 static int nci_spi_open(struct nci_dev *nci_dev)
45 {
46 	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
47 
48 	return ndev->ops->open(ndev);
49 }
50 
51 static int nci_spi_close(struct nci_dev *nci_dev)
52 {
53 	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
54 
55 	return ndev->ops->close(ndev);
56 }
57 
58 static int __nci_spi_send(struct nci_spi_dev *ndev, struct sk_buff *skb)
59 {
60 	struct spi_message m;
61 	struct spi_transfer t;
62 
63 	t.tx_buf = skb->data;
64 	t.len = skb->len;
65 	t.cs_change = 0;
66 	t.delay_usecs = ndev->xfer_udelay;
67 
68 	spi_message_init(&m);
69 	spi_message_add_tail(&t, &m);
70 
71 	return spi_sync(ndev->spi, &m);
72 }
73 
74 static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb)
75 {
76 	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
77 	unsigned int payload_len = skb->len;
78 	unsigned char *hdr;
79 	int ret;
80 	long completion_rc;
81 
82 	ndev->ops->deassert_int(ndev);
83 
84 	/* add the NCI SPI header to the start of the buffer */
85 	hdr = skb_push(skb, NCI_SPI_HDR_LEN);
86 	hdr[0] = NCI_SPI_DIRECT_WRITE;
87 	hdr[1] = ndev->acknowledge_mode;
88 	hdr[2] = payload_len >> 8;
89 	hdr[3] = payload_len & 0xFF;
90 
91 	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
92 		u16 crc;
93 
94 		crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
95 		*skb_put(skb, 1) = crc >> 8;
96 		*skb_put(skb, 1) = crc & 0xFF;
97 	}
98 
99 	ret = __nci_spi_send(ndev, skb);
100 
101 	kfree_skb(skb);
102 	ndev->ops->assert_int(ndev);
103 
104 	if (ret != 0 || ndev->acknowledge_mode == NCI_SPI_CRC_DISABLED)
105 		goto done;
106 
107 	init_completion(&ndev->req_completion);
108 	completion_rc =
109 		wait_for_completion_interruptible_timeout(&ndev->req_completion,
110 							  NCI_SPI_SEND_TIMEOUT);
111 
112 	if (completion_rc <= 0 || ndev->req_result == ACKNOWLEDGE_NACK)
113 		ret = -EIO;
114 
115 done:
116 	return ret;
117 }
118 
119 static struct nci_ops nci_spi_ops = {
120 	.open = nci_spi_open,
121 	.close = nci_spi_close,
122 	.send = nci_spi_send,
123 };
124 
125 /* ---- Interface to NCI SPI drivers ---- */
126 
127 /**
128  * nci_spi_allocate_device - allocate a new nci spi device
129  *
130  * @spi: SPI device
131  * @ops: device operations
132  * @supported_protocols: NFC protocols supported by the device
133  * @supported_se: NFC Secure Elements supported by the device
134  * @acknowledge_mode: Acknowledge mode used by the device
135  * @delay: delay between transactions in us
136  */
137 struct nci_spi_dev *nci_spi_allocate_device(struct spi_device *spi,
138 						struct nci_spi_ops *ops,
139 						u32 supported_protocols,
140 						u32 supported_se,
141 						u8 acknowledge_mode,
142 						unsigned int delay)
143 {
144 	struct nci_spi_dev *ndev;
145 	int tailroom = 0;
146 
147 	if (!ops->open || !ops->close || !ops->assert_int || !ops->deassert_int)
148 		return NULL;
149 
150 	if (!supported_protocols)
151 		return NULL;
152 
153 	ndev = devm_kzalloc(&spi->dev, sizeof(struct nci_dev), GFP_KERNEL);
154 	if (!ndev)
155 		return NULL;
156 
157 	ndev->ops = ops;
158 	ndev->acknowledge_mode = acknowledge_mode;
159 	ndev->xfer_udelay = delay;
160 
161 	if (acknowledge_mode == NCI_SPI_CRC_ENABLED)
162 		tailroom += NCI_SPI_CRC_LEN;
163 
164 	ndev->nci_dev = nci_allocate_device(&nci_spi_ops, supported_protocols,
165 					    NCI_SPI_HDR_LEN, tailroom);
166 	if (!ndev->nci_dev)
167 		return NULL;
168 
169 	nci_set_drvdata(ndev->nci_dev, ndev);
170 
171 	return ndev;
172 }
173 EXPORT_SYMBOL_GPL(nci_spi_allocate_device);
174 
175 /**
176  * nci_spi_free_device - deallocate nci spi device
177  *
178  * @ndev: The nci spi device to deallocate
179  */
180 void nci_spi_free_device(struct nci_spi_dev *ndev)
181 {
182 	nci_free_device(ndev->nci_dev);
183 }
184 EXPORT_SYMBOL_GPL(nci_spi_free_device);
185 
186 /**
187  * nci_spi_register_device - register a nci spi device in the nfc subsystem
188  *
189  * @pdev: The nci spi device to register
190  */
191 int nci_spi_register_device(struct nci_spi_dev *ndev)
192 {
193 	return nci_register_device(ndev->nci_dev);
194 }
195 EXPORT_SYMBOL_GPL(nci_spi_register_device);
196 
197 /**
198  * nci_spi_unregister_device - unregister a nci spi device in the nfc subsystem
199  *
200  * @dev: The nci spi device to unregister
201  */
202 void nci_spi_unregister_device(struct nci_spi_dev *ndev)
203 {
204 	nci_unregister_device(ndev->nci_dev);
205 }
206 EXPORT_SYMBOL_GPL(nci_spi_unregister_device);
207 
208 static int send_acknowledge(struct nci_spi_dev *ndev, u8 acknowledge)
209 {
210 	struct sk_buff *skb;
211 	unsigned char *hdr;
212 	u16 crc;
213 	int ret;
214 
215 	skb = nci_skb_alloc(ndev->nci_dev, 0, GFP_KERNEL);
216 
217 	/* add the NCI SPI header to the start of the buffer */
218 	hdr = skb_push(skb, NCI_SPI_HDR_LEN);
219 	hdr[0] = NCI_SPI_DIRECT_WRITE;
220 	hdr[1] = NCI_SPI_CRC_ENABLED;
221 	hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
222 	hdr[3] = 0;
223 
224 	crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
225 	*skb_put(skb, 1) = crc >> 8;
226 	*skb_put(skb, 1) = crc & 0xFF;
227 
228 	ret = __nci_spi_send(ndev, skb);
229 
230 	kfree_skb(skb);
231 
232 	return ret;
233 }
234 
235 static struct sk_buff *__nci_spi_recv_frame(struct nci_spi_dev *ndev)
236 {
237 	struct sk_buff *skb;
238 	struct spi_message m;
239 	unsigned char req[2], resp_hdr[2];
240 	struct spi_transfer tx, rx;
241 	unsigned short rx_len = 0;
242 	int ret;
243 
244 	spi_message_init(&m);
245 	req[0] = NCI_SPI_DIRECT_READ;
246 	req[1] = ndev->acknowledge_mode;
247 	tx.tx_buf = req;
248 	tx.len = 2;
249 	tx.cs_change = 0;
250 	spi_message_add_tail(&tx, &m);
251 	rx.rx_buf = resp_hdr;
252 	rx.len = 2;
253 	rx.cs_change = 1;
254 	spi_message_add_tail(&rx, &m);
255 	ret = spi_sync(ndev->spi, &m);
256 
257 	if (ret)
258 		return NULL;
259 
260 	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED)
261 		rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
262 				resp_hdr[1] + NCI_SPI_CRC_LEN;
263 	else
264 		rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
265 
266 	skb = nci_skb_alloc(ndev->nci_dev, rx_len, GFP_KERNEL);
267 	if (!skb)
268 		return NULL;
269 
270 	spi_message_init(&m);
271 	rx.rx_buf = skb_put(skb, rx_len);
272 	rx.len = rx_len;
273 	rx.cs_change = 0;
274 	rx.delay_usecs = ndev->xfer_udelay;
275 	spi_message_add_tail(&rx, &m);
276 	ret = spi_sync(ndev->spi, &m);
277 
278 	if (ret)
279 		goto receive_error;
280 
281 	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
282 		*skb_push(skb, 1) = resp_hdr[1];
283 		*skb_push(skb, 1) = resp_hdr[0];
284 	}
285 
286 	return skb;
287 
288 receive_error:
289 	kfree_skb(skb);
290 
291 	return NULL;
292 }
293 
294 static int nci_spi_check_crc(struct sk_buff *skb)
295 {
296 	u16 crc_data = (skb->data[skb->len - 2] << 8) |
297 			skb->data[skb->len - 1];
298 	int ret;
299 
300 	ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
301 			== crc_data);
302 
303 	skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
304 
305 	return ret;
306 }
307 
308 static u8 nci_spi_get_ack(struct sk_buff *skb)
309 {
310 	u8 ret;
311 
312 	ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
313 
314 	/* Remove NFCC part of the header: ACK, NACK and MSB payload len */
315 	skb_pull(skb, 2);
316 
317 	return ret;
318 }
319 
320 /**
321  * nci_spi_recv_frame - receive frame from NCI SPI drivers
322  *
323  * @ndev: The nci spi device
324  * Context: can sleep
325  *
326  * This call may only be used from a context that may sleep.  The sleep
327  * is non-interruptible, and has no timeout.
328  *
329  * It returns zero on success, else a negative error code.
330  */
331 int nci_spi_recv_frame(struct nci_spi_dev *ndev)
332 {
333 	struct sk_buff *skb;
334 	int ret = 0;
335 
336 	ndev->ops->deassert_int(ndev);
337 
338 	/* Retrieve frame from SPI */
339 	skb = __nci_spi_recv_frame(ndev);
340 	if (!skb) {
341 		ret = -EIO;
342 		goto done;
343 	}
344 
345 	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
346 		if (!nci_spi_check_crc(skb)) {
347 			send_acknowledge(ndev, ACKNOWLEDGE_NACK);
348 			goto done;
349 		}
350 
351 		/* In case of acknowledged mode: if ACK or NACK received,
352 		 * unblock completion of latest frame sent.
353 		 */
354 		ndev->req_result = nci_spi_get_ack(skb);
355 		if (ndev->req_result)
356 			complete(&ndev->req_completion);
357 	}
358 
359 	/* If there is no payload (ACK/NACK only frame),
360 	 * free the socket buffer
361 	 */
362 	if (skb->len == 0) {
363 		kfree_skb(skb);
364 		goto done;
365 	}
366 
367 	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED)
368 		send_acknowledge(ndev, ACKNOWLEDGE_ACK);
369 
370 	/* Forward skb to NCI core layer */
371 	ret = nci_recv_frame(ndev->nci_dev, skb);
372 
373 done:
374 	ndev->ops->assert_int(ndev);
375 
376 	return ret;
377 }
378 EXPORT_SYMBOL_GPL(nci_spi_recv_frame);
379