blob: a6a176adc583a4126a338c073f06a7fef3951e59 [file] [log] [blame]
Ajit Kumar59174b22020-02-19 13:08:07 +05301/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05302 *
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>
Arjun Singh48f011a2018-05-03 11:30:14 +053028#include <linux/dma-mapping.h>
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +053029#include "bgcom.h"
30#include "bgrsb.h"
31#include "bgcom_interface.h"
32
33#define BG_SPI_WORD_SIZE (0x04)
34#define BG_SPI_READ_LEN (0x04)
35#define BG_SPI_WRITE_CMND_LEN (0x01)
36#define BG_SPI_FIFO_READ_CMD (0x41)
37#define BG_SPI_FIFO_WRITE_CMD (0x40)
38#define BG_SPI_AHB_READ_CMD (0x43)
39#define BG_SPI_AHB_WRITE_CMD (0x42)
40#define BG_SPI_AHB_CMD_LEN (0x05)
41#define BG_SPI_AHB_READ_CMD_LEN (0x08)
42#define BG_STATUS_REG (0x05)
43#define BG_CMND_REG (0x14)
44
45#define BG_SPI_MAX_WORDS (0x3FFFFFFD)
46#define BG_SPI_MAX_REGS (0x0A)
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +053047#define HED_EVENT_ID_LEN (0x02)
48#define HED_EVENT_SIZE_LEN (0x02)
49#define HED_EVENT_DATA_STRT_LEN (0x05)
Arjun Singh17022f72018-07-24 16:32:49 +053050#define CMA_BFFR_POOL_SIZE (128*1024)
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +053051
Ajit Kumar59174b22020-02-19 13:08:07 +053052#define MAX_RETRY 100
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +053053
54enum bgcom_state {
55 /*BGCOM Staus ready*/
56 BGCOM_PROB_SUCCESS = 0,
57 BGCOM_PROB_WAIT = 1,
58 BGCOM_STATE_SUSPEND = 2,
59 BGCOM_STATE_ACTIVE = 3
60};
61
62enum bgcom_req_type {
63 /*BGCOM local requests*/
64 BGCOM_READ_REG = 0,
65 BGCOM_READ_FIFO = 1,
66 BGCOM_READ_AHB = 2,
Arjun Singh04dddde2018-05-01 22:30:12 +053067 BGCOM_WRITE_REG = 3,
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +053068};
69
70struct bg_spi_priv {
71 struct spi_device *spi;
72 /* Transaction related */
73 struct mutex xfer_mutex;
74 void *lhandle;
75 /* Message for single transfer */
76 struct spi_message msg1;
77 struct spi_transfer xfer1;
78 int irq_lock;
79
80 enum bgcom_state bg_state;
81};
82
83struct cb_data {
84 void *priv;
85 void *handle;
86 void (*bgcom_notification_cb)(void *handle, void *priv,
87 enum bgcom_event_type event,
88 union bgcom_event_data_type *event_data);
89 struct list_head list;
90};
91
92struct bg_context {
93 struct bg_spi_priv *bg_spi;
94 enum bgcom_state state;
95 struct cb_data *cb;
96};
97
98struct event_list {
99 struct event *evnt;
100 struct list_head list;
101};
102static void *bg_com_drv;
103static uint32_t g_slav_status_reg;
104
105/* BGCOM client callbacks set-up */
106static void send_input_events(struct work_struct *work);
107static struct list_head cb_head = LIST_HEAD_INIT(cb_head);
108static struct list_head pr_lst_hd = LIST_HEAD_INIT(pr_lst_hd);
Arjun Singhd9110522019-01-29 16:12:58 +0530109static DEFINE_SPINLOCK(lst_setup_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530110static enum bgcom_spi_state spi_state;
111
112
113static struct workqueue_struct *wq;
114static DECLARE_WORK(input_work, send_input_events);
115
116static struct mutex bg_resume_mutex;
117
Arjun Singh04dddde2018-05-01 22:30:12 +0530118static atomic_t bg_is_spi_active;
119static int bg_irq;
120
Arjun Singh17022f72018-07-24 16:32:49 +0530121static uint8_t *fxd_mem_buffer;
122static struct mutex cma_buffer_lock;
123
Arjun Singh48f011a2018-05-03 11:30:14 +0530124static struct spi_device *get_spi_device(void)
125{
126 struct bg_spi_priv *bg_spi = container_of(bg_com_drv,
127 struct bg_spi_priv, lhandle);
128 struct spi_device *spi = bg_spi->spi;
129 return spi;
130}
131
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530132static void augmnt_fifo(uint8_t *data, int pos)
133{
134 data[pos] = '\0';
135}
136
137static void send_input_events(struct work_struct *work)
138{
139 struct list_head *temp;
140 struct list_head *pos;
141 struct event_list *node;
142 struct event *evnt;
143
144 if (list_empty(&pr_lst_hd))
145 return;
146
147 list_for_each_safe(pos, temp, &pr_lst_hd) {
148 node = list_entry(pos, struct event_list, list);
149 evnt = node->evnt;
150 bgrsb_send_input(evnt);
151 kfree(evnt);
Arjun Singhd9110522019-01-29 16:12:58 +0530152 spin_lock(&lst_setup_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530153 list_del(&node->list);
Arjun Singhd9110522019-01-29 16:12:58 +0530154 spin_unlock(&lst_setup_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530155 kfree(node);
156 }
157}
158
159int bgcom_set_spi_state(enum bgcom_spi_state state)
160{
161 struct bg_spi_priv *bg_spi = container_of(bg_com_drv,
162 struct bg_spi_priv, lhandle);
163 if (state < 0 || state > 1)
164 return -EINVAL;
165
166 if (state == spi_state)
167 return 0;
168
169 mutex_lock(&bg_spi->xfer_mutex);
170 spi_state = state;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530171 mutex_unlock(&bg_spi->xfer_mutex);
172 return 0;
173}
174EXPORT_SYMBOL(bgcom_set_spi_state);
175
176static inline
177void add_to_irq_list(struct cb_data *data)
178{
179 list_add_tail(&data->list, &cb_head);
180}
181
182static bool is_bgcom_ready(void)
183{
184 return (bg_com_drv != NULL ? true : false);
185}
186
187static void bg_spi_reinit_xfer(struct spi_transfer *xfer)
188{
189 xfer->tx_buf = NULL;
190 xfer->rx_buf = NULL;
191 xfer->delay_usecs = 0;
192 xfer->len = 0;
193}
194
195static int read_bg_locl(enum bgcom_req_type req_type,
196 uint32_t no_of_words, void *buf)
197{
198
199 struct bg_context clnt_handle;
200 struct bg_spi_priv *spi =
201 container_of(bg_com_drv, struct bg_spi_priv, lhandle);
202 int ret = 0;
203
204 if (!buf)
205 return -EINVAL;
206
207 clnt_handle.bg_spi = spi;
208
209 switch (req_type) {
210 case BGCOM_READ_REG:
211 ret = bgcom_reg_read(&clnt_handle,
212 BG_STATUS_REG, no_of_words, buf);
213 break;
214 case BGCOM_READ_FIFO:
215 ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf);
216 break;
Arjun Singh04dddde2018-05-01 22:30:12 +0530217 case BGCOM_WRITE_REG:
218 ret = bgcom_reg_write(&clnt_handle, BG_CMND_REG,
219 no_of_words, buf);
220 break;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530221 case BGCOM_READ_AHB:
222 break;
223 }
224 return ret;
225}
226
227static int bgcom_transfer(void *handle, uint8_t *tx_buf,
228 uint8_t *rx_buf, uint32_t txn_len)
229{
230 struct spi_transfer *tx_xfer;
231 struct bg_spi_priv *bg_spi;
232 struct bg_context *cntx;
233 struct spi_device *spi;
234 int ret;
235
236 if (!handle || !tx_buf)
237 return -EINVAL;
238
239 cntx = (struct bg_context *)handle;
240
241 if (cntx->state == BGCOM_PROB_WAIT) {
242 if (!is_bgcom_ready())
243 return -ENODEV;
244 cntx->bg_spi = container_of(bg_com_drv,
245 struct bg_spi_priv, lhandle);
246 cntx->state = BGCOM_PROB_SUCCESS;
247 }
248 bg_spi = cntx->bg_spi;
249
250 if (!bg_spi)
251 return -ENODEV;
252
253 tx_xfer = &bg_spi->xfer1;
254 spi = bg_spi->spi;
255
Arjun Singh04dddde2018-05-01 22:30:12 +0530256 if (!atomic_read(&bg_is_spi_active))
257 return -ECANCELED;
258
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530259 mutex_lock(&bg_spi->xfer_mutex);
260 bg_spi_reinit_xfer(tx_xfer);
261 tx_xfer->tx_buf = tx_buf;
262 if (rx_buf)
263 tx_xfer->rx_buf = rx_buf;
264
265 tx_xfer->len = txn_len;
266 ret = spi_sync(spi, &bg_spi->msg1);
267 mutex_unlock(&bg_spi->xfer_mutex);
268
269 if (ret)
270 pr_err("SPI transaction failed: %d\n", ret);
271 return ret;
272}
273
274/* BG-COM Interrupt handling */
275static inline
276void send_event(enum bgcom_event_type event,
277 void *data)
278{
279 struct list_head *pos;
280 struct cb_data *cb;
281
282 /* send interrupt notification for each
283 * registered call-back
284 */
285 list_for_each(pos, &cb_head) {
286 cb = list_entry(pos, struct cb_data, list);
287 cb->bgcom_notification_cb(cb->handle,
288 cb->priv, event, data);
289 }
290}
291
292void bgcom_bgdown_handler(void)
293{
294 send_event(BGCOM_EVENT_RESET_OCCURRED, NULL);
295 g_slav_status_reg = 0;
296}
297EXPORT_SYMBOL(bgcom_bgdown_handler);
298
299static void parse_fifo(uint8_t *data, union bgcom_event_data_type *event_data)
300{
301 uint16_t p_len;
302 uint8_t sub_id;
303 uint32_t evnt_tm;
304 uint16_t event_id;
305 void *evnt_data;
306 struct event *evnt;
307 struct event_list *data_list;
308
309 while (*data != '\0') {
310
311 event_id = *((uint16_t *) data);
312 data = data + HED_EVENT_ID_LEN;
313 p_len = *((uint16_t *) data);
314 data = data + HED_EVENT_SIZE_LEN;
315
316 if (event_id == 0xFFFE) {
317
318 sub_id = *data;
319 evnt_tm = *((uint32_t *)(data+1));
320
321 evnt = kmalloc(sizeof(*evnt), GFP_KERNEL);
322 evnt->sub_id = sub_id;
323 evnt->evnt_tm = evnt_tm;
324 evnt->evnt_data =
325 *(int16_t *)(data + HED_EVENT_DATA_STRT_LEN);
326
327 data_list = kmalloc(sizeof(*data_list), GFP_KERNEL);
328 data_list->evnt = evnt;
Arjun Singhd9110522019-01-29 16:12:58 +0530329 spin_lock(&lst_setup_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530330 list_add_tail(&data_list->list, &pr_lst_hd);
Arjun Singhd9110522019-01-29 16:12:58 +0530331 spin_unlock(&lst_setup_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530332 } else if (event_id == 0x0001) {
333 evnt_data = kmalloc(p_len, GFP_KERNEL);
334 if (evnt_data != NULL) {
335 memcpy(evnt_data, data, p_len);
336 event_data->fifo_data.to_master_fifo_used =
337 p_len/BG_SPI_WORD_SIZE;
338 event_data->fifo_data.data = evnt_data;
339 send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED,
340 event_data);
341 }
342 }
343 data = data + p_len;
344 }
345 if (!list_empty(&pr_lst_hd))
346 queue_work(wq, &input_work);
347}
348
349static void send_back_notification(uint32_t slav_status_reg,
350 uint32_t slav_status_auto_clear_reg,
351 uint32_t fifo_fill_reg, uint32_t fifo_size_reg)
352{
353 uint16_t master_fifo_used;
354 uint16_t slave_fifo_free;
355 uint32_t *ptr;
356 int ret;
357 union bgcom_event_data_type event_data = { .fifo_data = {0} };
358
359 master_fifo_used = (uint16_t)fifo_fill_reg;
360 slave_fifo_free = (uint16_t)(fifo_fill_reg >> 16);
361
362 if (slav_status_auto_clear_reg & BIT(31))
363 send_event(BGCOM_EVENT_RESET_OCCURRED, NULL);
364
365 if (slav_status_auto_clear_reg & BIT(30))
366 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL);
367
368 if (slav_status_auto_clear_reg & BIT(29))
369 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL);
370
371 if (slav_status_auto_clear_reg & BIT(28))
372 send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL);
373
374 if (slav_status_auto_clear_reg & BIT(27))
375 send_event(BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL);
376
377 if (slav_status_auto_clear_reg & BIT(26))
378 send_event(BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL);
379
380 if (slav_status_auto_clear_reg & BIT(25))
381 send_event(BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL);
382
383 if (slav_status_auto_clear_reg & BIT(24))
384 send_event(BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL);
385
386 if (slav_status_auto_clear_reg & BIT(23))
387 send_event(BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL);
388
389 if (slav_status_auto_clear_reg & BIT(22))
390 send_event(BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL);
391
392 if (slav_status_auto_clear_reg & BIT(21))
393 send_event(BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL);
394
395 /* check if BG status is changed */
396 if (g_slav_status_reg ^ slav_status_reg) {
397 if (slav_status_reg & BIT(30)) {
398 event_data.application_running = true;
399 send_event(BGCOM_EVENT_APPLICATION_RUNNING,
400 &event_data);
401 }
402
403 if (slav_status_reg & BIT(29)) {
404 event_data.to_slave_fifo_ready = true;
405 send_event(BGCOM_EVENT_TO_SLAVE_FIFO_READY,
406 &event_data);
407 }
408
409 if (slav_status_reg & BIT(28)) {
410 event_data.to_master_fifo_ready = true;
411 send_event(BGCOM_EVENT_TO_MASTER_FIFO_READY,
412 &event_data);
413 }
414
415 if (slav_status_reg & BIT(27)) {
416 event_data.ahb_ready = true;
417 send_event(BGCOM_EVENT_AHB_READY,
418 &event_data);
419 }
420 }
421
422 if (master_fifo_used > 0) {
423 ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE + 1,
424 GFP_KERNEL | GFP_ATOMIC);
425 if (ptr != NULL) {
426 ret = read_bg_locl(BGCOM_READ_FIFO,
427 master_fifo_used, ptr);
428 if (!ret) {
429 augmnt_fifo((uint8_t *)ptr,
430 master_fifo_used*BG_SPI_WORD_SIZE);
431 parse_fifo((uint8_t *)ptr, &event_data);
432 }
433 kfree(ptr);
434 }
435 }
436
437 event_data.to_slave_fifo_free = slave_fifo_free;
438 send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data);
439}
440
441static void bg_irq_tasklet_hndlr_l(void)
442{
443 uint32_t slave_status_reg;
444 uint32_t glink_isr_reg;
445 uint32_t slav_status_auto_clear_reg;
446 uint32_t fifo_fill_reg;
447 uint32_t fifo_size_reg;
448 int ret = 0;
449 uint32_t irq_buf[5] = {0};
450
451 ret = read_bg_locl(BGCOM_READ_REG, 5, &irq_buf[0]);
452 if (ret)
453 return;
454
455 /* save current state */
456 slave_status_reg = irq_buf[0];
457 glink_isr_reg = irq_buf[1];
458 slav_status_auto_clear_reg = irq_buf[2];
459 fifo_fill_reg = irq_buf[3];
460 fifo_size_reg = irq_buf[4];
461
462 send_back_notification(slave_status_reg,
463 slav_status_auto_clear_reg, fifo_fill_reg, fifo_size_reg);
464
465 g_slav_status_reg = slave_status_reg;
466}
467
468int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr,
469 uint32_t num_words, void *read_buf)
470{
471 uint32_t txn_len;
472 uint8_t *tx_buf;
473 uint8_t *rx_buf;
474 uint32_t size;
475 int ret;
476 uint8_t cmnd = 0;
477 uint32_t ahb_addr = 0;
478
479 if (!handle || !read_buf || num_words == 0
480 || num_words > BG_SPI_MAX_WORDS) {
481 pr_err("Invalid param\n");
482 return -EINVAL;
483 }
484 if (!is_bgcom_ready())
485 return -ENODEV;
486
487 if (spi_state == BGCOM_SPI_BUSY) {
488 pr_err("Device busy\n");
489 return -EBUSY;
490 }
491
492 if (bgcom_resume(handle)) {
493 pr_err("Failed to resume\n");
494 return -EBUSY;
495 }
496
497 size = num_words*BG_SPI_WORD_SIZE;
498 txn_len = BG_SPI_AHB_READ_CMD_LEN + size;
499
Arjun Singh5e415992018-12-04 13:04:34 +0530500 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530501 if (!tx_buf)
502 return -ENOMEM;
503
Arjun Singh5e415992018-12-04 13:04:34 +0530504 rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530505 if (!rx_buf) {
Arjun Singh5e415992018-12-04 13:04:34 +0530506 kfree(tx_buf);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530507 return -ENOMEM;
508 }
509
510 cmnd |= BG_SPI_AHB_READ_CMD;
511 ahb_addr |= ahb_start_addr;
512
513 memcpy(tx_buf, &cmnd, sizeof(cmnd));
514 memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr));
515
516 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
517
518 if (!ret)
519 memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size);
520
Arjun Singh5e415992018-12-04 13:04:34 +0530521 kfree(tx_buf);
522 kfree(rx_buf);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530523 return ret;
524}
525EXPORT_SYMBOL(bgcom_ahb_read);
526
527int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr,
528 uint32_t num_words, void *write_buf)
529{
Arjun Singh48f011a2018-05-03 11:30:14 +0530530 dma_addr_t dma_hndl;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530531 uint32_t txn_len;
532 uint8_t *tx_buf;
533 uint32_t size;
534 int ret;
Arjun Singh17022f72018-07-24 16:32:49 +0530535 bool is_cma_used = false;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530536 uint8_t cmnd = 0;
537 uint32_t ahb_addr = 0;
Arjun Singh48f011a2018-05-03 11:30:14 +0530538 struct spi_device *spi = get_spi_device();
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530539
540 if (!handle || !write_buf || num_words == 0
541 || num_words > BG_SPI_MAX_WORDS) {
542 pr_err("Invalid param\n");
543 return -EINVAL;
544 }
545
546 if (!is_bgcom_ready())
547 return -ENODEV;
548
549 if (spi_state == BGCOM_SPI_BUSY) {
550 pr_err("Device busy\n");
551 return -EBUSY;
552 }
553
554 if (bgcom_resume(handle)) {
555 pr_err("Failed to resume\n");
556 return -EBUSY;
557 }
558
Arjun Singh17022f72018-07-24 16:32:49 +0530559 mutex_lock(&cma_buffer_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530560 size = num_words*BG_SPI_WORD_SIZE;
561 txn_len = BG_SPI_AHB_CMD_LEN + size;
Arjun Singh17022f72018-07-24 16:32:49 +0530562 if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) {
563 memset(fxd_mem_buffer, 0, txn_len);
564 tx_buf = fxd_mem_buffer;
565 is_cma_used = true;
Arjun Singhe6b52252018-09-17 11:39:22 +0530566 } else {
567 pr_info("DMA memory used for size[%d]\n", txn_len);
Arjun Singh17022f72018-07-24 16:32:49 +0530568 tx_buf = dma_zalloc_coherent(&spi->dev, txn_len,
569 &dma_hndl, GFP_KERNEL);
Arjun Singhe6b52252018-09-17 11:39:22 +0530570 }
Arjun Singh17022f72018-07-24 16:32:49 +0530571
572 if (!tx_buf) {
573 mutex_unlock(&cma_buffer_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530574 return -ENOMEM;
Arjun Singh17022f72018-07-24 16:32:49 +0530575 }
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530576
577 cmnd |= BG_SPI_AHB_WRITE_CMD;
578 ahb_addr |= ahb_start_addr;
579
580 memcpy(tx_buf, &cmnd, sizeof(cmnd));
581 memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr));
582 memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size);
583
584 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
Arjun Singh17022f72018-07-24 16:32:49 +0530585 if (!is_cma_used)
586 dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl);
587 mutex_unlock(&cma_buffer_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530588 return ret;
589}
590EXPORT_SYMBOL(bgcom_ahb_write);
591
592int bgcom_fifo_write(void *handle, uint32_t num_words,
593 void *write_buf)
594{
595 uint32_t txn_len;
596 uint8_t *tx_buf;
597 uint32_t size;
598 int ret;
599 uint8_t cmnd = 0;
600
601 if (!handle || !write_buf || num_words == 0
602 || num_words > BG_SPI_MAX_WORDS) {
603 pr_err("Invalid param\n");
604 return -EINVAL;
605 }
606
607 if (!is_bgcom_ready())
608 return -ENODEV;
609
610 if (spi_state == BGCOM_SPI_BUSY) {
611 pr_err("Device busy\n");
612 return -EBUSY;
613 }
614
615 if (bgcom_resume(handle)) {
616 pr_err("Failed to resume\n");
617 return -EBUSY;
618 }
619
620 size = num_words*BG_SPI_WORD_SIZE;
621 txn_len = BG_SPI_WRITE_CMND_LEN + size;
622
623 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
624
625 if (!tx_buf)
626 return -ENOMEM;
627
628 cmnd |= BG_SPI_FIFO_WRITE_CMD;
629 memcpy(tx_buf, &cmnd, sizeof(cmnd));
630 memcpy(tx_buf+sizeof(cmnd), write_buf, size);
631
632 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
633 kfree(tx_buf);
634 return ret;
635}
636EXPORT_SYMBOL(bgcom_fifo_write);
637
638int bgcom_fifo_read(void *handle, uint32_t num_words,
639 void *read_buf)
640{
641 uint32_t txn_len;
642 uint8_t *tx_buf;
643 uint8_t *rx_buf;
644 uint32_t size;
645 uint8_t cmnd = 0;
646 int ret = 0;
647
648 if (!handle || !read_buf || num_words == 0
649 || num_words > BG_SPI_MAX_WORDS) {
650 pr_err("Invalid param\n");
651 return -EINVAL;
652 }
653
654 if (!is_bgcom_ready())
655 return -ENODEV;
656
657 if (spi_state == BGCOM_SPI_BUSY) {
658 pr_err("Device busy\n");
659 return -EBUSY;
660 }
661
Arjun Singh04dddde2018-05-01 22:30:12 +0530662 if (bgcom_resume(handle)) {
663 pr_err("Failed to resume\n");
664 return -EBUSY;
665 }
666
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530667 size = num_words*BG_SPI_WORD_SIZE;
668 txn_len = BG_SPI_READ_LEN + size;
669 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
670
671 if (!tx_buf)
672 return -ENOMEM;
673
674 rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
675
676 if (!rx_buf) {
677 kfree(tx_buf);
678 return -ENOMEM;
679 }
680
681 cmnd |= BG_SPI_FIFO_READ_CMD;
682 memcpy(tx_buf, &cmnd, sizeof(cmnd));
683
684 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
685
686 if (!ret)
687 memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size);
688 kfree(tx_buf);
689 kfree(rx_buf);
690 return ret;
691}
692EXPORT_SYMBOL(bgcom_fifo_read);
693
694int bgcom_reg_write(void *handle, uint8_t reg_start_addr,
695 uint8_t num_regs, void *write_buf)
696{
697 uint32_t txn_len;
698 uint8_t *tx_buf;
699 uint32_t size;
700 uint8_t cmnd = 0;
701 int ret = 0;
702
703 if (!handle || !write_buf || num_regs == 0
704 || num_regs > BG_SPI_MAX_REGS) {
705 pr_err("Invalid param\n");
706 return -EINVAL;
707 }
708
709 if (!is_bgcom_ready())
710 return -ENODEV;
711
712 if (spi_state == BGCOM_SPI_BUSY) {
713 pr_err("Device busy\n");
714 return -EBUSY;
715 }
716
Arjun Singh04dddde2018-05-01 22:30:12 +0530717 if (bgcom_resume(handle)) {
718 pr_err("Failed to resume\n");
719 return -EBUSY;
720 }
721
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530722 size = num_regs*BG_SPI_WORD_SIZE;
723 txn_len = BG_SPI_WRITE_CMND_LEN + size;
724
725 tx_buf = kzalloc(txn_len, GFP_KERNEL);
726
727 if (!tx_buf)
728 return -ENOMEM;
729
730 cmnd |= reg_start_addr;
731 memcpy(tx_buf, &cmnd, sizeof(cmnd));
732 memcpy(tx_buf+sizeof(cmnd), write_buf, size);
733
734 ret = bgcom_transfer(handle, tx_buf, NULL, txn_len);
735 kfree(tx_buf);
736 return ret;
737}
738EXPORT_SYMBOL(bgcom_reg_write);
739
740int bgcom_reg_read(void *handle, uint8_t reg_start_addr,
741 uint32_t num_regs, void *read_buf)
742{
743 uint32_t txn_len;
744 uint8_t *tx_buf;
745 uint8_t *rx_buf;
746 uint32_t size;
747 int ret;
748 uint8_t cmnd = 0;
749
750 if (!handle || !read_buf || num_regs == 0
751 || num_regs > BG_SPI_MAX_REGS) {
752 pr_err("Invalid param\n");
753 return -EINVAL;
754 }
755
756 if (!is_bgcom_ready())
757 return -ENODEV;
758
759 if (spi_state == BGCOM_SPI_BUSY) {
760 pr_err("Device busy\n");
761 return -EBUSY;
762 }
763
764 size = num_regs*BG_SPI_WORD_SIZE;
765 txn_len = BG_SPI_READ_LEN + size;
766
767 tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
768
769 if (!tx_buf)
770 return -ENOMEM;
771
772 rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC);
773
774 if (!rx_buf) {
775 kfree(tx_buf);
776 return -ENOMEM;
777 }
778
779 cmnd |= reg_start_addr;
780 memcpy(tx_buf, &cmnd, sizeof(cmnd));
781
782 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
783
784 if (!ret)
785 memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size);
786 kfree(tx_buf);
787 kfree(rx_buf);
788 return ret;
789}
790EXPORT_SYMBOL(bgcom_reg_read);
791
792static int is_bg_resume(void *handle)
793{
794 uint32_t txn_len;
795 int ret;
796 uint8_t tx_buf[8] = {0};
797 uint8_t rx_buf[8] = {0};
798 uint32_t cmnd_reg = 0;
799
Arjun Singhaec44a22018-04-20 11:26:00 +0530800 if (spi_state == BGCOM_SPI_BUSY) {
801 printk_ratelimited("SPI is held by TZ\n");
802 goto ret_err;
803 }
804
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530805 txn_len = 0x08;
806 tx_buf[0] = 0x05;
807 ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len);
808 if (!ret)
809 memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04);
Arjun Singhaec44a22018-04-20 11:26:00 +0530810
811ret_err:
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530812 return cmnd_reg & BIT(31);
813}
814
815int bgcom_resume(void *handle)
816{
817 struct bg_spi_priv *bg_spi;
818 struct bg_context *cntx;
819 int retry = 0;
820
821 if (handle == NULL)
822 return -EINVAL;
823
Arjun Singh04dddde2018-05-01 22:30:12 +0530824 if (!atomic_read(&bg_is_spi_active))
825 return -ECANCELED;
826
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530827 cntx = (struct bg_context *)handle;
Arjun Singhfd35ef12019-02-06 10:47:15 +0530828
829 /* if client is outside bgcom scope and
830 * handle is provided before BGCOM probed
831 */
832 if (cntx->state == BGCOM_PROB_WAIT) {
833 pr_info("handle is provided before BGCOM probed\n");
834 if (!is_bgcom_ready())
835 return -EAGAIN;
836 cntx->bg_spi = container_of(bg_com_drv,
837 struct bg_spi_priv, lhandle);
838 cntx->state = BGCOM_PROB_SUCCESS;
839 }
840
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530841 bg_spi = cntx->bg_spi;
842
843 mutex_lock(&bg_resume_mutex);
844 if (bg_spi->bg_state == BGCOM_STATE_ACTIVE)
845 goto unlock;
Ajit Kumar197330e2019-10-16 15:37:47 +0530846 enable_irq(bg_irq);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530847 do {
848 if (is_bg_resume(handle)) {
849 bg_spi->bg_state = BGCOM_STATE_ACTIVE;
850 break;
851 }
Ajit Kumar59174b22020-02-19 13:08:07 +0530852 udelay(1000);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530853 ++retry;
854 } while (retry < MAX_RETRY);
855
856unlock:
857 mutex_unlock(&bg_resume_mutex);
858 if (retry == MAX_RETRY) {
859 /* BG failed to resume. Trigger BG soft reset. */
860 pr_err("BG failed to resume\n");
Protik Biswasd023ec12019-07-04 09:54:34 +0530861 pr_err("%s: gpio#95 value is: %d\n",
862 __func__, gpio_get_value(95));
863 pr_err("%s: gpio#97 value is: %d\n",
864 __func__, gpio_get_value(97));
865 BUG();
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530866 bg_soft_reset();
867 return -ETIMEDOUT;
868 }
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530869 return 0;
870}
871EXPORT_SYMBOL(bgcom_resume);
872
873int bgcom_suspend(void *handle)
874{
Arjun Singh04dddde2018-05-01 22:30:12 +0530875 if (!handle)
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530876 return -EINVAL;
Arjun Singh04dddde2018-05-01 22:30:12 +0530877 return 0;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530878}
879EXPORT_SYMBOL(bgcom_suspend);
880
881void *bgcom_open(struct bgcom_open_config_type *open_config)
882{
883 struct bg_spi_priv *spi;
884 struct cb_data *irq_notification;
885 struct bg_context *clnt_handle =
886 kzalloc(sizeof(*clnt_handle), GFP_KERNEL);
887
888 if (!clnt_handle)
889 return NULL;
890
891 /* Client handle Set-up */
892 if (!is_bgcom_ready()) {
893 clnt_handle->bg_spi = NULL;
894 clnt_handle->state = BGCOM_PROB_WAIT;
895 } else {
896 spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle);
897 clnt_handle->bg_spi = spi;
898 clnt_handle->state = BGCOM_PROB_SUCCESS;
899 }
900 clnt_handle->cb = NULL;
901 /* Interrupt callback Set-up */
902 if (open_config && open_config->bgcom_notification_cb) {
903 irq_notification = kzalloc(sizeof(*irq_notification),
904 GFP_KERNEL);
905 if (!irq_notification)
906 goto error_ret;
907
908 /* set irq node */
909 irq_notification->handle = clnt_handle;
910 irq_notification->priv = open_config->priv;
911 irq_notification->bgcom_notification_cb =
912 open_config->bgcom_notification_cb;
913 add_to_irq_list(irq_notification);
914 clnt_handle->cb = irq_notification;
915 }
916 return clnt_handle;
917
918error_ret:
919 kfree(clnt_handle);
920 return NULL;
921}
922EXPORT_SYMBOL(bgcom_open);
923
924int bgcom_close(void **handle)
925{
926 struct bg_context *lhandle;
927 struct cb_data *cb = NULL;
928
929 if (*handle == NULL)
930 return -EINVAL;
931 lhandle = *handle;
932 cb = lhandle->cb;
933 if (cb)
934 list_del(&cb->list);
935
936 kfree(*handle);
937 *handle = NULL;
938 return 0;
939}
940EXPORT_SYMBOL(bgcom_close);
941
942static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device)
943{
944 struct bg_spi_priv *bg_spi = device;
Arjun Singh98a4afd2018-08-29 13:39:33 +0530945
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530946 /* check if call-back exists */
Arjun Singh98a4afd2018-08-29 13:39:33 +0530947 if (!atomic_read(&bg_is_spi_active)) {
948 pr_debug("Interrupt received in suspend state\n");
949 return IRQ_HANDLED;
950 } else if (list_empty(&cb_head)) {
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530951 pr_debug("No callback registered\n");
952 return IRQ_HANDLED;
953 } else if (spi_state == BGCOM_SPI_BUSY) {
Arjun Singh156dbc52018-08-06 17:06:35 +0530954 /* delay for SPI to be freed */
955 msleep(50);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530956 return IRQ_HANDLED;
957 } else if (!bg_spi->irq_lock) {
958 bg_spi->irq_lock = 1;
959 bg_irq_tasklet_hndlr_l();
960 bg_spi->irq_lock = 0;
961 }
962 return IRQ_HANDLED;
963}
964
965static void bg_spi_init(struct bg_spi_priv *bg_spi)
966{
967 if (!bg_spi) {
968 pr_err("device not found\n");
969 return;
970 }
971
972 /* BGCOM SPI set-up */
973 mutex_init(&bg_spi->xfer_mutex);
974 spi_message_init(&bg_spi->msg1);
975 spi_message_add_tail(&bg_spi->xfer1, &bg_spi->msg1);
976
977 /* BGCOM IRQ set-up */
978 bg_spi->irq_lock = 0;
979
980 spi_state = BGCOM_SPI_FREE;
981
982 wq = create_singlethread_workqueue("input_wq");
983
984 bg_spi->bg_state = BGCOM_STATE_ACTIVE;
985
986 bg_com_drv = &bg_spi->lhandle;
987
988 mutex_init(&bg_resume_mutex);
Arjun Singh17022f72018-07-24 16:32:49 +0530989
990 fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC);
991
992 mutex_init(&cma_buffer_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +0530993}
994
995static int bg_spi_probe(struct spi_device *spi)
996{
997 struct bg_spi_priv *bg_spi;
998 struct device_node *node;
999 int irq_gpio = 0;
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301000 int ret;
1001
1002 bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi),
1003 GFP_KERNEL | GFP_ATOMIC);
1004 if (!bg_spi)
1005 return -ENOMEM;
1006 bg_spi->spi = spi;
1007 spi_set_drvdata(spi, bg_spi);
1008 bg_spi_init(bg_spi);
1009
1010 /* BGCOM Interrupt probe */
1011 node = spi->dev.of_node;
1012 irq_gpio = of_get_named_gpio(node, "qcom,irq-gpio", 0);
1013 if (!gpio_is_valid(irq_gpio)) {
1014 pr_err("gpio %d found is not valid\n", irq_gpio);
1015 goto err_ret;
1016 }
1017
1018 ret = gpio_request(irq_gpio, "bgcom_gpio");
1019 if (ret) {
1020 pr_err("gpio %d request failed\n", irq_gpio);
1021 goto err_ret;
1022 }
1023
1024 ret = gpio_direction_input(irq_gpio);
1025 if (ret) {
1026 pr_err("gpio_direction_input not set: %d\n", ret);
1027 goto err_ret;
1028 }
1029
1030 bg_irq = gpio_to_irq(irq_gpio);
1031 ret = request_threaded_irq(bg_irq, NULL, bg_irq_tasklet_hndlr,
Arjun Singhce5cb172019-01-28 18:17:43 +05301032 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "qcom-bg_spi", bg_spi);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301033
1034 if (ret)
1035 goto err_ret;
1036
Arjun Singh04dddde2018-05-01 22:30:12 +05301037 atomic_set(&bg_is_spi_active, 1);
Arjun Singh48f011a2018-05-03 11:30:14 +05301038 dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(64));
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301039 pr_info("Bgcom Probed successfully\n");
1040 return ret;
1041
1042err_ret:
1043 bg_com_drv = NULL;
1044 mutex_destroy(&bg_spi->xfer_mutex);
1045 spi_set_drvdata(spi, NULL);
1046 return -ENODEV;
1047}
1048
1049static int bg_spi_remove(struct spi_device *spi)
1050{
1051 struct bg_spi_priv *bg_spi = spi_get_drvdata(spi);
1052
1053 mutex_destroy(&bg_spi->xfer_mutex);
1054 devm_kfree(&spi->dev, bg_spi);
1055 spi_set_drvdata(spi, NULL);
Arjun Singh17022f72018-07-24 16:32:49 +05301056 if (fxd_mem_buffer != NULL)
1057 kfree(fxd_mem_buffer);
1058 mutex_destroy(&cma_buffer_lock);
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301059 return 0;
1060}
1061
Arjun Singh4e259312018-08-28 11:02:22 +05301062static void bg_spi_shutdown(struct spi_device *spi)
1063{
1064 bg_spi_remove(spi);
1065}
1066
Arjun Singh04dddde2018-05-01 22:30:12 +05301067static int bgcom_pm_suspend(struct device *dev)
1068{
1069 uint32_t cmnd_reg = 0;
1070 struct spi_device *s_dev = to_spi_device(dev);
1071 struct bg_spi_priv *bg_spi = spi_get_drvdata(s_dev);
1072 int ret = 0;
1073
1074 if (bg_spi->bg_state == BGCOM_STATE_SUSPEND)
1075 return 0;
1076
1077 cmnd_reg |= BIT(31);
1078 ret = read_bg_locl(BGCOM_WRITE_REG, 1, &cmnd_reg);
1079 if (ret == 0) {
1080 bg_spi->bg_state = BGCOM_STATE_SUSPEND;
1081 atomic_set(&bg_is_spi_active, 0);
Ajit Kumar197330e2019-10-16 15:37:47 +05301082 disable_irq(bg_irq);
Arjun Singh04dddde2018-05-01 22:30:12 +05301083 }
1084 pr_info("suspended with : %d\n", ret);
1085 return ret;
1086}
1087
1088static int bgcom_pm_resume(struct device *dev)
1089{
1090 struct bg_context clnt_handle;
1091 int ret;
1092 struct bg_spi_priv *spi =
1093 container_of(bg_com_drv, struct bg_spi_priv, lhandle);
1094
1095 clnt_handle.bg_spi = spi;
1096 atomic_set(&bg_is_spi_active, 1);
1097 ret = bgcom_resume(&clnt_handle);
Arjun Singh98a4afd2018-08-29 13:39:33 +05301098 pr_info("Bgcom resumed with : %d\n", ret);
Arjun Singh04dddde2018-05-01 22:30:12 +05301099 return ret;
1100}
1101
1102static const struct dev_pm_ops bgcom_pm = {
1103 .suspend = bgcom_pm_suspend,
1104 .resume = bgcom_pm_resume,
1105};
1106
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301107static const struct of_device_id bg_spi_of_match[] = {
1108 { .compatible = "qcom,bg-spi", },
1109 { }
1110};
1111MODULE_DEVICE_TABLE(of, bg_spi_of_match);
1112
1113static struct spi_driver bg_spi_driver = {
1114 .driver = {
1115 .name = "bg-spi",
1116 .of_match_table = bg_spi_of_match,
Arjun Singh04dddde2018-05-01 22:30:12 +05301117 .pm = &bgcom_pm,
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301118 },
1119 .probe = bg_spi_probe,
1120 .remove = bg_spi_remove,
Arjun Singh4e259312018-08-28 11:02:22 +05301121 .shutdown = bg_spi_shutdown,
Ramesh Yadav Javadi43ff8772018-04-06 13:13:53 +05301122};
1123
1124module_spi_driver(bg_spi_driver);
1125MODULE_DESCRIPTION("bg SPI driver");
1126MODULE_LICENSE("GPL v2");