if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend)
err = host->bus_ops->suspend(host);
-
- if (err == -ENOSYS || !host->bus_ops->resume) {
- /*
- * We simply "remove" the card in this case.
- * It will be redetected on resume. (Calling
- * bus_ops->remove() with a claimed host can
- * deadlock.)
- */
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- err = 0;
- }
}
mmc_bus_put(host);
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
+ int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work_sync(&host->detect);
- if (!host->bus_ops || host->bus_ops->suspend)
+ if (!host->bus_ops)
+ break;
+
+ /* Validate prerequisites for suspend */
+ if (host->bus_ops->pre_suspend)
+ err = host->bus_ops->pre_suspend(host);
+ if (!err && host->bus_ops->suspend)
break;
/* Calling bus_ops->remove() with a claimed host can deadlock */
struct mmc_bus_ops {
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
+ int (*pre_suspend)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
}
/*
- * SDIO suspend. We need to suspend all functions separately.
+ * SDIO pre_suspend. We need to suspend all functions separately.
* Therefore all registered functions must have drivers with suspend
* and resume methods. Failing that we simply remove the whole card.
*/
-static int mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_pre_suspend(struct mmc_host *host)
{
int i, err = 0;
if (!pmops || !pmops->suspend || !pmops->resume) {
/* force removal of entire card in that case */
err = -ENOSYS;
- } else
- err = pmops->suspend(&func->dev);
+ break;
+ }
+ }
+ }
+
+ return err;
+}
+
+/*
+ * SDIO suspend. Suspend all functions separately.
+ */
+static int mmc_sdio_suspend(struct mmc_host *host)
+{
+ int i, err = 0;
+
+ 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;
}
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
+ .pre_suspend = mmc_sdio_pre_suspend,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,