Commit e390af77 authored by Raja Mani's avatar Raja Mani Committed by Kalle Valo

ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend

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: default avatarRaja Mani <rmani@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent c8651541
...@@ -25,13 +25,13 @@ ...@@ -25,13 +25,13 @@
#include "cfg80211.h" #include "cfg80211.h"
unsigned int debug_mask; unsigned int debug_mask;
static bool suspend_cutpower; static unsigned int suspend_mode;
static unsigned int uart_debug; static unsigned int uart_debug;
static unsigned int ath6kl_p2p; static unsigned int ath6kl_p2p;
static unsigned int testmode; static unsigned int testmode;
module_param(debug_mask, uint, 0644); 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(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644); module_param(ath6kl_p2p, uint, 0644);
module_param(testmode, uint, 0644); module_param(testmode, uint, 0644);
...@@ -147,8 +147,12 @@ int ath6kl_core_init(struct ath6kl *ar) ...@@ -147,8 +147,12 @@ int ath6kl_core_init(struct ath6kl *ar)
ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
if (suspend_cutpower) if (suspend_mode &&
ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER; 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) if (uart_debug)
ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
......
...@@ -196,8 +196,7 @@ struct ath6kl_fw_ie { ...@@ -196,8 +196,7 @@ struct ath6kl_fw_ie {
#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
#define ATH6KL_CONF_ENABLE_11N BIT(2) #define ATH6KL_CONF_ENABLE_11N BIT(2)
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
#define ATH6KL_CONF_SUSPEND_CUTPOWER BIT(4) #define ATH6KL_CONF_UART_DEBUG BIT(4)
#define ATH6KL_CONF_UART_DEBUG BIT(5)
enum wlan_low_pwr_state { enum wlan_low_pwr_state {
WLAN_POWER_STATE_ON, WLAN_POWER_STATE_ON,
...@@ -619,6 +618,7 @@ struct ath6kl { ...@@ -619,6 +618,7 @@ struct ath6kl {
} hw; } hw;
u16 conf_flags; u16 conf_flags;
u16 suspend_mode;
wait_queue_head_t event_wq; wait_queue_head_t event_wq;
struct ath6kl_mbox_info mbox_info; struct ath6kl_mbox_info mbox_info;
......
...@@ -779,7 +779,7 @@ static int ath6kl_sdio_config(struct ath6kl *ar) ...@@ -779,7 +779,7 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
return ret; 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 ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func; struct sdio_func *func = ar_sdio->func;
...@@ -790,60 +790,82 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -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); ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
if (!(flags & MMC_PM_KEEP_POWER) || if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
(ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) { !(flags & MMC_PM_KEEP_POWER))
/* as host doesn't support keep power we need to cut power */ return -EINVAL;
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
NULL);
}
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret) { if (ret) {
printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
ret);
return ret; return ret;
} }
if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
goto deepsleep;
/* sdio irq wakes up host */ /* 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) { 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, ret = ath6kl_cfg80211_suspend(ar,
ATH6KL_CFG_SUSPEND_SCHED_SCAN, ATH6KL_CFG_SUSPEND_SCHED_SCAN,
NULL); 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) if (ret)
ath6kl_warn("set sdio wake irq flag failed: %d\n", ret); goto cut_pwr;
return ret; return 0;
} }
if (wow) { if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
/* (!ar->suspend_mode && wow)) {
* The host sdio controller is capable of keep power and
* sdio irq wake up at this point. It's fine to continue ret = ath6kl_set_sdio_pm_caps(ar);
* wow suspend operation. if (ret)
*/ goto cut_pwr;
ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
if (ret) 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) 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: cut_pwr:
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL); return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
} }
static int ath6kl_sdio_resume(struct ath6kl *ar) static int ath6kl_sdio_resume(struct ath6kl *ar)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment