wl1251: use ELP wakeup interrupt instead of polling
[pandora-wifi.git] / drivers / net / wireless / wl12xx / wl1251_ps.c
index f5b90a1..4e4c661 100644 (file)
@@ -67,8 +67,10 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
 
 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);
@@ -79,31 +81,42 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
        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)