diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/baseband-xmm-power.c | 132 | ||||
-rw-r--r-- | arch/arm/mach-tegra/baseband-xmm-power.h | 16 |
2 files changed, 90 insertions, 58 deletions
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c index a1c6a9c15ebe..37302317d82b 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.c +++ b/arch/arm/mach-tegra/baseband-xmm-power.c @@ -81,12 +81,12 @@ static enum baseband_xmm_powerstate_t baseband_xmm_powerstate; static enum ipc_ap_wake_state_t ipc_ap_wake_state; static struct workqueue_struct *workqueue; static struct work_struct init2_work; -static struct work_struct L2_resume_work; +static struct work_struct l2_resume_work; static struct work_struct autopm_resume_work; static bool register_hsic_device; static struct wake_lock wakelock; static struct usb_device *usbdev; -static bool CP_initiated_L2toL0; +static bool cp_initiated_l2tol0; static bool modem_power_on; static int power_onoff; static int reenable_autosuspend; @@ -164,6 +164,17 @@ static int tegra_baseband_rail_off(void) return 0; } +static inline enum baseband_xmm_powerstate_t baseband_xmm_get_power_status(void) +{ + enum baseband_xmm_powerstate_t status; + unsigned long flags; + + spin_lock_irqsave(&xmm_lock, flags); + status = baseband_xmm_powerstate; + spin_unlock_irqrestore(&xmm_lock, flags); + return status; +} + static int baseband_modem_power_on(struct baseband_power_platform_data *data) { /* set IPC_HSIC_ACTIVE active */ @@ -230,6 +241,7 @@ static int xmm_power_on(struct platform_device *device) struct baseband_power_platform_data *pdata = device->dev.platform_data; struct xmm_power_data *data = &xmm_power_drv_data; + unsigned long flags; int ret; pr_debug("%s {\n", __func__); @@ -239,13 +251,13 @@ static int xmm_power_on(struct platform_device *device) pr_err("%s: !pdata\n", __func__); return -EINVAL; } - if (baseband_xmm_powerstate != BBXMM_PS_UNINIT) + if (baseband_xmm_get_power_status() != BBXMM_PS_UNINIT) return -EINVAL; tegra_baseband_rail_on(); /* reset the state machine */ - baseband_xmm_powerstate = BBXMM_PS_INIT; + baseband_xmm_set_power_status(BBXMM_PS_INIT); modem_sleep_flag = false; pr_debug("%s wake_st(%d) modem version %lu\n", __func__, @@ -255,7 +267,10 @@ static int xmm_power_on(struct platform_device *device) if (!modem_flash) { pr_debug("%s - %d\n", __func__, __LINE__); + spin_lock_irqsave(&xmm_lock, flags); ipc_ap_wake_state = IPC_AP_WAKE_INIT2; + spin_unlock_irqrestore(&xmm_lock, flags); + /* register usb host controller only once */ if (register_hsic_device) { pr_debug("%s: register usb host controller\n", @@ -282,8 +297,11 @@ static int xmm_power_on(struct platform_device *device) */ pr_debug("%s: reset flash modem\n", __func__); + modem_power_on = false; + spin_lock_irqsave(&xmm_lock, flags); ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; + spin_unlock_irqrestore(&xmm_lock, flags); gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0); xmm_power_reset_on(pdata); @@ -302,14 +320,14 @@ static int xmm_power_off(struct platform_device *device) struct baseband_power_platform_data *pdata = device->dev.platform_data; struct xmm_power_data *data = &xmm_power_drv_data; - int ret; unsigned long flags; pr_debug("%s {\n", __func__); - if (baseband_xmm_powerstate == BBXMM_PS_UNINIT) + if (baseband_xmm_get_power_status() == BBXMM_PS_UNINIT) return -EINVAL; + /* check for device / platform data */ if (!device) { pr_err("%s: !device\n", __func__); @@ -320,7 +338,10 @@ static int xmm_power_off(struct platform_device *device) return -EINVAL; } + spin_lock_irqsave(&xmm_lock, flags); ipc_ap_wake_state = IPC_AP_WAKE_UNINIT; + spin_unlock_irqrestore(&xmm_lock, flags); + ret = disable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake)); if (ret < 0) pr_err("%s: disable_irq_wake error\n", __func__); @@ -343,13 +364,15 @@ static int xmm_power_off(struct platform_device *device) /* sleep 1ms */ usleep_range(1000, 2000); - baseband_xmm_powerstate = BBXMM_PS_UNINIT; - modem_sleep_flag = false; - CP_initiated_L2toL0 = false; + baseband_xmm_set_power_status(BBXMM_PS_UNINIT); + spin_lock_irqsave(&xmm_lock, flags); + modem_sleep_flag = false; + cp_initiated_l2tol0 = false; wakeup_pending = false; system_suspending = false; spin_unlock_irqrestore(&xmm_lock, flags); + /* start registration process once again on xmm on */ register_hsic_device = true; @@ -430,23 +453,31 @@ static void xmm_power_l2_resume(void) if (!pdata) return; + /* erroneous remote-wakeup might call this from irq */ + if (in_interrupt() || in_atomic()) { + pr_err("%s: not allowed in interrupt\n", __func__); + return; + } + /* claim the wakelock here to avoid any system suspend */ if (!wake_lock_active(&wakelock)) wake_lock_timeout(&wakelock, HZ*2); - modem_sleep_flag = false; + spin_lock_irqsave(&xmm_lock, flags); + modem_sleep_flag = false; wakeup_pending = false; - spin_unlock_irqrestore(&xmm_lock, flags); - if (CP_initiated_L2toL0) { + if (cp_initiated_l2tol0) { + cp_initiated_l2tol0 = false; + queue_work(workqueue, &l2_resume_work); + spin_unlock_irqrestore(&xmm_lock, flags); pr_info("CP L2->L0\n"); - CP_initiated_L2toL0 = false; - queue_work(workqueue, &L2_resume_work); } else { /* set the slave wakeup request */ - pr_info("AP/CP L2->L0\n"); value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake); + spin_unlock_irqrestore(&xmm_lock, flags); if (value) { + pr_info("AP/CP L2->L0\n"); drv->hostwake = 0; /* wake bb */ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1); @@ -474,16 +505,21 @@ retry: } } - +/* this function holds xmm_lock */ void baseband_xmm_set_power_status(unsigned int status) { struct baseband_power_platform_data *data = xmm_power_drv_data.pdata; int value = 0; unsigned long flags; - if (baseband_xmm_powerstate == status) + if (baseband_xmm_get_power_status() == status) return; - pr_debug("%s\n", __func__); + + /* avoid prints inside spinlock */ + if (status <= BBXMM_PS_L2) + pr_info("%s\n", status == BBXMM_PS_L0 ? "L0" : "L2"); + + spin_lock_irqsave(&xmm_lock, flags); switch (status) { case BBXMM_PS_L0: if (modem_sleep_flag) { @@ -491,7 +527,6 @@ void baseband_xmm_set_power_status(unsigned int status) * xmm_power_driver_handle_resume(data); */ } - pr_info("L0\n"); baseband_xmm_powerstate = status; if (!wake_lock_active(&wakelock)) wake_lock_timeout(&wakelock, HZ*2); @@ -507,15 +542,13 @@ void baseband_xmm_set_power_status(unsigned int status) } break; case BBXMM_PS_L2: - pr_info("L2\n"); baseband_xmm_powerstate = status; - spin_lock_irqsave(&xmm_lock, flags); if (wakeup_pending) { spin_unlock_irqrestore(&xmm_lock, flags); pr_debug("%s: wakeup pending\n", __func__); xmm_power_l2_resume(); + spin_lock_irqsave(&xmm_lock, flags); } else { - spin_unlock_irqrestore(&xmm_lock, flags); if (wake_lock_active(&wakelock)) wake_unlock(&wakelock); modem_sleep_flag = true; @@ -523,15 +556,14 @@ void baseband_xmm_set_power_status(unsigned int status) break; case BBXMM_PS_L2TOL0: pr_debug("L2TOL0\n"); - spin_lock_irqsave(&xmm_lock, flags); system_suspending = false; wakeup_pending = false; - spin_unlock_irqrestore(&xmm_lock, flags); /* do this only from L2 state */ if (baseband_xmm_powerstate == BBXMM_PS_L2) { baseband_xmm_powerstate = status; - pr_debug("BB XMM POWER STATE = %d\n", status); + spin_unlock_irqrestore(&xmm_lock, flags); xmm_power_l2_resume(); + spin_lock_irqsave(&xmm_lock, flags); } baseband_xmm_powerstate = status; break; @@ -540,6 +572,7 @@ void baseband_xmm_set_power_status(unsigned int status) baseband_xmm_powerstate = status; break; } + spin_unlock_irqrestore(&xmm_lock, flags); pr_debug("BB XMM POWER STATE = %d\n", status); } EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status); @@ -553,38 +586,40 @@ irqreturn_t xmm_power_ipc_ap_wake_irq(int value) /* modem wakeup part */ if (!value) { pr_debug("%s - falling\n", __func__); - if (drv->hostwake == 0) { - /* AP L2 to L0 wakeup */ - pr_debug("received wakeup ap l2->l0\n"); - drv->hostwake = 1; - wake_up_interruptible(&drv->bb_wait); - } + spin_lock(&xmm_lock); + + /* AP L2 to L0 wakeup */ + pr_debug("received wakeup ap l2->l0\n"); + drv->hostwake = 1; + wake_up_interruptible(&drv->bb_wait); + /* First check it a CP ack or CP wake */ value = gpio_get_value(data->modem.xmm.ipc_bb_wake); if (value) { pr_debug("cp ack for bb_wake\n"); ipc_ap_wake_state = IPC_AP_WAKE_L; + spin_unlock(&xmm_lock); return IRQ_HANDLED; } - spin_lock(&xmm_lock); wakeup_pending = true; - if (system_suspending) { - spin_unlock(&xmm_lock); - pr_info("Set wakeup_pending = 1 in system_" - " suspending!!!\n"); - } else { - if (baseband_xmm_powerstate == BBXMM_PS_L2) { - CP_initiated_L2toL0 = true; + if (system_suspending) + pr_info("set wakeup_pending 1 in system_suspending\n"); + else { + if (baseband_xmm_powerstate == BBXMM_PS_L2 || + baseband_xmm_powerstate == BBXMM_PS_L2TOL0) { + cp_initiated_l2tol0 = true; spin_unlock(&xmm_lock); baseband_xmm_set_power_status(BBXMM_PS_L2TOL0); - } else { - CP_initiated_L2toL0 = true; - spin_unlock(&xmm_lock); - } + spin_lock(&xmm_lock); + } else + cp_initiated_l2tol0 = true; + } + /* save gpio state */ ipc_ap_wake_state = IPC_AP_WAKE_L; + spin_unlock(&xmm_lock); } else { pr_debug("%s - rising\n", __func__); value = gpio_get_value(data->modem.xmm.ipc_hsic_active); @@ -846,9 +881,9 @@ static int xmm_power_pm_notifier_event(struct notifier_block *this, if (wakeup_pending && (baseband_xmm_powerstate == BBXMM_PS_L2)) { wakeup_pending = false; + cp_initiated_l2tol0 = true; spin_unlock_irqrestore(&xmm_lock, flags); pr_info("%s : Service Pending CP wakeup\n", __func__); - CP_initiated_L2toL0 = true; baseband_xmm_set_power_status(BBXMM_PS_L2TOL0); return NOTIFY_OK; } @@ -953,13 +988,13 @@ static int xmm_power_driver_probe(struct platform_device *device) /* init work objects */ INIT_WORK(&init2_work, xmm_power_init2_work); - INIT_WORK(&L2_resume_work, xmm_power_l2_resume_work); + INIT_WORK(&l2_resume_work, xmm_power_l2_resume_work); INIT_WORK(&autopm_resume_work, xmm_power_autopm_resume); /* init state variables */ register_hsic_device = true; - CP_initiated_L2toL0 = false; - baseband_xmm_powerstate = BBXMM_PS_UNINIT; + cp_initiated_l2tol0 = false; + baseband_xmm_set_power_status(BBXMM_PS_UNINIT); spin_lock_irqsave(&xmm_lock, flags); wakeup_pending = false; system_suspending = false; @@ -988,9 +1023,8 @@ static int xmm_power_driver_remove(struct platform_device *device) usb_unregister_notify(&usb_xmm_nb); /* free baseband irq(s) */ - if (modem_flash && modem_pm) { + if (modem_flash && modem_pm) free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), NULL); - } /* free baseband gpio(s) */ gpio_free_array(tegra_baseband_gpios, diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h index b9d85eafda1d..0c8723fe6766 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.h +++ b/arch/arm/mach-tegra/baseband-xmm-power.h @@ -90,15 +90,13 @@ struct xmm_power_data { }; enum baseband_xmm_powerstate_t { - BBXMM_PS_UNINIT = 0, - BBXMM_PS_INIT = 1, - BBXMM_PS_L0 = 2, - BBXMM_PS_L0TOL2 = 3, - BBXMM_PS_L2 = 4, - BBXMM_PS_L2TOL0 = 5, - BBXMM_PS_L2TOL3 = 6, - BBXMM_PS_L3 = 7, - BBXMM_PS_L3TOL0 = 8, + BBXMM_PS_L0 = 0, + BBXMM_PS_L2 = 1, + BBXMM_PS_L0TOL2 = 2, + BBXMM_PS_L2TOL0 = 3, + BBXMM_PS_UNINIT = 4, + BBXMM_PS_INIT = 5, + BBXMM_PS_L3 = 6, BBXMM_PS_LAST = -1, }; |