summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/sdio.c')
-rw-r--r--drivers/mmc/core/sdio.c54
1 files changed, 29 insertions, 25 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index f4c8637fd07..cdb845b68ab 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -302,6 +302,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto err;
}
card = oldcard;
+ return 0;
}
/*
@@ -399,62 +400,65 @@ static void mmc_sdio_detect(struct mmc_host *host)
* Therefore all registered functions must have drivers with suspend
* and resume methods. Failing that we simply remove the whole card.
*/
-static void mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_suspend(struct mmc_host *host)
{
- int i;
+ int i, err = 0;
- /* make sure all registered functions can suspend/resume */
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;
if (!pmops || !pmops->suspend || !pmops->resume) {
- /* just remove the entire card in that case */
- mmc_sdio_remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
- return;
- }
+ /* force removal of entire card in that case */
+ err = -ENOSYS;
+ } else
+ err = pmops->suspend(&func->dev);
+ if (err)
+ break;
}
}
-
- /* now suspend them */
- for (i = 0; i < host->card->sdio_funcs; i++) {
+ 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->suspend(&func->dev);
+ pmops->resume(&func->dev);
}
}
+
+ return err;
}
-static void mmc_sdio_resume(struct mmc_host *host)
+static int mmc_sdio_resume(struct mmc_host *host)
{
int i, err;
BUG_ON(!host);
BUG_ON(!host->card);
+ /* Basic card reinitialization. */
mmc_claim_host(host);
err = mmc_sdio_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- if (err) {
- mmc_sdio_remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
- return;
- }
- /* resume all functions */
- for (i = 0; i < host->card->sdio_funcs; i++) {
+ /*
+ * 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;
- pmops->resume(&func->dev);
+ err = pmops->resume(&func->dev);
}
}
+
+ return err;
}
static const struct mmc_bus_ops mmc_sdio_ops = {