Commit 573185cc authored by Ulf Hansson's avatar Ulf Hansson Committed by Chris Ball

mmc: core: Invoke sdio func driver's PM callbacks from the sdio bus

The sdio func device is added to the driver model after the card
device.

This means the sdio func device will be suspend before the card device
and thus resumed after. The consequence are the mmc core don't
explicity need to protect itself from receiving sdio requests in
suspended state. Instead that can be handled from the sdio bus, which
is thus invokes the PM callbacks instead of old dummy function.

In the case were the sdio func driver don't implement the PM callbacks
the mmc core will in the early phase of system suspend, remove the
card from the driver model and thus power off it.

Cc: Aaron Lu <aaron.lu@intel.com>
Cc: NeilBrown <neilb@suse.de>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarAaron Lu <aaron.lu@intel.com>
Tested-by: default avatarxiaoming wang <xiaoming.wang@intel.com>
Tested-by: default avatarChuanxiao Dong <chuanxiao.dong@intel.com>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent f7bf11a3
...@@ -943,40 +943,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) ...@@ -943,40 +943,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
*/ */
static int mmc_sdio_suspend(struct mmc_host *host) static int mmc_sdio_suspend(struct mmc_host *host)
{ {
int i, err = 0; if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->suspend(&func->dev);
if (err)
break;
}
}
while (err && --i >= 0) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
pmops->resume(&func->dev);
}
}
if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
mmc_claim_host(host); mmc_claim_host(host);
sdio_disable_wide(host->card); sdio_disable_wide(host->card);
mmc_release_host(host); mmc_release_host(host);
} }
if (!err && !mmc_card_keep_power(host)) if (!mmc_card_keep_power(host))
mmc_power_off(host); mmc_power_off(host);
return err; return 0;
} }
static int mmc_sdio_resume(struct mmc_host *host) static int mmc_sdio_resume(struct mmc_host *host)
{ {
int i, err = 0; int err = 0;
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
...@@ -1019,24 +1000,6 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -1019,24 +1000,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
mmc_release_host(host); mmc_release_host(host);
/*
* If the card looked to be the same as before suspending, then
* we proceed to resume all card functions. If one of them returns
* an error then we simply return that error to the core and the
* card will be redetected as new. It is the responsibility of
* the function driver to perform further tests with the extra
* knowledge it has of the card to confirm the card is indeed the
* same as before suspending (same MAC address for network cards,
* etc.) and return an error otherwise.
*/
for (i = 0; !err && i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->resume(&func->dev);
}
}
host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err; return err;
} }
......
...@@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev) ...@@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int pm_no_operation(struct device *dev)
{
/*
* Prevent the PM core from calling SDIO device drivers' suspend
* callback routines, which it is not supposed to do, by using this
* empty function as the bus type suspend callaback for SDIO.
*/
return 0;
}
#endif
static const struct dev_pm_ops sdio_bus_pm_ops = { static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment