]>
Commit | Line | Data |
---|---|---|
5e72bc8b MM |
1 | /* |
2 | * Copyright (C) 2015-2020 Espressif Systems (Shanghai) PTE LTD | |
3 | * | |
4 | * This software file (the "File") is distributed by Espressif Systems (Shanghai) | |
5 | * PTE LTD under the terms of the GNU General Public License Version 2, June 1991 | |
6 | * (the "License"). You may use, redistribute and/or modify this File in | |
7 | * accordance with the terms and conditions of the License, a copy of which | |
8 | * is available by writing to the Free Software Foundation, Inc., | |
9 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | |
10 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | |
11 | * | |
12 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | |
13 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | |
14 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | |
15 | * this warranty disclaimer. | |
16 | */ | |
17 | #include <linux/device.h> | |
18 | #include <linux/spi/spi.h> | |
19 | #include <linux/gpio.h> | |
a9096fbc MM |
20 | #include <linux/mutex.h> |
21 | #include <linux/delay.h> | |
5e72bc8b MM |
22 | #include "esp_spi.h" |
23 | #include "esp_if.h" | |
24 | #include "esp_api.h" | |
25 | #include "esp_bt_api.h" | |
26 | #ifdef CONFIG_SUPPORT_ESP_SERIAL | |
27 | #include "esp_serial.h" | |
28 | #endif | |
29 | ||
30 | static struct sk_buff * read_packet(struct esp_adapter *adapter); | |
31 | static int write_packet(struct esp_adapter *adapter, u8 *buf, u32 size); | |
32 | static void spi_exit(void); | |
33 | ||
c746d295 MM |
34 | volatile u8 data_path = 0; |
35 | static struct esp_spi_context spi_context; | |
36 | ||
5e72bc8b MM |
37 | static struct esp_if_ops if_ops = { |
38 | .read = read_packet, | |
39 | .write = write_packet, | |
40 | }; | |
41 | ||
a9096fbc | 42 | static DEFINE_MUTEX(spi_lock); |
c746d295 MM |
43 | |
44 | static void open_data_path(void) | |
45 | { | |
46 | msleep(200); | |
47 | data_path = OPEN_DATAPATH; | |
48 | } | |
49 | ||
50 | static void close_data_path(void) | |
51 | { | |
52 | data_path = CLOSE_DATAPATH; | |
53 | msleep(200); | |
54 | } | |
5e72bc8b | 55 | |
a9096fbc MM |
56 | static irqreturn_t spi_data_ready_interrupt_handler(int irq, void * dev) |
57 | { | |
58 | /* ESP peripheral has queued buffer for transmission */ | |
59 | if (spi_context.spi_workqueue) | |
60 | queue_work(spi_context.spi_workqueue, &spi_context.spi_work); | |
61 | ||
62 | return IRQ_HANDLED; | |
63 | } | |
64 | ||
5e72bc8b MM |
65 | static irqreturn_t spi_interrupt_handler(int irq, void * dev) |
66 | { | |
a9096fbc | 67 | /* ESP peripheral is ready for next SPI transaction */ |
5e72bc8b MM |
68 | if (spi_context.spi_workqueue) |
69 | queue_work(spi_context.spi_workqueue, &spi_context.spi_work); | |
70 | ||
71 | return IRQ_HANDLED; | |
72 | } | |
73 | ||
74 | static struct sk_buff * read_packet(struct esp_adapter *adapter) | |
75 | { | |
76 | struct esp_spi_context *context; | |
77 | struct sk_buff *skb = NULL; | |
78 | ||
c746d295 MM |
79 | if (!data_path) { |
80 | return NULL; | |
81 | } | |
82 | ||
5e72bc8b MM |
83 | if (!adapter || !adapter->if_context) { |
84 | printk (KERN_ERR "%s: Invalid args\n", __func__); | |
85 | return NULL; | |
86 | } | |
87 | ||
88 | context = adapter->if_context; | |
89 | ||
90 | if (context->esp_spi_dev) { | |
91 | skb = skb_dequeue(&(context->rx_q)); | |
92 | } else { | |
93 | printk (KERN_ERR "%s: Invalid args\n", __func__); | |
94 | return NULL; | |
95 | } | |
96 | ||
97 | return skb; | |
98 | } | |
99 | ||
100 | static int write_packet(struct esp_adapter *adapter, u8 *buf, u32 size) | |
101 | { | |
102 | struct esp_spi_context *context; | |
103 | struct sk_buff *skb; | |
104 | u8 *tx_buf = NULL; | |
105 | ||
106 | if (!adapter || !adapter->if_context || !buf || !size || (size > SPI_BUF_SIZE)) { | |
107 | printk (KERN_ERR "%s: Invalid args\n", __func__); | |
108 | return -EINVAL; | |
109 | } | |
110 | ||
c746d295 MM |
111 | if (!data_path) { |
112 | return -EPERM; | |
113 | } | |
114 | ||
5e72bc8b MM |
115 | /* Adjust length to make it multiple of 4 bytes */ |
116 | size += 4 - (size & 3); | |
117 | ||
118 | context = adapter->if_context; | |
119 | ||
120 | skb = esp_alloc_skb(size); | |
121 | ||
122 | if (!skb) | |
123 | return -ENOMEM; | |
124 | ||
125 | tx_buf = skb_put(skb, size); | |
126 | ||
127 | if (!tx_buf) { | |
128 | dev_kfree_skb(skb); | |
129 | return -ENOMEM; | |
130 | } | |
131 | ||
132 | /* TODO: This memecpy can be avoided if this function receives SKB as an argument */ | |
133 | memcpy(tx_buf, buf, size); | |
134 | ||
135 | /* Enqueue SKB in tx_q */ | |
136 | skb_queue_tail(&spi_context.tx_q, skb); | |
137 | ||
a9096fbc MM |
138 | if (spi_context.spi_workqueue) |
139 | queue_work(spi_context.spi_workqueue, &spi_context.spi_work); | |
140 | ||
5e72bc8b MM |
141 | return 0; |
142 | } | |
143 | ||
062be972 MM |
144 | static void process_capabilities(u8 cap) |
145 | { | |
a9096fbc | 146 | printk (KERN_INFO "ESP32 capabilities: 0x%x\n", cap); |
062be972 MM |
147 | |
148 | /* Reset BT */ | |
149 | esp_deinit_bt(spi_context.adapter); | |
150 | ||
151 | if ((cap & ESP_BT_SPI_SUPPORT) || (cap & ESP_BT_SDIO_SUPPORT)) { | |
152 | msleep(200); | |
153 | esp_init_bt(spi_context.adapter); | |
154 | } | |
155 | } | |
156 | ||
157 | static void process_init_event(u8 *evt_buf, u8 len) | |
158 | { | |
159 | u8 len_left = len, tag_len; | |
160 | u8 *pos; | |
161 | ||
162 | if (!evt_buf) | |
163 | return; | |
164 | ||
165 | pos = evt_buf; | |
166 | ||
167 | while (len_left) { | |
168 | tag_len = *(pos + 1); | |
169 | if (*pos == ESP_PRIV_CAPABILITY) { | |
170 | process_capabilities(*(pos + 2)); | |
171 | } else { | |
172 | printk (KERN_WARNING "Unsupported tag in event"); | |
173 | } | |
174 | len_left = len_left - (tag_len + 2); | |
175 | } | |
176 | } | |
177 | ||
178 | static void process_event(u8 *evt_buf, u16 len) | |
179 | { | |
180 | struct esp_priv_event *event; | |
181 | ||
182 | if (!evt_buf || !len) | |
183 | return; | |
184 | ||
185 | event = (struct esp_priv_event *) evt_buf; | |
186 | ||
187 | if (event->event_type == ESP_PRIV_EVENT_INIT) { | |
188 | printk (KERN_INFO "Received INIT event from esp32"); | |
189 | process_init_event(event->event_data, event->event_len); | |
190 | } else { | |
191 | printk (KERN_WARNING "Drop unknown event"); | |
192 | } | |
193 | } | |
194 | ||
195 | static void process_priv_communication(struct sk_buff *skb) | |
196 | { | |
197 | struct esp_payload_header *header; | |
198 | u8 *payload; | |
199 | u16 len; | |
200 | ||
201 | if (!skb || !skb->data) | |
202 | return; | |
203 | ||
204 | header = (struct esp_payload_header *) skb->data; | |
205 | ||
206 | payload = skb->data + le16_to_cpu(header->offset); | |
207 | len = le16_to_cpu(header->len); | |
208 | ||
209 | if (header->priv_pkt_type == ESP_PACKET_TYPE_EVENT) { | |
210 | process_event(payload, len); | |
211 | } | |
212 | ||
213 | dev_kfree_skb(skb); | |
214 | } | |
215 | ||
5e72bc8b MM |
216 | static int process_rx_buf(struct sk_buff *skb) |
217 | { | |
218 | struct esp_payload_header *header; | |
219 | u16 len = 0; | |
220 | u16 offset = 0; | |
221 | ||
222 | if (!skb) | |
223 | return -EINVAL; | |
224 | ||
225 | header = (struct esp_payload_header *) skb->data; | |
226 | ||
a9096fbc MM |
227 | if (header->if_type >= ESP_MAX_IF) { |
228 | return -EINVAL; | |
229 | } | |
230 | ||
5e72bc8b MM |
231 | offset = le16_to_cpu(header->offset); |
232 | ||
233 | /* Validate received SKB. Check len and offset fields */ | |
a9096fbc | 234 | if (offset != sizeof(struct esp_payload_header)) { |
5e72bc8b | 235 | return -EINVAL; |
a9096fbc | 236 | } |
5e72bc8b MM |
237 | |
238 | len = le16_to_cpu(header->len); | |
a9096fbc | 239 | if (!len) { |
5e72bc8b | 240 | return -EINVAL; |
a9096fbc | 241 | } |
5e72bc8b MM |
242 | |
243 | len += sizeof(struct esp_payload_header); | |
244 | ||
a9096fbc | 245 | if (len > SPI_BUF_SIZE) { |
5e72bc8b | 246 | return -EINVAL; |
a9096fbc MM |
247 | } |
248 | ||
5e72bc8b MM |
249 | /* Trim SKB to actual size */ |
250 | skb_trim(skb, len); | |
251 | ||
062be972 MM |
252 | if (header->if_type == ESP_PRIV_IF) { |
253 | process_priv_communication(skb); | |
254 | return 0; | |
255 | } | |
256 | ||
257 | if (!data_path) | |
258 | return -EPERM; | |
259 | ||
5e72bc8b MM |
260 | /* enqueue skb for read_packet to pick it */ |
261 | skb_queue_tail(&spi_context.rx_q, skb); | |
262 | ||
263 | /* indicate reception of new packet */ | |
264 | esp_process_new_packet_intr(spi_context.adapter); | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | static void esp_spi_work(struct work_struct *work) | |
270 | { | |
271 | struct spi_transfer trans; | |
a9096fbc | 272 | struct sk_buff *tx_skb = NULL, *rx_skb = NULL; |
5e72bc8b MM |
273 | u8 *rx_buf; |
274 | int ret = 0; | |
a9096fbc | 275 | int trans_ready, rx_pending; |
5e72bc8b | 276 | |
a9096fbc | 277 | mutex_lock(&spi_lock); |
5e72bc8b | 278 | |
a9096fbc MM |
279 | trans_ready = gpio_get_value(HANDSHAKE_PIN); |
280 | rx_pending = gpio_get_value(SPI_DATA_READY_PIN); | |
5e72bc8b | 281 | |
5e72bc8b | 282 | |
a9096fbc MM |
283 | if (trans_ready) { |
284 | if (data_path) | |
285 | tx_skb = skb_dequeue(&spi_context.tx_q); | |
5e72bc8b | 286 | |
a9096fbc MM |
287 | if (rx_pending || tx_skb) { |
288 | memset(&trans, 0, sizeof(trans)); | |
5e72bc8b | 289 | |
a9096fbc MM |
290 | /* Setup and execute SPI transaction |
291 | * Tx_buf: Check if tx_q has valid buffer for transmission, | |
292 | * else keep it blank | |
293 | * | |
294 | * Rx_buf: Allocate memory for incoming data. This will be freed | |
295 | * immediately if received buffer is invalid. | |
296 | * If it is a valid buffer, upper layer will free it. | |
297 | * */ | |
5e72bc8b | 298 | |
a9096fbc | 299 | /* Configure TX buffer if available */ |
5e72bc8b | 300 | |
a9096fbc MM |
301 | if (tx_skb) { |
302 | trans.tx_buf = tx_skb->data; | |
303 | } else { | |
304 | tx_skb = esp_alloc_skb(SPI_BUF_SIZE); | |
305 | trans.tx_buf = skb_put(tx_skb, SPI_BUF_SIZE); | |
306 | } | |
5e72bc8b | 307 | |
a9096fbc MM |
308 | /* Configure RX buffer */ |
309 | rx_skb = esp_alloc_skb(SPI_BUF_SIZE); | |
310 | rx_buf = skb_put(rx_skb, SPI_BUF_SIZE); | |
311 | ||
312 | memset(rx_buf, 0, SPI_BUF_SIZE); | |
313 | ||
314 | trans.rx_buf = rx_buf; | |
315 | trans.len = SPI_BUF_SIZE; | |
316 | ||
317 | ret = spi_sync_transfer(spi_context.esp_spi_dev, &trans, 1); | |
318 | ||
319 | if (ret) { | |
320 | printk(KERN_ERR "SPI Transaction failed: %d", ret); | |
321 | dev_kfree_skb(rx_skb); | |
322 | dev_kfree_skb(tx_skb); | |
323 | } else { | |
324 | ||
325 | /* Free rx_skb if received data is not valid */ | |
326 | if (process_rx_buf(rx_skb)) { | |
327 | dev_kfree_skb(rx_skb); | |
328 | } | |
5e72bc8b | 329 | |
a9096fbc MM |
330 | if (tx_skb) |
331 | dev_kfree_skb(tx_skb); | |
332 | } | |
333 | } | |
5e72bc8b MM |
334 | } |
335 | ||
a9096fbc | 336 | mutex_unlock(&spi_lock); |
5e72bc8b MM |
337 | } |
338 | ||
339 | static int spi_init(void) | |
340 | { | |
341 | int status = 0; | |
342 | struct spi_board_info esp_board = {{0}}; | |
343 | struct spi_master *master = NULL; | |
344 | ||
345 | strlcpy(esp_board.modalias, "esp_spi", sizeof(esp_board.modalias)); | |
a9096fbc | 346 | esp_board.mode = SPI_MODE_2; |
5e72bc8b | 347 | /* 10MHz */ |
a9096fbc | 348 | esp_board.max_speed_hz = 10000000; |
5e72bc8b MM |
349 | esp_board.bus_num = 0; |
350 | esp_board.chip_select = 0; | |
351 | ||
352 | spi_context.spi_workqueue = create_workqueue("ESP_SPI_WORK_QUEUE"); | |
353 | ||
354 | if (!spi_context.spi_workqueue) { | |
355 | spi_exit(); | |
356 | return -EFAULT; | |
357 | } | |
358 | ||
359 | INIT_WORK(&spi_context.spi_work, esp_spi_work); | |
360 | ||
361 | skb_queue_head_init(&spi_context.tx_q); | |
362 | skb_queue_head_init(&spi_context.rx_q); | |
363 | ||
364 | master = spi_busnum_to_master(esp_board.bus_num); | |
365 | ||
366 | if (!master) { | |
367 | printk(KERN_ERR "Failed to obtain SPI master handle\n"); | |
368 | spi_exit(); | |
369 | return -ENODEV; | |
370 | } | |
371 | ||
372 | spi_context.esp_spi_dev = spi_new_device(master, &esp_board); | |
373 | ||
374 | if (!spi_context.esp_spi_dev) { | |
375 | printk(KERN_ERR "Failed to add new SPI device\n"); | |
376 | spi_exit(); | |
377 | return -ENODEV; | |
378 | } | |
379 | ||
380 | status = spi_setup(spi_context.esp_spi_dev); | |
381 | ||
382 | if (status) { | |
383 | printk (KERN_ERR "Failed to setup new SPI device"); | |
384 | spi_exit(); | |
385 | return status; | |
386 | } | |
387 | ||
388 | printk (KERN_INFO "ESP32 device is registered to SPI bus [%d]" | |
389 | ",chip select [%d]\n", esp_board.bus_num, | |
390 | esp_board.chip_select); | |
391 | ||
392 | status = gpio_request(HANDSHAKE_PIN, "SPI_HANDSHAKE_PIN"); | |
393 | ||
394 | if (status) { | |
395 | printk (KERN_ERR "Failed to obtain GPIO"); | |
396 | spi_exit(); | |
397 | return status; | |
398 | } | |
399 | ||
400 | status = gpio_direction_input(HANDSHAKE_PIN); | |
401 | ||
402 | if (status) { | |
403 | printk (KERN_ERR "Failed to set GPIO direction"); | |
404 | spi_exit(); | |
405 | return status; | |
406 | } | |
407 | ||
408 | status = request_irq(SPI_IRQ, spi_interrupt_handler, | |
409 | IRQF_SHARED | IRQF_TRIGGER_RISING, | |
410 | "ESP_SPI", spi_context.esp_spi_dev); | |
411 | if (status) { | |
412 | printk (KERN_ERR "Failed to request IRQ"); | |
413 | spi_exit(); | |
414 | return status; | |
415 | } | |
416 | ||
a9096fbc MM |
417 | status = gpio_request(SPI_DATA_READY_PIN, "SPI_DATA_READY_PIN"); |
418 | if (status) { | |
419 | printk (KERN_ERR "Failed to obtain GPIO"); | |
420 | spi_exit(); | |
421 | return status; | |
422 | } | |
423 | ||
424 | status = gpio_direction_input(SPI_DATA_READY_PIN); | |
425 | if (status) { | |
426 | printk (KERN_ERR "Failed to set GPIO direction"); | |
427 | spi_exit(); | |
428 | return status; | |
429 | } | |
430 | ||
431 | status = request_irq(SPI_DATA_READY_IRQ, spi_data_ready_interrupt_handler, | |
432 | IRQF_SHARED | IRQF_TRIGGER_RISING, | |
433 | "ESP_SPI_DATA_READY", spi_context.esp_spi_dev); | |
434 | if (status) { | |
435 | printk (KERN_ERR "Failed to request IRQ"); | |
436 | spi_exit(); | |
437 | return status; | |
438 | } | |
439 | ||
c746d295 | 440 | open_data_path(); |
5e72bc8b MM |
441 | |
442 | #ifdef CONFIG_SUPPORT_ESP_SERIAL | |
443 | status = esp_serial_init((void *) spi_context.adapter); | |
444 | if (status != 0) { | |
445 | spi_exit(); | |
446 | printk(KERN_ERR "Error initialising serial interface\n"); | |
447 | return status; | |
448 | } | |
449 | #endif | |
450 | ||
451 | status = esp_add_card(spi_context.adapter); | |
452 | if (status) { | |
453 | spi_exit(); | |
454 | printk (KERN_ERR "Failed to add card\n"); | |
455 | return status; | |
456 | } | |
457 | ||
5e72bc8b MM |
458 | msleep(200); |
459 | ||
460 | return status; | |
461 | } | |
462 | ||
463 | static void spi_exit(void) | |
464 | { | |
c746d295 | 465 | disable_irq(SPI_IRQ); |
a9096fbc | 466 | disable_irq(SPI_DATA_READY_IRQ); |
c746d295 MM |
467 | close_data_path(); |
468 | msleep(200); | |
469 | ||
470 | skb_queue_purge(&spi_context.tx_q); | |
471 | skb_queue_purge(&spi_context.rx_q); | |
472 | ||
5e72bc8b MM |
473 | if (spi_context.spi_workqueue) { |
474 | destroy_workqueue(spi_context.spi_workqueue); | |
c746d295 | 475 | spi_context.spi_workqueue = NULL; |
5e72bc8b MM |
476 | } |
477 | ||
478 | esp_serial_cleanup(); | |
479 | esp_remove_card(spi_context.adapter); | |
480 | ||
481 | if (spi_context.adapter->hcidev) | |
482 | esp_deinit_bt(spi_context.adapter); | |
483 | ||
c746d295 | 484 | free_irq(SPI_IRQ, spi_context.esp_spi_dev); |
a9096fbc | 485 | free_irq(SPI_DATA_READY_IRQ, spi_context.esp_spi_dev); |
c746d295 | 486 | |
5e72bc8b | 487 | gpio_free(HANDSHAKE_PIN); |
a9096fbc | 488 | gpio_free(SPI_DATA_READY_PIN); |
5e72bc8b MM |
489 | |
490 | if (spi_context.esp_spi_dev) | |
491 | spi_unregister_device(spi_context.esp_spi_dev); | |
492 | ||
493 | memset(&spi_context, 0, sizeof(spi_context)); | |
494 | } | |
495 | ||
496 | int esp_init_interface_layer(struct esp_adapter *adapter) | |
497 | { | |
498 | if (!adapter) | |
499 | return -EINVAL; | |
500 | ||
501 | memset(&spi_context, 0, sizeof(spi_context)); | |
502 | ||
503 | adapter->if_context = &spi_context; | |
504 | adapter->if_ops = &if_ops; | |
062be972 | 505 | adapter->if_type = ESP_IF_TYPE_SPI; |
5e72bc8b MM |
506 | spi_context.adapter = adapter; |
507 | ||
508 | return spi_init(); | |
509 | } | |
510 | ||
511 | void esp_deinit_interface_layer(void) | |
512 | { | |
513 | spi_exit(); | |
514 | } |