summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/sdio.c
diff options
context:
space:
mode:
authorKalle Valo <kvalo@qca.qualcomm.com>2011-11-01 08:44:44 +0200
committerKalle Valo <kvalo@qca.qualcomm.com>2011-11-11 12:59:00 +0200
commitb4b2a0b116d79510640622a5f28f219065e61b03 (patch)
tree1d889cf3c4669165af7697c3737ca45431fa96c1 /drivers/net/wireless/ath/ath6kl/sdio.c
parente28e810486a6826417e77e634666f0dfc2bfe548 (diff)
downloadlinux-b4b2a0b116d79510640622a5f28f219065e61b03.tar.bz2
ath6kl: cut power during suspend
If sdio controller doesn't support keep power, cut power from hardware during suspend and restart firmware during resume. If we are connected during suspend, send a disconnected event to user space. Earlier suspend failed with an error if sdio didn't support keep power. Now suspend will happen succesfully even with that case. 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.c64
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index b02ecea0cc0d..ccb888b41c46 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -782,12 +782,11 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
flags = sdio_get_host_pm_caps(func);
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
+
if (!(flags & MMC_PM_KEEP_POWER)) {
- /* as host doesn't support keep power we need to bail out */
- ath6kl_dbg(ATH6KL_DBG_SDIO,
- "func %d doesn't support MMC_PM_KEEP_POWER\n",
- func->num);
- return -EINVAL;
+ /* as host doesn't support keep power we need to cut power */
+ return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER);
}
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
@@ -797,13 +796,30 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
return ret;
}
- ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP);
-
- return 0;
+ return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP);
}
static int ath6kl_sdio_resume(struct ath6kl *ar)
{
+ switch (ar->state) {
+ case ATH6KL_STATE_OFF:
+ case ATH6KL_STATE_CUTPOWER:
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND,
+ "sdio resume configuring sdio\n");
+
+ /* need to set sdio settings after power is cut from sdio */
+ ath6kl_sdio_config(ar);
+ break;
+
+ case ATH6KL_STATE_ON:
+ /* we shouldn't be on this state during resume */
+ WARN_ON(1);
+ break;
+
+ case ATH6KL_STATE_DEEPSLEEP:
+ break;
+ }
+
ath6kl_cfg80211_resume(ar);
return 0;
@@ -858,6 +874,37 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.stop = ath6kl_sdio_stop,
};
+#ifdef CONFIG_PM_SLEEP
+
+/*
+ * Empty handlers so that mmc subsystem doesn't remove us entirely during
+ * suspend. We instead follow cfg80211 suspend/resume handlers.
+ */
+static int ath6kl_sdio_pm_suspend(struct device *device)
+{
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio pm suspend\n");
+
+ return 0;
+}
+
+static int ath6kl_sdio_pm_resume(struct device *device)
+{
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio pm resume\n");
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ath6kl_sdio_pm_ops, ath6kl_sdio_pm_suspend,
+ ath6kl_sdio_pm_resume);
+
+#define ATH6KL_SDIO_PM_OPS (&ath6kl_sdio_pm_ops)
+
+#else
+
+#define ATH6KL_SDIO_PM_OPS NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
static int ath6kl_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -969,6 +1016,7 @@ static struct sdio_driver ath6kl_sdio_driver = {
.id_table = ath6kl_sdio_devices,
.probe = ath6kl_sdio_probe,
.remove = ath6kl_sdio_remove,
+ .drv.pm = ATH6KL_SDIO_PM_OPS,
};
static int __init ath6kl_sdio_init(void)