mmc: sdio: don't power up cards on system suspend
authorOhad Ben-Cohen <ohad@wizery.com>
Sun, 28 Nov 2010 05:21:30 +0000 (07:21 +0200)
committerChris Ball <cjb@laptop.org>
Sun, 9 Jan 2011 03:48:13 +0000 (22:48 -0500)
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>
drivers/mmc/core/core.c
drivers/mmc/core/sdio_bus.c

index 9683d4d..241ffb2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.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)) {
                        mmc_power_up(host);
                        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);
                err = host->bus_ops->resume(host);
index 203da44..d29b9c3 100644 (file)
@@ -197,44 +197,12 @@ out:
 
 #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 = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
                pm_generic_runtime_idle
        )
-       .prepare = sdio_bus_pm_prepare,
 };
 
 #define SDIO_PM_OPS_PTR        (&sdio_bus_pm_ops)