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:
Ohad Ben-Cohen 2010-11-28 07:21:30 +02:00 committed by Chris Ball
parent 30201e7f3a
commit e594573d79
2 changed files with 13 additions and 32 deletions

View File

@ -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);

View File

@ -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)