aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2014-02-28 06:49:00 -0500
committerChris Ball <chris@printf.net>2014-04-22 07:06:40 -0400
commit573185cc7e646fdd5da12702ba5383e91cc25ef3 (patch)
treede598dc7d6854ec38208a4f5f1f2f0df6984daf0
parentf7bf11a3a2e0ee829a262b4b0bb09c2bb40cf6fa (diff)
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: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Aaron Lu <aaron.lu@intel.com> Tested-by: xiaoming wang <xiaoming.wang@intel.com> Tested-by: Chuanxiao Dong <chuanxiao.dong@intel.com> Signed-off-by: Chris Ball <chris@printf.net>
-rw-r--r--drivers/mmc/core/sdio.c45
-rw-r--r--drivers/mmc/core/sdio_bus.c14
2 files changed, 5 insertions, 54 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6e2af0..9933e426bc36 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -943,40 +943,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
943 */ 943 */
944static int mmc_sdio_suspend(struct mmc_host *host) 944static int mmc_sdio_suspend(struct mmc_host *host)
945{ 945{
946 int i, err = 0; 946 if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
947
948 for (i = 0; i < host->card->sdio_funcs; i++) {
949 struct sdio_func *func = host->card->sdio_func[i];
950 if (func && sdio_func_present(func) && func->dev.driver) {
951 const struct dev_pm_ops *pmops = func->dev.driver->pm;
952 err = pmops->suspend(&func->dev);
953 if (err)
954 break;
955 }
956 }
957 while (err && --i >= 0) {
958 struct sdio_func *func = host->card->sdio_func[i];
959 if (func && sdio_func_present(func) && func->dev.driver) {
960 const struct dev_pm_ops *pmops = func->dev.driver->pm;
961 pmops->resume(&func->dev);
962 }
963 }
964
965 if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
966 mmc_claim_host(host); 947 mmc_claim_host(host);
967 sdio_disable_wide(host->card); 948 sdio_disable_wide(host->card);
968 mmc_release_host(host); 949 mmc_release_host(host);
969 } 950 }
970 951
971 if (!err && !mmc_card_keep_power(host)) 952 if (!mmc_card_keep_power(host))
972 mmc_power_off(host); 953 mmc_power_off(host);
973 954
974 return err; 955 return 0;
975} 956}
976 957
977static int mmc_sdio_resume(struct mmc_host *host) 958static int mmc_sdio_resume(struct mmc_host *host)
978{ 959{
979 int i, err = 0; 960 int err = 0;
980 961
981 BUG_ON(!host); 962 BUG_ON(!host);
982 BUG_ON(!host->card); 963 BUG_ON(!host->card);
@@ -1019,24 +1000,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
1019 wake_up_process(host->sdio_irq_thread); 1000 wake_up_process(host->sdio_irq_thread);
1020 mmc_release_host(host); 1001 mmc_release_host(host);
1021 1002
1022 /*
1023 * If the card looked to be the same as before suspending, then
1024 * we proceed to resume all card functions. If one of them returns
1025 * an error then we simply return that error to the core and the
1026 * card will be redetected as new. It is the responsibility of
1027 * the function driver to perform further tests with the extra
1028 * knowledge it has of the card to confirm the card is indeed the
1029 * same as before suspending (same MAC address for network cards,
1030 * etc.) and return an error otherwise.
1031 */
1032 for (i = 0; !err && i < host->card->sdio_funcs; i++) {
1033 struct sdio_func *func = host->card->sdio_func[i];
1034 if (func && sdio_func_present(func) && func->dev.driver) {
1035 const struct dev_pm_ops *pmops = func->dev.driver->pm;
1036 err = pmops->resume(&func->dev);
1037 }
1038 }
1039
1040 host->pm_flags &= ~MMC_PM_KEEP_POWER; 1003 host->pm_flags &= ~MMC_PM_KEEP_POWER;
1041 return err; 1004 return err;
1042} 1005}
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 92d1ba8e8153..4fa8fef9147f 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev)
197 197
198#ifdef CONFIG_PM 198#ifdef CONFIG_PM
199 199
200#ifdef CONFIG_PM_SLEEP
201static int pm_no_operation(struct device *dev)
202{
203 /*
204 * Prevent the PM core from calling SDIO device drivers' suspend
205 * callback routines, which it is not supposed to do, by using this
206 * empty function as the bus type suspend callaback for SDIO.
207 */
208 return 0;
209}
210#endif
211
212static const struct dev_pm_ops sdio_bus_pm_ops = { 200static const struct dev_pm_ops sdio_bus_pm_ops = {
213 SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) 201 SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
214 SET_RUNTIME_PM_OPS( 202 SET_RUNTIME_PM_OPS(
215 pm_generic_runtime_suspend, 203 pm_generic_runtime_suspend,
216 pm_generic_runtime_resume, 204 pm_generic_runtime_resume,