blob: b8e3b841a8f76a101416691aef321617d2fd18c7 [file] [log] [blame]
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(msg) "bgcom: %s: " msg, __func__
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/delay.h>
20#include <linux/spi/spi.h>
21#include <linux/ratelimit.h>
22#include <linux/interrupt.h>
23#include <linux/device.h>
24#include <linux/bitops.h>
25#include <linux/gpio.h>
26#include <linux/of_gpio.h>
27#include <linux/kthread.h>
28#include "bgcom.h"
29#include "bgrsb.h"
30#include "bgcom_interface.h"
31
32#define BG_SPI_WORD_SIZE (0x04)
33#define BG_SPI_READ_LEN (0x04)
34#define BG_SPI_WRITE_CMND_LEN (0x01)
35#define BG_SPI_FIFO_READ_CMD (0x41)
36#define BG_SPI_FIFO_WRITE_CMD (0x40)
37#define BG_SPI_AHB_READ_CMD (0x43)
38#define BG_SPI_AHB_WRITE_CMD (0x42)
39#define BG_SPI_AHB_CMD_LEN (0x05)
40#define BG_SPI_AHB_READ_CMD_LEN (0x08)
41#define BG_STATUS_REG (0x05)
42#define BG_CMND_REG (0x14)
43
44#define BG_SPI_MAX_WORDS (0x3FFFFFFD)
45#define BG_SPI_MAX_REGS (0x0A)
46#define SLEEP_IN_STATE_CHNG 2000
47#define HED_EVENT_ID_LEN (0x02)
48#define HED_EVENT_SIZE_LEN (0x02)
49#define HED_EVENT_DATA_STRT_LEN (0x05)
50
51#define MAX_RETRY 200
52
53enum bgcom_state {
54 /*BGCOM Staus ready*/
55 BGCOM_PROB_SUCCESS = 0,
56 BGCOM_PROB_WAIT = 1,
57 BGCOM_STATE_SUSPEND = 2,
58 BGCOM_STATE_ACTIVE = 3
59};
60
61enum bgcom_req_type {
62 /*BGCOM local requests*/
63 BGCOM_READ_REG = 0,
64 BGCOM_READ_FIFO = 1,
65 BGCOM_READ_AHB = 2,
66};
67
68struct bg_spi_priv {
69 struct spi_device *spi;
70 /* Transaction related */
71 struct mutex xfer_mutex;
72 void *lhandle;
73 /* Message for single transfer */
74 struct spi_message msg1;
75 struct spi_transfer xfer1;
76 int irq_lock;
77
78 enum bgcom_state bg_state;
79};
80
81struct cb_data {
82 void *priv;
83 void *handle;
84 void (*bgcom_notification_cb)(void *handle, void *priv,
85 enum bgcom_event_type event,
86 union bgcom_event_data_type *event_data);
87 struct list_head list;
88};
89
90struct bg_context {
91 struct bg_spi_priv *bg_spi;
92 enum bgcom_state state;
93 struct cb_data *cb;
94};
95
96struct event_list {
97 struct event *evnt;
98 struct list_head list;
99};
100static void *bg_com_drv;
101static uint32_t g_slav_status_reg;
102
103/* BGCOM client callbacks set-up */
104static void send_input_events(struct work_struct *work);
105static struct list_head cb_head = LIST_HEAD_INIT(cb_head);
106static struct list_head pr_lst_hd = LIST_HEAD_INIT(pr_lst_hd);
107static enum bgcom_spi_state spi_state;
108
109
110static struct workqueue_struct *wq;
111static DECLARE_WORK(input_work, send_input_events);
112
113static struct mutex bg_resume_mutex;
114
115static void augmnt_fifo(uint8_t *data, int pos)
116{
117 data[pos] = '\0';
118}
119
120static void send_input_events(struct work_struct *work)
121{
122 struct list_head *temp;
123 struct list_head *pos;
124 struct event_list *node;
125 struct event *evnt;
126
127 if (list_empty(&pr_lst_hd))
128 return;
129
130 list_for_each_safe(pos, temp, &pr_lst_hd) {
131 node = list_entry(pos, struct event_list, list);
132 evnt = node->evnt;
133 bgrsb_send_input(evnt);
134 kfree(evnt);
135 list_del(&node->list);
136 kfree(node);
137 }
138}
139
140int bgcom_set_spi_state(enum bgcom_spi_state state)
141{
142 struct bg_spi_priv *bg_spi = container_of(bg_com_drv,
143 struct bg_spi_priv, lhandle);
144 if (state < 0 || state > 1)
145 return -EINVAL;
146
147 if (state == spi_state)
148 return 0;
149
150 mutex_lock(&bg_spi->xfer_mutex);
151 spi_state = state;
152 if (spi_state == BGCOM_SPI_BUSY)
153 msleep(SLEEP_IN_STATE_CHNG);
154 mutex_unlock(&bg_spi->xfer_mutex);
155 return 0;
156}
157EXPORT_SYMBOL(bgcom_set_spi_state);
158
159static inline
160void add_to_irq_list(struct cb_data *data)
161{
162 list_add_tail(&data->list, &cb_head);
163}
164
165static bool is_bgcom_ready(void)
166{
167 return (bg_com_drv != NULL ? true : false);
168}
169
170static void bg_spi_reinit_xfer(struct spi_transfer *xfer)
171{
172 xfer->tx_buf = NULL;
173 xfer->rx_buf = NULL;
174 xfer->delay_usecs = 0;
175 xfer->len = 0;
176}
177
178static int read_bg_locl(enum bgcom_req_type req_type,
179 uint32_t no_of_words, void *buf)
180{
181
182 struct bg_context clnt_handle;
183 struct bg_spi_priv *spi =
184 container_of(bg_com_drv, struct bg_spi_priv, lhandle);
185 int ret = 0;
186
187 if (!buf)
188 return -EINVAL;
189
190 clnt_handle.bg_spi = spi;
191
192 switch (req_type) {
193 case BGCOM_READ_REG:
194 ret = bgcom_reg_read(&clnt_handle,
195 BG_STATUS_REG, no_of_words, buf);
196 break;
197 case BGCOM_READ_FIFO:
198 ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf);
199 break;
200 case BGCOM_READ_AHB:
201 break;
202 }
203 return ret;
204}
205
206static int bgcom_transfer(void *handle, uint8_t *tx_buf,
207 uint8_t *rx_buf, uint32_t txn_len)
208{
209 struct spi_transfer *tx_xfer;
210 struct bg_spi_priv *bg_spi;
211 struct bg_context *cntx;
212 struct spi_device *spi;
213 int ret;
214
215 if (!handle || !tx_buf)
216 return -EINVAL;
217
218 cntx = (struct bg_context *)handle;
219
220 if (cntx->state == BGCOM_PROB_WAIT) {
221 if (!is_bgcom_ready())
222 return -ENODEV;
223 cntx->bg_spi = container_of(bg_com_drv,
224 struct bg_spi_priv, lhandle);
225 cntx->state = BGCOM_PROB_SUCCESS;
226 }
227 bg_spi = cntx->bg_spi;
228
229 if (!bg_spi)
230 return -ENODEV;
231
232 tx_xfer = &bg_spi->xfer1;
233 spi = bg_spi->spi;
234
235 mutex_lock(&bg_spi->xfer_mutex);
236 bg_spi_reinit_xfer(tx_xfer);
237 tx_xfer->tx_buf = tx_buf;
238 if (rx_buf)
239 tx_xfer->rx_buf = rx_buf;
240
241 tx_xfer->len = txn_len;
242 ret = spi_sync(spi, &bg_spi->msg1);
243 mutex_unlock(&bg_spi->xfer_mutex);
244
245 if (ret)
246 pr_err("SPI transaction failed: %d\n", ret);
247 return ret;
248}
249
250/* BG-COM Interrupt handling */
251static inline
252void send_event(enum bgcom_event_type event,
253 void *data)
254{
255 struct list_head *pos;
256 struct cb_data *cb;
257
258 /* send interrupt notification for each
259 * registered call-back
260 */
261 list_for_each(pos, &cb_head) {
262 cb = list_entry(pos, struct cb_data, list);
263 cb->bgcom_notification_cb(cb->handle,
264 cb->priv, event, data);
265 }
266}
267
268void bgcom_bgdown_handler(void)
269{
270 send_event(BGCOM_EVENT_RESET_OCCURRED, NULL);
271 g_slav_status_reg = 0;
272}
273EXPORT_SYMBOL(bgcom_bgdown_handler);
274
275static void parse_fifo(uint8_t *data, union bgcom_event_data_type *event_data)
276{
277 uint16_t p_len;
278 uint8_t sub_id;
279 uint32_t evnt_tm;
280 uint16_t event_id;
281 void *evnt_data;
282 struct event *evnt;
283 struct event_list *data_list;
284
285 while (*data != '\0') {
286
287 event_id = *((uint16_t *) data);
288 data = data + HED_EVENT_ID_LEN;
289 p_len = *((uint16_t *) data);
290 data = data + HED_EVENT_SIZE_LEN;
291
292 if (event_id == 0xFFFE) {
293
294 sub_id = *data;
295 evnt_tm = *((uint32_t *)(data+1));
296
297 evnt = kmalloc(sizeof(*evnt), GFP_KERNEL);
298 evnt->sub_id = sub_id;
299 evnt->evnt_tm = evnt_tm;
300 evnt->evnt_data =
301 *(int16_t *)(data + HED_EVENT_DATA_STRT_LEN);
302
303 data_list = kmalloc(sizeof(*data_list), GFP_KERNEL);
304 data_list->evnt = evnt;
305 list_add_tail(&data_list->list, &pr_lst_hd);
306
307 } else if (event_id == 0x0001) {
308 evnt_data = kmalloc(p_len, GFP_KERNEL);
309 if (evnt_data != NULL) {
310 memcpy(evnt_data, data, p_len);
311 event_data->fifo_data.to_master_fifo_used =
312 p_len/BG_SPI_WORD_SIZE;
313 event_data->fifo_data.data = evnt_data;
314 send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED,
315 event_data);
316 }
317 }
318 data = data + p_len;
319 }
320 if (!list_empty(&pr_lst_hd))
321 queue_work(wq, &input_work);
322}
323
324static void send_back_notification(uint32_t slav_status_reg,
325 uint32_t slav_status_auto_clear_reg,
326 uint32_t fifo_fill_reg, uint32_t fifo_size_reg)
327{
328 uint16_t master_fifo_used;
329 uint16_t slave_fifo_free;
330 uint32_t *ptr;
331 int ret;
332 union bgcom_event_data_type event_data = { .fifo_data = {0} };
333
334 master_fifo_used = (uint16_t)fifo_fill_reg;
335 slave_fifo_free = (uint16_t)(fifo_fill_reg >> 16);
336
337 if (slav_status_auto_clear_reg & BIT(31))
338 send_event(BGCOM_EVENT_RESET_OCCURRED, NULL);
339
340 if (slav_status_auto_clear_reg & BIT(30))
341 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL);
342
343 if (slav_status_auto_clear_reg & BIT(29))
344 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL);
345
346 if (slav_status_auto_clear_reg & BIT(28))
347 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL);
348
349 if (slav_status_auto_clear_reg & BIT(27))
350 send_event(BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL);
351
352 if (slav_status_auto_clear_reg & BIT(26))
353 send_event(BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL);
354
355 if (slav_status_auto_clear_reg & BIT(25))
356 send_event(BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL);
357
358 if (slav_status_auto_clear_reg & BIT(24))
359 send_event(BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL);
360
361 if (slav_status_auto_clear_reg & BIT(23))
362 send_event(BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL);
363
364 if (slav_status_auto_clear_reg & BIT(22))
365 send_event(BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL);
366
367 if (slav_status_auto_clear_reg & BIT(21))
368 send_event(BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL);
369
370 /* check if BG status is changed */
371 if (g_slav_status_reg ^ slav_status_reg) {
372 if (slav_status_reg & BIT(30)) {
373 event_data.application_running = true;
374 send_event(BGCOM_EVENT_APPLICATION_RUNNING,
375 &event_data);
376 }
377
378 if (slav_status_reg & BIT(29)) {
379 event_data.to_slave_fifo_ready = true;
380 send_event(BGCOM_EVENT_TO_SLAVE_FIFO_READY,
381 &event_data);
382 }
383
384 if (slav_status_reg & BIT(28)) {
385 event_data.to_master_fifo_ready = true;
386 send_event(BGCOM_EVENT_TO_MASTER_FIFO_READY,
387 &event_data);
388 }
389
390 if (slav_status_reg & BIT(27)) {
391 event_data.ahb_ready = true;
392 send_event(BGCOM_EVENT_AHB_READY,
393 &event_data);
394 }
395 }
396
397 if (master_fifo_used > 0) {
398 ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE + 1,
399 GFP_KERNEL | GFP_ATOMIC);
400 if (ptr != NULL) {
401 ret = read_bg_locl(BGCOM_READ_FIFO,
402 master_fifo_used, ptr);
403 if (!ret) {
404 augmnt_fifo((uint8_t *)ptr,
405 master_fifo_used*BG_SPI_WORD_SIZE);
406 parse_fifo((uint8_t *)ptr, &event_data);
407 }
408 kfree(ptr);
409 }
410 }
411
412 event_data.to_slave_fifo_free = slave_fifo_free;
413 send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data);
414}
415
416static void bg_irq_tasklet_hndlr_l(void)
417{
418 uint32_t slave_status_reg;
419 uint32_t glink_isr_reg;
420 uint32_t slav_status_auto_clear_reg;
421 uint32_t fifo_fill_reg;
422 uint32_t fifo_size_reg;
423 int ret = 0;
424 uint32_t irq_buf[5] = {0};
425
426 ret = read_bg_locl(BGCOM_READ_REG, 5, &irq_buf[0]);
427 if (ret)
428 return;
429
430 /* save current state */
431 slave_status_reg = irq_buf[0];
432 glink_isr_reg = irq_buf[1];
433 slav_status_auto_clear_reg = irq_buf[2];
434 fifo_fill_reg = irq_buf[3];
435 fifo_size_reg = irq_buf[4];
436
437 send_back_notification(slave_status_reg,
438 slav_status_auto_clear_reg, fifo_fill_reg, fifo_size_reg);
439
440 g_slav_status_reg = slave_status_reg;
441}
442
443int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr,
444 uint32_t num_words, void *read_buf)
445{
446 uint32_t txn_len;
447 uint8_t *tx_buf;
448 uint8_t *rx_buf;
449 uint32_t size;
450 int ret;
451 uint8_t cmnd = 0;
452 uint32_t ahb_addr = 0;
453
454 if (!handle || !read_buf || num_words == 0
455 || num_words > BG_SPI_MAX_WORDS) {
456 pr_err("Invalid param\n");
457 return -EINVAL;
458 }
459 if (!is_bgcom_ready())
460 return -ENODEV;
461
462 if (spi_state == BGCOM_SPI_BUSY) {
463 pr_err("Device busy\n");
464 return -EBUSY;
465 }
466
467 if (bgcom_resume(handle)) {
468 pr_err("Failed to resume\n");
469 return -EBUSY;
470 }
471
472 size = num_words*BG_SPI_WORD_SIZE;
473 txn_len = BG_SPI_AHB_READ_CMD_LEN + size;
474
475 tx_buf = kzalloc(txn_len, GFP_KERNEL);
476
477 if (!tx_buf)
478 return -ENOMEM;
479
480 rx_buf = kzalloc(txn_len, GFP_KERNEL);
481
482 if (!rx_buf) {
483 kfree(tx_buf);
484 return -ENOMEM;
485 }
486
487 cmnd |= BG_SPI_AHB_READ_CMD;
488 ahb_addr |= ahb_start_addr;
489
490 memcpy(tx_buf, &cmnd, sizeof(cmnd));
491 memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr));
492
493 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
494
495 if (!ret)
496 memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size);
497
498 kfree(tx_buf);
499 kfree(rx_buf);
500 return ret;
501}
502EXPORT_SYMBOL(bgcom_ahb_read);
503
504int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr,
505 uint32_t num_words, void *write_buf)
506{
507 uint32_t txn_len;
508 uint8_t *tx_buf;
509 uint32_t size;
510 int ret;
511 uint8_t cmnd = 0;
512 uint32_t ahb_addr = 0;
513
514 if (!handle || !write_buf || num_words == 0
515 || num_words > BG_SPI_MAX_WORDS) {
516 pr_err("Invalid param\n");
517 return -EINVAL;
518 }
519
520 if (!is_bgcom_ready())
521 return -ENODEV;
522
523 if (spi_state == BGCOM_SPI_BUSY) {
524 pr_err("Device busy\n");
525 return -EBUSY;
526 }
527
528 if (bgcom_resume(handle)) {
529 pr_err("Failed to resume\n");
530 return -EBUSY;
531 }
532
533 size = num_words*BG_SPI_WORD_SIZE;
534 txn_len = BG_SPI_AHB_CMD_LEN + size;
535
536 tx_buf = kzalloc(txn_len, GFP_KERNEL);
537
538 if (!tx_buf)
539 return -ENOMEM;
540
541 cmnd |= BG_SPI_AHB_WRITE_CMD;
542 ahb_addr |= ahb_start_addr;
543
544 memcpy(tx_buf, &cmnd, sizeof(cmnd));
545 memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr));
546 memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size);
547
548 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
549 kfree(tx_buf);
550 return ret;
551}
552EXPORT_SYMBOL(bgcom_ahb_write);
553
554int bgcom_fifo_write(void *handle, uint32_t num_words,
555 void *write_buf)
556{
557 uint32_t txn_len;
558 uint8_t *tx_buf;
559 uint32_t size;
560 int ret;
561 uint8_t cmnd = 0;
562
563 if (!handle || !write_buf || num_words == 0
564 || num_words > BG_SPI_MAX_WORDS) {
565 pr_err("Invalid param\n");
566 return -EINVAL;
567 }
568
569 if (!is_bgcom_ready())
570 return -ENODEV;
571
572 if (spi_state == BGCOM_SPI_BUSY) {
573 pr_err("Device busy\n");
574 return -EBUSY;
575 }
576
577 if (bgcom_resume(handle)) {
578 pr_err("Failed to resume\n");
579 return -EBUSY;
580 }
581
582 size = num_words*BG_SPI_WORD_SIZE;
583 txn_len = BG_SPI_WRITE_CMND_LEN + size;
584
585 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
586
587 if (!tx_buf)
588 return -ENOMEM;
589
590 cmnd |= BG_SPI_FIFO_WRITE_CMD;
591 memcpy(tx_buf, &cmnd, sizeof(cmnd));
592 memcpy(tx_buf+sizeof(cmnd), write_buf, size);
593
594 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
595 kfree(tx_buf);
596 return ret;
597}
598EXPORT_SYMBOL(bgcom_fifo_write);
599
600int bgcom_fifo_read(void *handle, uint32_t num_words,
601 void *read_buf)
602{
603 uint32_t txn_len;
604 uint8_t *tx_buf;
605 uint8_t *rx_buf;
606 uint32_t size;
607 uint8_t cmnd = 0;
608 int ret = 0;
609
610 if (!handle || !read_buf || num_words == 0
611 || num_words > BG_SPI_MAX_WORDS) {
612 pr_err("Invalid param\n");
613 return -EINVAL;
614 }
615
616 if (!is_bgcom_ready())
617 return -ENODEV;
618
619 if (spi_state == BGCOM_SPI_BUSY) {
620 pr_err("Device busy\n");
621 return -EBUSY;
622 }
623
624 size = num_words*BG_SPI_WORD_SIZE;
625 txn_len = BG_SPI_READ_LEN + size;
626 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
627
628 if (!tx_buf)
629 return -ENOMEM;
630
631 rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
632
633 if (!rx_buf) {
634 kfree(tx_buf);
635 return -ENOMEM;
636 }
637
638 cmnd |= BG_SPI_FIFO_READ_CMD;
639 memcpy(tx_buf, &cmnd, sizeof(cmnd));
640
641 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
642
643 if (!ret)
644 memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size);
645 kfree(tx_buf);
646 kfree(rx_buf);
647 return ret;
648}
649EXPORT_SYMBOL(bgcom_fifo_read);
650
651int bgcom_reg_write(void *handle, uint8_t reg_start_addr,
652 uint8_t num_regs, void *write_buf)
653{
654 uint32_t txn_len;
655 uint8_t *tx_buf;
656 uint32_t size;
657 uint8_t cmnd = 0;
658 int ret = 0;
659
660 if (!handle || !write_buf || num_regs == 0
661 || num_regs > BG_SPI_MAX_REGS) {
662 pr_err("Invalid param\n");
663 return -EINVAL;
664 }
665
666 if (!is_bgcom_ready())
667 return -ENODEV;
668
669 if (spi_state == BGCOM_SPI_BUSY) {
670 pr_err("Device busy\n");
671 return -EBUSY;
672 }
673
674 size = num_regs*BG_SPI_WORD_SIZE;
675 txn_len = BG_SPI_WRITE_CMND_LEN + size;
676
677 tx_buf = kzalloc(txn_len, GFP_KERNEL);
678
679 if (!tx_buf)
680 return -ENOMEM;
681
682 cmnd |= reg_start_addr;
683 memcpy(tx_buf, &cmnd, sizeof(cmnd));
684 memcpy(tx_buf+sizeof(cmnd), write_buf, size);
685
686 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
687 kfree(tx_buf);
688 return ret;
689}
690EXPORT_SYMBOL(bgcom_reg_write);
691
692int bgcom_reg_read(void *handle, uint8_t reg_start_addr,
693 uint32_t num_regs, void *read_buf)
694{
695 uint32_t txn_len;
696 uint8_t *tx_buf;
697 uint8_t *rx_buf;
698 uint32_t size;
699 int ret;
700 uint8_t cmnd = 0;
701
702 if (!handle || !read_buf || num_regs == 0
703 || num_regs > BG_SPI_MAX_REGS) {
704 pr_err("Invalid param\n");
705 return -EINVAL;
706 }
707
708 if (!is_bgcom_ready())
709 return -ENODEV;
710
711 if (spi_state == BGCOM_SPI_BUSY) {
712 pr_err("Device busy\n");
713 return -EBUSY;
714 }
715
716 size = num_regs*BG_SPI_WORD_SIZE;
717 txn_len = BG_SPI_READ_LEN + size;
718
719 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
720
721 if (!tx_buf)
722 return -ENOMEM;
723
724 rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
725
726 if (!rx_buf) {
727 kfree(tx_buf);
728 return -ENOMEM;
729 }
730
731 cmnd |= reg_start_addr;
732 memcpy(tx_buf, &cmnd, sizeof(cmnd));
733
734 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
735
736 if (!ret)
737 memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size);
738 kfree(tx_buf);
739 kfree(rx_buf);
740 return ret;
741}
742EXPORT_SYMBOL(bgcom_reg_read);
743
744static int is_bg_resume(void *handle)
745{
746 uint32_t txn_len;
747 int ret;
748 uint8_t tx_buf[8] = {0};
749 uint8_t rx_buf[8] = {0};
750 uint32_t cmnd_reg = 0;
751
752 txn_len = 0x08;
753 tx_buf[0] = 0x05;
754 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
755 if (!ret)
756 memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04);
757 return cmnd_reg & BIT(31);
758}
759
760int bgcom_resume(void *handle)
761{
762 struct bg_spi_priv *bg_spi;
763 struct bg_context *cntx;
764 int retry = 0;
765
766 if (handle == NULL)
767 return -EINVAL;
768
769 cntx = (struct bg_context *)handle;
770 bg_spi = cntx->bg_spi;
771
772 mutex_lock(&bg_resume_mutex);
773 if (bg_spi->bg_state == BGCOM_STATE_ACTIVE)
774 goto unlock;
775 do {
776 if (is_bg_resume(handle)) {
777 bg_spi->bg_state = BGCOM_STATE_ACTIVE;
778 break;
779 }
780 udelay(10);
781 ++retry;
782 } while (retry < MAX_RETRY);
783
784unlock:
785 mutex_unlock(&bg_resume_mutex);
786 if (retry == MAX_RETRY) {
787 /* BG failed to resume. Trigger BG soft reset. */
788 pr_err("BG failed to resume\n");
789 bg_soft_reset();
790 return -ETIMEDOUT;
791 }
792 pr_info("BG retries for wake up : %d\n", retry);
793 return 0;
794}
795EXPORT_SYMBOL(bgcom_resume);
796
797int bgcom_suspend(void *handle)
798{
799 struct bg_spi_priv *bg_spi;
800 struct bg_context *cntx;
801 uint32_t cmnd_reg = 0;
802 int ret = 0;
803
804 if (handle == NULL)
805 return -EINVAL;
806
807 cntx = (struct bg_context *)handle;
808 bg_spi = cntx->bg_spi;
809 mutex_lock(&bg_resume_mutex);
810 if (bg_spi->bg_state == BGCOM_STATE_SUSPEND)
811 goto unlock;
812
813 cmnd_reg |= BIT(31);
814 ret = bgcom_reg_write(handle, BG_CMND_REG, 1, &cmnd_reg);
815 if (ret == 0)
816 bg_spi->bg_state = BGCOM_STATE_SUSPEND;
817
818unlock:
819 mutex_unlock(&bg_resume_mutex);
820 pr_info("suspended with : %d\n", ret);
821 return ret;
822}
823EXPORT_SYMBOL(bgcom_suspend);
824
825void *bgcom_open(struct bgcom_open_config_type *open_config)
826{
827 struct bg_spi_priv *spi;
828 struct cb_data *irq_notification;
829 struct bg_context *clnt_handle =
830 kzalloc(sizeof(*clnt_handle), GFP_KERNEL);
831
832 if (!clnt_handle)
833 return NULL;
834
835 /* Client handle Set-up */
836 if (!is_bgcom_ready()) {
837 clnt_handle->bg_spi = NULL;
838 clnt_handle->state = BGCOM_PROB_WAIT;
839 } else {
840 spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle);
841 clnt_handle->bg_spi = spi;
842 clnt_handle->state = BGCOM_PROB_SUCCESS;
843 }
844 clnt_handle->cb = NULL;
845 /* Interrupt callback Set-up */
846 if (open_config && open_config->bgcom_notification_cb) {
847 irq_notification = kzalloc(sizeof(*irq_notification),
848 GFP_KERNEL);
849 if (!irq_notification)
850 goto error_ret;
851
852 /* set irq node */
853 irq_notification->handle = clnt_handle;
854 irq_notification->priv = open_config->priv;
855 irq_notification->bgcom_notification_cb =
856 open_config->bgcom_notification_cb;
857 add_to_irq_list(irq_notification);
858 clnt_handle->cb = irq_notification;
859 }
860 return clnt_handle;
861
862error_ret:
863 kfree(clnt_handle);
864 return NULL;
865}
866EXPORT_SYMBOL(bgcom_open);
867
868int bgcom_close(void **handle)
869{
870 struct bg_context *lhandle;
871 struct cb_data *cb = NULL;
872
873 if (*handle == NULL)
874 return -EINVAL;
875 lhandle = *handle;
876 cb = lhandle->cb;
877 if (cb)
878 list_del(&cb->list);
879
880 kfree(*handle);
881 *handle = NULL;
882 return 0;
883}
884EXPORT_SYMBOL(bgcom_close);
885
886static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device)
887{
888 struct bg_spi_priv *bg_spi = device;
889 /* check if call-back exists */
890 if (list_empty(&cb_head)) {
891 pr_debug("No callback registered\n");
892 return IRQ_HANDLED;
893 } else if (spi_state == BGCOM_SPI_BUSY) {
894 return IRQ_HANDLED;
895 } else if (!bg_spi->irq_lock) {
896 bg_spi->irq_lock = 1;
897 bg_irq_tasklet_hndlr_l();
898 bg_spi->irq_lock = 0;
899 }
900 return IRQ_HANDLED;
901}
902
903static void bg_spi_init(struct bg_spi_priv *bg_spi)
904{
905 if (!bg_spi) {
906 pr_err("device not found\n");
907 return;
908 }
909
910 /* BGCOM SPI set-up */
911 mutex_init(&bg_spi->xfer_mutex);
912 spi_message_init(&bg_spi->msg1);
913 spi_message_add_tail(&bg_spi->xfer1, &bg_spi->msg1);
914
915 /* BGCOM IRQ set-up */
916 bg_spi->irq_lock = 0;
917
918 spi_state = BGCOM_SPI_FREE;
919
920 wq = create_singlethread_workqueue("input_wq");
921
922 bg_spi->bg_state = BGCOM_STATE_ACTIVE;
923
924 bg_com_drv = &bg_spi->lhandle;
925
926 mutex_init(&bg_resume_mutex);
927}
928
929static int bg_spi_probe(struct spi_device *spi)
930{
931 struct bg_spi_priv *bg_spi;
932 struct device_node *node;
933 int irq_gpio = 0;
934 int bg_irq = 0;
935 int ret;
936
937 bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi),
938 GFP_KERNEL | GFP_ATOMIC);
939 if (!bg_spi)
940 return -ENOMEM;
941 bg_spi->spi = spi;
942 spi_set_drvdata(spi, bg_spi);
943 bg_spi_init(bg_spi);
944
945 /* BGCOM Interrupt probe */
946 node = spi->dev.of_node;
947 irq_gpio = of_get_named_gpio(node, "qcom,irq-gpio", 0);
948 if (!gpio_is_valid(irq_gpio)) {
949 pr_err("gpio %d found is not valid\n", irq_gpio);
950 goto err_ret;
951 }
952
953 ret = gpio_request(irq_gpio, "bgcom_gpio");
954 if (ret) {
955 pr_err("gpio %d request failed\n", irq_gpio);
956 goto err_ret;
957 }
958
959 ret = gpio_direction_input(irq_gpio);
960 if (ret) {
961 pr_err("gpio_direction_input not set: %d\n", ret);
962 goto err_ret;
963 }
964
965 bg_irq = gpio_to_irq(irq_gpio);
966 ret = request_threaded_irq(bg_irq, NULL, bg_irq_tasklet_hndlr,
967 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "qcom,bg_spi", bg_spi);
968
969 if (ret)
970 goto err_ret;
971
972 pr_info("Bgcom Probed successfully\n");
973 return ret;
974
975err_ret:
976 bg_com_drv = NULL;
977 mutex_destroy(&bg_spi->xfer_mutex);
978 spi_set_drvdata(spi, NULL);
979 return -ENODEV;
980}
981
982static int bg_spi_remove(struct spi_device *spi)
983{
984 struct bg_spi_priv *bg_spi = spi_get_drvdata(spi);
985
986 mutex_destroy(&bg_spi->xfer_mutex);
987 devm_kfree(&spi->dev, bg_spi);
988 spi_set_drvdata(spi, NULL);
989
990 return 0;
991}
992
993static const struct of_device_id bg_spi_of_match[] = {
994 { .compatible = "qcom,bg-spi", },
995 { }
996};
997MODULE_DEVICE_TABLE(of, bg_spi_of_match);
998
999static struct spi_driver bg_spi_driver = {
1000 .driver = {
1001 .name = "bg-spi",
1002 .of_match_table = bg_spi_of_match,
1003 },
1004 .probe = bg_spi_probe,
1005 .remove = bg_spi_remove,
1006};
1007
1008module_spi_driver(bg_spi_driver);
1009MODULE_DESCRIPTION("bg SPI driver");
1010MODULE_LICENSE("GPL v2");