Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4b2a0b1 authored by Kalle Valo's avatar Kalle Valo
Browse files

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: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent e28e8104
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
	}
+1 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -454,6 +454,7 @@ enum ath6kl_state {
	ATH6KL_STATE_OFF,
	ATH6KL_STATE_ON,
	ATH6KL_STATE_DEEPSLEEP,
	ATH6KL_STATE_CUTPOWER,
};

struct ath6kl {
+1 −0
Original line number Diff line number Diff line
@@ -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 */
};

+56 −8
Original line number Diff line number Diff line
@@ -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)