diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 95498f80c905..cb58e44b1e45 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -1745,6 +1745,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) void prcmu_ac_wake_req(void) { u32 val; + u32 status; mutex_lock(&mb0_transfer.ac_wake_lock); @@ -1754,11 +1755,34 @@ void prcmu_ac_wake_req(void) atomic_set(&ac_wake_req_state, 1); +retry: writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), PRCM_HOSTACCESS_REQ); if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, - msecs_to_jiffies(20000))) { - pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + msecs_to_jiffies(5000))) { + panic("prcmu: %s timed out (5 s) waiting for a reply.\n", + __func__); + goto unlock_and_return; + } + + /* + * The modem can generate an AC_WAKE_ACK, and then still go to sleep. + * As a workaround, we wait, and then check that the modem is indeed + * awake (in terms of the value of the PRCM_MOD_AWAKE_STATUS + * register, which may not be the whole truth). + */ + udelay(400); + status = (readl(PRCM_MOD_AWAKE_STATUS) & BITS(0, 2)); + if (status != (PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE | + PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE)) { + pr_err("prcmu: %s received ack, but modem not awake (0x%X).\n", + __func__, status); + udelay(1200); + writel(val, PRCM_HOSTACCESS_REQ); + if (wait_for_completion_timeout(&mb0_transfer.ac_wake_work, + msecs_to_jiffies(5000))) + goto retry; + panic("prcmu: %s timed out (5 s) waiting for AC_SLEEP_ACK.\n", __func__); } @@ -1783,8 +1807,8 @@ void prcmu_ac_sleep_req() PRCM_HOSTACCESS_REQ); if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, - msecs_to_jiffies(20000))) { - pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + msecs_to_jiffies(5000))) { + panic("prcmu: %s timed out (5 s) waiting for a reply.\n", __func__); }