int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
- unsigned long timeout, start;
+ DECLARE_COMPLETION_ONSTACK(compl);
+ unsigned long start;
u32 elp_reg;
+ int ret;
if (delayed_work_pending(&wl->elp_work))
cancel_delayed_work(&wl->elp_work);
wl1251_debug(DEBUG_PSM, "waking up chip from elp");
start = jiffies;
- timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
-
- wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
- /*
- * FIXME: we should wait for irq from chip but, as a temporary
- * solution to simplify locking, let's poll instead
- */
- while (!(elp_reg & ELPCTRL_WLAN_READY)) {
- if (time_after(jiffies, timeout)) {
- wl1251_error("elp wakeup timeout");
- return -ETIMEDOUT;
+ wl->elp_compl = &compl;
+ wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR,
+ ELPCTRL_WAKE_UP | ELPCTRL_IRQ_SRC);
+
+ elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ if (!(elp_reg & ELPCTRL_WLAN_READY)) {
+ ret = wait_for_completion_timeout(
+ &compl, msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT));
+ if (ret == 0) {
+ wl1251_error("ELP wakeup timeout");
+ ret = -ETIMEDOUT;
+ goto err;
+ } else if (ret < 0) {
+ wl1251_error("ELP wakeup completion error.");
+ goto err;
}
- msleep(1);
- elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
}
+ wl->elp_compl = NULL;
+
+ /* clear IRQ_SRC to switch irq source back from WLAN_RDY to HOST_IRQ */
+ wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+
wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies - start));
wl->elp = false;
return 0;
+
+err:
+ wl->elp_compl = NULL;
+ return ret;
}
int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)