aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/sdio.c
diff options
context:
space:
mode:
authorRaja Mani <rmani@qca.qualcomm.com>2012-01-30 06:43:09 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2012-01-30 14:22:54 -0500
commite390af779dc671551800514d391928f5a798089a (patch)
tree2602772094fe21b94e6f38c0f2279b24da464644 /drivers/net/wireless/ath/ath6kl/sdio.c
parentc86515412f0c364f2d45029b45d5909614087af3 (diff)
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: Raja Mani <rmani@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/sdio.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index d9f55914b893..07dcf00ca1a7 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -779,7 +779,7 @@ out:
779 return ret; 779 return ret;
780} 780}
781 781
782static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) 782static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar)
783{ 783{
784 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 784 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
785 struct sdio_func *func = ar_sdio->func; 785 struct sdio_func *func = ar_sdio->func;
@@ -790,60 +790,82 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
790 790
791 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); 791 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
792 792
793 if (!(flags & MMC_PM_KEEP_POWER) || 793 if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
794 (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) { 794 !(flags & MMC_PM_KEEP_POWER))
795 /* as host doesn't support keep power we need to cut power */ 795 return -EINVAL;
796 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
797 NULL);
798 }
799 796
800 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 797 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
801 if (ret) { 798 if (ret) {
802 printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", 799 ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
803 ret);
804 return ret; 800 return ret;
805 } 801 }
806 802
807 if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
808 goto deepsleep;
809
810 /* sdio irq wakes up host */ 803 /* sdio irq wakes up host */
804 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
805 if (ret)
806 ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
807
808 return ret;
809}
810
811static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
812{
813 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
814 struct sdio_func *func = ar_sdio->func;
815 mmc_pm_flag_t flags;
816 int ret;
811 817
812 if (ar->state == ATH6KL_STATE_SCHED_SCAN) { 818 if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
819 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
820
821 ret = ath6kl_set_sdio_pm_caps(ar);
822 if (ret)
823 goto cut_pwr;
824
813 ret = ath6kl_cfg80211_suspend(ar, 825 ret = ath6kl_cfg80211_suspend(ar,
814 ATH6KL_CFG_SUSPEND_SCHED_SCAN, 826 ATH6KL_CFG_SUSPEND_SCHED_SCAN,
815 NULL); 827 NULL);
816 if (ret) {
817 ath6kl_warn("Schedule scan suspend failed: %d", ret);
818 return ret;
819 }
820
821 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
822 if (ret) 828 if (ret)
823 ath6kl_warn("set sdio wake irq flag failed: %d\n", ret); 829 goto cut_pwr;
824 830
825 return ret; 831 return 0;
826 } 832 }
827 833
828 if (wow) { 834 if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
829 /* 835 (!ar->suspend_mode && wow)) {
830 * The host sdio controller is capable of keep power and 836
831 * sdio irq wake up at this point. It's fine to continue 837 ret = ath6kl_set_sdio_pm_caps(ar);
832 * wow suspend operation. 838 if (ret)
833 */ 839 goto cut_pwr;
840
834 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); 841 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
835 if (ret) 842 if (ret)
836 return ret; 843 goto cut_pwr;
844
845 return 0;
846 }
847
848 if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
849 !ar->suspend_mode) {
837 850
838 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); 851 flags = sdio_get_host_pm_caps(func);
852 if (!(flags & MMC_PM_KEEP_POWER))
853 goto cut_pwr;
854
855 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
839 if (ret) 856 if (ret)
840 ath6kl_err("set sdio wake irq flag failed: %d\n", ret); 857 goto cut_pwr;
841 858
842 return ret; 859 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
860 NULL);
861 if (ret)
862 goto cut_pwr;
863
864 return 0;
843 } 865 }
844 866
845deepsleep: 867cut_pwr:
846 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL); 868 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
847} 869}
848 870
849static int ath6kl_sdio_resume(struct ath6kl *ar) 871static int ath6kl_sdio_resume(struct ath6kl *ar)