mutex_lock(&wl->mutex);
- if (wl->elp || !wl->psm)
+ if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE)
goto out;
wl1251_debug(DEBUG_PSM, "chip to elp");
{
unsigned long delay;
- if (wl->psm) {
- cancel_delayed_work(&wl->elp_work);
+ if (wl->station_mode != STATION_ACTIVE_MODE) {
delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
}
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);
if (!wl->elp)
return 0;
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)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode)
{
int ret;
if (ret < 0)
return ret;
- ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE);
if (ret < 0)
return ret;
ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
-
- wl->psm = 1;
break;
case STATION_ACTIVE_MODE:
default:
if (ret < 0)
return ret;
- ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE);
if (ret < 0)
return ret;
- wl->psm = 0;
break;
}
+ wl->station_mode = mode;
return ret;
}