Skip to content

Commit

Permalink
ath6kl: cut power during suspend
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kalle Valo committed Nov 11, 2011
1 parent e28e810 commit b4b2a0b
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 8 deletions.
31 changes: 31 additions & 0 deletions drivers/net/wireless/ath/ath6kl/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,28 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
ar->state = ATH6KL_STATE_DEEPSLEEP;

break;

case ATH6KL_CFG_SUSPEND_CUTPOWER:
if (ar->state == ATH6KL_STATE_OFF) {
ath6kl_dbg(ATH6KL_DBG_SUSPEND,
"suspend hw off, no action for cutpower\n");
break;
}

ath6kl_dbg(ATH6KL_DBG_SUSPEND, "suspend cutting power\n");

ret = ath6kl_init_hw_stop(ar);
if (ret) {
ath6kl_warn("failed to stop hw during suspend: %d\n",
ret);
}

ar->state = ATH6KL_STATE_CUTPOWER;

break;

default:
break;
}

return 0;
Expand All @@ -1698,6 +1720,15 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)

break;

case ATH6KL_STATE_CUTPOWER:
ath6kl_dbg(ATH6KL_DBG_SUSPEND, "resume restoring power\n");

ret = ath6kl_init_hw_start(ar);
if (ret) {
ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
return ret;
}

default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath6kl/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
ATH6KL_CFG_SUSPEND_CUTPOWER,
};

struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath6kl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ enum ath6kl_state {
ATH6KL_STATE_OFF,
ATH6KL_STATE_ON,
ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER,
};

struct ath6kl {
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath6kl/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_SDIO_DUMP = BIT(17),
ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
ATH6KL_DBG_WMI_DUMP = BIT(19),
ATH6KL_DBG_SUSPEND = BIT(20),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
};

Expand Down
64 changes: 56 additions & 8 deletions drivers/net/wireless/ath/ath6kl/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit b4b2a0b

Please sign in to comment.