diff options
Diffstat (limited to 'drivers/misc/modem_if/modem_link_device_spi.c')
-rw-r--r-- | drivers/misc/modem_if/modem_link_device_spi.c | 246 |
1 files changed, 136 insertions, 110 deletions
diff --git a/drivers/misc/modem_if/modem_link_device_spi.c b/drivers/misc/modem_if/modem_link_device_spi.c index c4715e0..ece6b65 100644 --- a/drivers/misc/modem_if/modem_link_device_spi.c +++ b/drivers/misc/modem_if/modem_link_device_spi.c @@ -26,9 +26,10 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/suspend.h> #include <linux/kthread.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_spi.h" #include "modem_utils.h" @@ -66,8 +67,7 @@ static irqreturn_t spi_srdy_irq_handler(int irq, void *p_ld) if (!spild->boot_done) return result; - if (!wake_lock_active(&spild->spi_wake_lock) - && spild->send_modem_spi != 1) { + if (!wake_lock_active(&spild->spi_wake_lock)) { wake_lock(&spild->spi_wake_lock); pr_debug("[SPI] [%s](%d) spi_wakelock locked . spild->spi_state[%d]\n", __func__, __LINE__, (int)spild->spi_state); @@ -311,7 +311,7 @@ static void spi_prepare_tx_packet(void) ld = &p_spild->ld; - for (i = 0; i < p_spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { while ((skb = skb_dequeue(ld->skb_txq[i]))) { ret = spi_buff_write(p_spild, i, skb->data, skb->len); if (!ret) { @@ -331,7 +331,7 @@ static void spi_start_data_send(void) ld = &p_spild->ld; - for (i = 0; i < p_spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { if (skb_queue_len(ld->skb_txq[i]) > 0) spi_send_work(SPI_WORK_SEND, SPI_WORK); } @@ -345,6 +345,14 @@ static void spi_tx_work(void) char *spi_sync_buf; spild = p_spild; + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + + if (iod->mc->phone_state == STATE_CRASH_EXIT) + return; /* check SUB SRDY, SRDY state */ if (gpio_get_value(spild->gpio_ipc_sub_srdy) == @@ -420,8 +428,6 @@ static void spi_tx_work(void) pr_err("[SPI] spi_dev_send fail\n"); /* add cp reset when spi sync fail */ - iod = link_get_iod_with_format(&spild->ld, IPC_FMT); - if (iod) iod->modem_state_changed(iod, STATE_CRASH_RESET); @@ -553,6 +559,15 @@ static void spi_rx_work(void) if (!spild) pr_err("[LNK/E] <%s> dpld == NULL\n", __func__); + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + + if (iod->mc->phone_state == STATE_CRASH_EXIT) + return; + if (!wake_lock_active(&spild->spi_wake_lock) || gpio_get_value(spild->gpio_ipc_srdy) == SPI_GPIOLEVEL_LOW || get_console_suspended() || @@ -606,7 +621,7 @@ static void spi_rx_work(void) /* parsing SPI packet */ if (spi_buff_read(spild) > 0) { /* call function for send data to IPC, RAW, RFS */ - for (i = 0; i < spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { iod = spild->iod[i]; while ((skb = skb_dequeue(&spild->skb_rxq[i])) != NULL) { @@ -623,8 +638,6 @@ static void spi_rx_work(void) "spi sync failed"); /* add cp reset when spi sync fail */ - iod = link_get_iod_with_format(&spild->ld, IPC_FMT); - if (iod) iod->modem_state_changed(iod, STATE_CRASH_RESET); @@ -639,6 +652,34 @@ static void spi_rx_work(void) spi_start_data_send(); } + +static int spi_init_ipc(struct spi_link_device *spild) +{ + struct link_device *ld = &spild->ld; + + int i; + + /* Make aliases to each IO device */ + for (i = 0; i < MAX_DEV_FORMAT; i++) + spild->iod[i] = link_get_iod_with_format(ld, i); + + spild->iod[IPC_RAW] = spild->iod[IPC_MULTI_RAW]; + + /* List up the IO devices connected to each IPC channel */ + for (i = 0; i < MAX_DEV_FORMAT; i++) { + if (spild->iod[i]) + pr_err("[LNK] <%s:%s> spild->iod[%d]->name = %s\n", + __func__, ld->name, i, spild->iod[i]->name); + else + pr_err("[LNK] <%s:%s> No spild->iod[%d]\n", + __func__, ld->name, i); + } + + ld->mode = LINK_MODE_IPC; + + return 0; +} + unsigned int sprd_crc_calc(char *buf_ptr, unsigned int len) { unsigned int i; @@ -1239,10 +1280,19 @@ err3: static void spi_send_modem_bin(struct work_struct *send_modem_w) { + struct spi_link_device *spild; + struct io_device *iod; int retval; struct image_buf img; unsigned long tick1, tick2 = 0; + spild = p_spild; + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + tick1 = jiffies_to_msecs(jiffies); retval = spi_send_modem_bin_xmit_img(MODEM_MAIN, &img); @@ -1285,16 +1335,25 @@ static void spi_send_modem_bin(struct work_struct *send_modem_w) tick2 = jiffies_to_msecs(jiffies); pr_info("Downloading takes %lu msec\n", (tick2-tick1)); - complete_all(&p_spild->ril_init); + spi_init_ipc(p_spild); + sprd_boot_done = 1; p_spild->ril_send_cnt = 0; + p_spild->spi_state = SPI_STATE_IDLE; + if (iod) + iod->modem_state_changed(iod, + STATE_ONLINE); + return; err: + if (iod) + iod->modem_state_changed(iod, + STATE_OFFLINE); return; } -static inline int _request_mem(struct ipc_spi *od) +static inline int _request_mem(struct spi_v_buff *od) { if (!p_spild->p_virtual_buff) { od->mmio = vmalloc(od->size); @@ -1320,7 +1379,7 @@ void spi_tx_timer_callback(unsigned long param) { if (p_spild->spi_state == SPI_STATE_TX_WAIT) { p_spild->spi_timer_tx_state = SPI_STATE_TIME_OVER; - pr_err("[SPI] spi_tx_timer_callback -timer expires\n"); + pr_debug("[SPI] spi_tx_timer_callback -timer expires\n"); } } @@ -1328,7 +1387,7 @@ void spi_rx_timer_callback(unsigned long param) { if (p_spild->spi_state == SPI_STATE_RX_WAIT) { p_spild->spi_timer_rx_state = SPI_STATE_TIME_OVER; - pr_err("[SPI] spi_rx_timer_callback -timer expires\n"); + pr_debug("[SPI] spi_rx_timer_callback -timer expires\n"); } } @@ -1381,96 +1440,37 @@ static void spi_work(struct work_struct *work) } } -static int spi_init_ipc(struct spi_link_device *spild) +static int link_pm_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) { - struct link_device *ld = &spild->ld; - - int i; - - /* Make aliases to each IO device */ - for (i = 0; i < MAX_DEV_FORMAT; i++) - spild->iod[i] = link_get_iod_with_format(ld, i); - - spild->iod[IPC_RAW] = spild->iod[IPC_MULTI_RAW]; - - /* List up the IO devices connected to each IPC channel */ - for (i = 0; i < MAX_DEV_FORMAT; i++) { - if (spild->iod[i]) - pr_err("[LNK] <%s:%s> spild->iod[%d]->name = %s\n", - __func__, ld->name, i, spild->iod[i]->name); - else - pr_err("[LNK] <%s:%s> No spild->iod[%d]\n", - __func__, ld->name, i); - } - - ld->mode = LINK_MODE_IPC; - - return 0; -} - -static int spi_thread(void *data) -{ - struct spi_link_device *spild = (struct spi_link_device *)data; + struct io_device *iod; + struct link_pm_data *pm_data = + container_of(this, struct link_pm_data, pm_notifier); - if (lpcharge == 1) { - pr_err("[LPM MODE] spi_thread_exit!\n"); - return 0; + iod = link_get_iod_with_format(&pm_data->spild->ld, IPC_FMT); + if (!iod) { + pr_err("no iodevice for modem control\n"); + return NOTIFY_BAD; } - daemonize("spi_thread"); - - pr_info("[%s] spi_thread start.\n", __func__); - p_spild->boot_done = 1; - - wait_for_completion(&p_spild->ril_init); - - pr_info("[%s] ril_init completed.\n", __func__); + if (!gpio_get_value(iod->mc->gpio_phone_active)) + return NOTIFY_DONE; - pr_info("<%s> wait 2 sec... srdy : %d\n", - __func__, gpio_get_value(spild->gpio_ipc_srdy)); - msleep_interruptible(1700); + switch (event) { + case PM_SUSPEND_PREPARE: + /* set TD PDA Active High if previous state was LPA */ + mif_info("TD PDA active low to LPA suspend spot\n"); + gpio_set_value(iod->mc->gpio_pda_active, 0); - while (gpio_get_value(spild->gpio_ipc_srdy)) - ; - pr_info("(%s) cp booting... Done.\n", __func__); - - spi_init_ipc(spild); - - pr_info("[spi_thread] Start IPC Communication. SRDY : %d\n", - gpio_get_value(spild->gpio_ipc_srdy)); - - /* CP booting is already completed, just set submrdy to high */ - if (gpio_get_value(spild->gpio_ipc_sub_srdy) == SPI_GPIOLEVEL_HIGH) { - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_HIGH); - pr_err("[spi_thread] CP booting is already completed\n"); + return NOTIFY_OK; + case PM_POST_SUSPEND: + /* LPA to Kernel suspend and User Freezing task fail resume, + restore to LPA GPIO states. */ + mif_info("TD PDA active High to LPA GPIO state\n"); + gpio_set_value(iod->mc->gpio_pda_active, 1); + return NOTIFY_OK; } - /* CP booting is not completed. - set submrdy to high and wait until subsrdy is high */ - else { - pr_err("[spi_thread] CP booting is not completed. wait...\n"); - - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_HIGH); - do { - msleep_interruptible(5); - } while (gpio_get_value(spild->gpio_ipc_sub_srdy) == - SPI_GPIOLEVEL_LOW); - - pr_err("[spi_thread] CP booting is done...\n"); - } - - if (p_spild->spi_is_restart) - msleep_interruptible(100); - else - msleep_interruptible(30); - - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_LOW); - - pr_info("(%s) spi sync done.\n", __func__); - - spild->spi_state = SPI_STATE_IDLE; - p_spild->spi_is_restart = 0; - - return 0; + return NOTIFY_DONE; } static int spi_probe(struct spi_device *spi) @@ -1512,8 +1512,7 @@ static struct spi_driver spi_driver = { static int spi_link_init(void) { int ret; - struct ipc_spi *od; - struct task_struct *th; + struct spi_v_buff *od; struct link_device *ld = &p_spild->ld; p_spild->gpio_modem_bin_srdy = p_spild->gpio_ipc_srdy; @@ -1522,7 +1521,7 @@ static int spi_link_init(void) p_spild->gpio_ipc_mrdy, p_spild->gpio_modem_bin_srdy, gpio_get_value(p_spild->gpio_ipc_srdy)); - od = kzalloc(sizeof(struct ipc_spi), GFP_KERNEL); + od = kzalloc(sizeof(struct spi_v_buff), GFP_KERNEL); if (!od) { pr_err("(%d) failed to allocate device\n", __LINE__); ret = -ENOMEM; @@ -1537,7 +1536,6 @@ static int spi_link_init(void) if (ret) goto err; - init_completion(&p_spild->ril_init); sema_init(&p_spild->srdy_sem, 0); INIT_WORK(&p_spild->send_modem_w, @@ -1563,12 +1561,7 @@ static int spi_link_init(void) if (ret) goto err; - th = kthread_create(spi_thread, (void *)p_spild, "spi_thread"); - if (IS_ERR(th)) { - pr_err("kernel_thread() failed\n"); - goto err; - } - wake_up_process(th); + p_spild->boot_done = 1; pr_info("[%s] Done\n", __func__); return 0; @@ -1591,7 +1584,6 @@ void spi_set_restart(void) gpio_set_value(p_spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_LOW); p_spild->spi_state = SPI_STATE_END; - p_spild->spi_is_restart = 1; /* Flush SPI work queue */ flush_workqueue(p_spild->spi_wq); @@ -1635,6 +1627,35 @@ exit: } EXPORT_SYMBOL(spi_thread_restart); +static int spi_link_pm_init(struct spi_link_device *spild, + struct platform_device *pdev) +{ + struct modem_data *pdata = + (struct modem_data *)pdev->dev.platform_data; + struct modemlink_pm_data *pm_pdata; + struct link_pm_data *pm_data = + kzalloc(sizeof(struct link_pm_data), GFP_KERNEL); + + if (!pdata || !pdata->link_pm_data) { + mif_err("platform data is NULL\n"); + return -EINVAL; + } + pm_pdata = pdata->link_pm_data; + + if (!pm_data) { + mif_err("link_pm_data is NULL\n"); + return -ENOMEM; + } + + pm_data->spild = spild; + spild->link_pm_data = pm_data; + + pm_data->pm_notifier.notifier_call = link_pm_notifier_event; + register_pm_notifier(&pm_data->pm_notifier); + + return 0; +} + struct link_device *spi_create_link_device(struct platform_device *pdev) { struct spi_link_device *spild = NULL; @@ -1689,9 +1710,9 @@ struct link_device *spi_create_link_device(struct platform_device *pdev) } spild->spi_state = SPI_STATE_END; - spild->max_ipc_dev = IPC_RFS+1; /* FMT, RAW, RFS */ + ld->max_ipc_dev = (IPC_RFS + 1); /* FMT, RAW, RFS */ - for (i = 0; i < spild->max_ipc_dev; i++) + for (i = 0; i < ld->max_ipc_dev; i++) skb_queue_head_init(&spild->skb_rxq[i]); /* Prepare a clean buffer for SPI access */ @@ -1738,6 +1759,11 @@ struct link_device *spi_create_link_device(struct platform_device *pdev) goto err; } + /* create link pm device */ + ret = spi_link_pm_init(spild, pdev); + if (ret) + goto err; + /* Create SPI device */ ret = spi_link_init(); if (ret) |