ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend
authorRaja Mani <rmani@qca.qualcomm.com>
Mon, 30 Jan 2012 11:43:09 +0000 (17:13 +0530)
committerKalle Valo <kvalo@qca.qualcomm.com>
Mon, 30 Jan 2012 19:22:54 +0000 (21:22 +0200)
Using this patch, the user can bypass existing auto
suspend mode selection logic and force ath6kl to enter
into the suspend mode what he/she wants.

If the user doesn't choose any suspend mode while doing
insmod of the driver, auto suspend mode selection logic
will kick in and choose suspend mode based on the host
SDIO controller capability.

Generic module parameter is required to specify suspend
mode including Deep Sleep and WOW while doing insmod.
Renaming existing mod param variable suspend_cutpower
would be sufficient to meet this requirement.

New module parameter suspend_mode can take any one of
the below suspend state,
   1. cut power
   2. deep sleep
   3. wow

Signed-off-by: Raja Mani <rmani@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath6kl/core.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/sdio.c

index 2a51981..722ca59 100644 (file)
 #include "cfg80211.h"
 
 unsigned int debug_mask;
-static bool suspend_cutpower;
+static unsigned int suspend_mode;
 static unsigned int uart_debug;
 static unsigned int ath6kl_p2p;
 static unsigned int testmode;
 
 module_param(debug_mask, uint, 0644);
-module_param(suspend_cutpower, bool, 0444);
+module_param(suspend_mode, uint, 0644);
 module_param(uart_debug, uint, 0644);
 module_param(ath6kl_p2p, uint, 0644);
 module_param(testmode, uint, 0644);
@@ -147,8 +147,12 @@ int ath6kl_core_init(struct ath6kl *ar)
        ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
                         ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
-       if (suspend_cutpower)
-               ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER;
+       if (suspend_mode &&
+               suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
+               suspend_mode <= WLAN_POWER_STATE_WOW)
+               ar->suspend_mode = suspend_mode;
+       else
+               ar->suspend_mode = 0;
 
        if (uart_debug)
                ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
index 426f269..ce572c0 100644 (file)
@@ -196,8 +196,7 @@ struct ath6kl_fw_ie {
 #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN  BIT(1)
 #define ATH6KL_CONF_ENABLE_11N                 BIT(2)
 #define ATH6KL_CONF_ENABLE_TX_BURST            BIT(3)
-#define ATH6KL_CONF_SUSPEND_CUTPOWER           BIT(4)
-#define ATH6KL_CONF_UART_DEBUG                 BIT(5)
+#define ATH6KL_CONF_UART_DEBUG                 BIT(4)
 
 enum wlan_low_pwr_state {
        WLAN_POWER_STATE_ON,
@@ -619,6 +618,7 @@ struct ath6kl {
        } hw;
 
        u16 conf_flags;
+       u16 suspend_mode;
        wait_queue_head_t event_wq;
        struct ath6kl_mbox_info mbox_info;
 
index d9f5591..07dcf00 100644 (file)
@@ -779,7 +779,7 @@ out:
        return ret;
 }
 
-static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
        struct sdio_func *func = ar_sdio->func;
@@ -790,60 +790,82 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 
        ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
 
-       if (!(flags & MMC_PM_KEEP_POWER) ||
-           (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) {
-               /* as host doesn't support keep power we need to cut power */
-               return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
-                                              NULL);
-       }
+       if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
+           !(flags & MMC_PM_KEEP_POWER))
+               return -EINVAL;
 
        ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
        if (ret) {
-               printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
-                      ret);
+               ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
                return ret;
        }
 
-       if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
-               goto deepsleep;
-
        /* sdio irq wakes up host */
+       ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+       if (ret)
+               ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+
+       return ret;
+}
+
+static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+       struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+       struct sdio_func *func = ar_sdio->func;
+       mmc_pm_flag_t flags;
+       int ret;
 
        if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+               ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
+
+               ret = ath6kl_set_sdio_pm_caps(ar);
+               if (ret)
+                       goto cut_pwr;
+
                ret =  ath6kl_cfg80211_suspend(ar,
                                               ATH6KL_CFG_SUSPEND_SCHED_SCAN,
                                               NULL);
-               if (ret) {
-                       ath6kl_warn("Schedule scan suspend failed: %d", ret);
-                       return ret;
-               }
-
-               ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
                if (ret)
-                       ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+                       goto cut_pwr;
 
-               return ret;
+               return 0;
        }
 
-       if (wow) {
-               /*
-                * The host sdio controller is capable of keep power and
-                * sdio irq wake up at this point. It's fine to continue
-                * wow suspend operation.
-                */
+       if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
+           (!ar->suspend_mode && wow)) {
+
+               ret = ath6kl_set_sdio_pm_caps(ar);
+               if (ret)
+                       goto cut_pwr;
+
                ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
                if (ret)
-                       return ret;
+                       goto cut_pwr;
+
+               return 0;
+       }
+
+       if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
+           !ar->suspend_mode) {
 
-               ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+               flags = sdio_get_host_pm_caps(func);
+               if (!(flags & MMC_PM_KEEP_POWER))
+                       goto cut_pwr;
+
+               ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
                if (ret)
-                       ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+                       goto cut_pwr;
 
-               return ret;
+               ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
+                                             NULL);
+               if (ret)
+                       goto cut_pwr;
+
+               return 0;
        }
 
-deepsleep:
-       return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
+cut_pwr:
+       return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
 }
 
 static int ath6kl_sdio_resume(struct ath6kl *ar)