forked from Minki/linux
mmc: sdio: don't power up cards on system suspend
Initial SDIO runtime PM implementation took a conservative approach of powering up cards (and fully reinitializing them) on system suspend, just before the suspend handlers of the relevant drivers were executed. To avoid redundant power and reinitialization cycles, this patch removes this behavior: if a card is already powered off when system suspend kicks in, it is left at that state. If a card is active when a system sleep starts, everything is straightforward and works exactly like before. But if the card was already suspended before the sleep began, then when the MMC core powers it back up on resume, its run-time PM status has to be updated to reflect the actual post-system sleep status. The technique to do that is borrowed from the I2C runtime PM implementation (for more info see Documentation/power/runtime_pm.txt). Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com> Reviewed-by: Chris Ball <cjb@laptop.org> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
parent
30201e7f3a
commit
e594573d79
@ -22,6 +22,7 @@
|
|||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <linux/mmc/card.h>
|
#include <linux/mmc/card.h>
|
||||||
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
||||||
@ -1785,6 +1786,18 @@ int mmc_resume_host(struct mmc_host *host)
|
|||||||
if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
|
if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
|
||||||
mmc_power_up(host);
|
mmc_power_up(host);
|
||||||
mmc_select_voltage(host, host->ocr);
|
mmc_select_voltage(host, host->ocr);
|
||||||
|
/*
|
||||||
|
* Tell runtime PM core we just powered up the card,
|
||||||
|
* since it still believes the card is powered off.
|
||||||
|
* Note that currently runtime PM is only enabled
|
||||||
|
* for SDIO cards that are MMC_CAP_POWER_OFF_CARD
|
||||||
|
*/
|
||||||
|
if (mmc_card_sdio(host->card) &&
|
||||||
|
(host->caps & MMC_CAP_POWER_OFF_CARD)) {
|
||||||
|
pm_runtime_disable(&host->card->dev);
|
||||||
|
pm_runtime_set_active(&host->card->dev);
|
||||||
|
pm_runtime_enable(&host->card->dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BUG_ON(!host->bus_ops->resume);
|
BUG_ON(!host->bus_ops->resume);
|
||||||
err = host->bus_ops->resume(host);
|
err = host->bus_ops->resume(host);
|
||||||
|
@ -197,44 +197,12 @@ out:
|
|||||||
|
|
||||||
#ifdef CONFIG_PM_RUNTIME
|
#ifdef CONFIG_PM_RUNTIME
|
||||||
|
|
||||||
static int sdio_bus_pm_prepare(struct device *dev)
|
|
||||||
{
|
|
||||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resume an SDIO device which was suspended at run time at this
|
|
||||||
* point, in order to allow standard SDIO suspend/resume paths
|
|
||||||
* to keep working as usual.
|
|
||||||
*
|
|
||||||
* Ultimately, the SDIO driver itself will decide (in its
|
|
||||||
* suspend handler, or lack thereof) whether the card should be
|
|
||||||
* removed or kept, and if kept, at what power state.
|
|
||||||
*
|
|
||||||
* At this point, PM core have increased our use count, so it's
|
|
||||||
* safe to directly resume the device. After system is resumed
|
|
||||||
* again, PM core will drop back its runtime PM use count, and if
|
|
||||||
* needed device will be suspended again.
|
|
||||||
*
|
|
||||||
* The end result is guaranteed to be a power state that is
|
|
||||||
* coherent with the device's runtime PM use count.
|
|
||||||
*
|
|
||||||
* The return value of pm_runtime_resume is deliberately unchecked
|
|
||||||
* since there is little point in failing system suspend if a
|
|
||||||
* device can't be resumed.
|
|
||||||
*/
|
|
||||||
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
|
|
||||||
pm_runtime_resume(dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct dev_pm_ops sdio_bus_pm_ops = {
|
static const struct dev_pm_ops sdio_bus_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(
|
SET_RUNTIME_PM_OPS(
|
||||||
pm_generic_runtime_suspend,
|
pm_generic_runtime_suspend,
|
||||||
pm_generic_runtime_resume,
|
pm_generic_runtime_resume,
|
||||||
pm_generic_runtime_idle
|
pm_generic_runtime_idle
|
||||||
)
|
)
|
||||||
.prepare = sdio_bus_pm_prepare,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
|
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
|
||||||
|
Loading…
Reference in New Issue
Block a user