/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) { if (!mmc_try_claim_host(host->mmc)) return 0; if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) { mmc_release_host(host->mmc); return 0; } mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); host->vdd = 0; host->power_mode = MMC_POWER_OFF; dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); host->dpm_state = OFF; mmc_release_host(host->mmc); return 0; }
/** * mmc_suspend_host - suspend a host * @host: mmc host */ int mmc_suspend_host(struct mmc_host *host) { int err = 0; if (mmc_bus_needs_resume(host)) return 0; if (host->caps & MMC_CAP_DISABLE) cancel_delayed_work(&host->disable); mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { /* * A long response time is not acceptable for device drivers * when doing suspend. Prevent mmc_claim_host in the suspend * sequence, to potentially wait "forever" by trying to * pre-claim the host. * * Skip try claim host for SDIO cards, doing so fixes deadlock * conditions. The function driver suspend may again call into * SDIO driver within a different context for enabling power * save mode in the card and hence wait in mmc_claim_host * causing deadlock. */ if (!(host->card && mmc_card_sdio(host->card))) if (!mmc_try_claim_host(host)) err = -EBUSY; if (!err) { if (host->bus_ops->suspend) err = host->bus_ops->suspend(host); if (!(host->card && mmc_card_sdio(host->card))) mmc_do_release_host(host); if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. * It will be redetected on resume. */ if (host->bus_ops->remove) 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); if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER)) mmc_power_off(host); return err; }
void mmc_host_deeper_disable(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, disable.work); /* If the host is claimed then we do not want to disable it anymore */ if (!mmc_try_claim_host(host)) return; mmc_host_do_disable(host, 1); mmc_do_release_host(host); }
void mmc_host_deeper_disable(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, disable.work); /* If the host is claimed then we do not want to disable it anymore */ if (!mmc_try_claim_host(host)) goto out; mmc_host_do_disable(host, 1); mmc_do_release_host(host); out: wake_unlock(&mmc_delayed_work_wake_lock); }
void mmc_host_deeper_disable(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, disable.work); /* If the host is claimed then we do not want to disable it anymore */ if (!mmc_try_claim_host(host)) goto out; mmc_host_do_disable(host, 1); mmc_do_release_host(host); out: #if 0 //Robert, 20101006, KB62_CR766 : Fix unexpectedly remove SD card issue wake_unlock(&mmc_delayed_work_wake_lock); #endif printk(KERN_ERR "mmc_try_claim_host(host) = 0\n"); }
static int sprd_mmc_host_runtime_suspend(struct device *dev) { int rc = -EBUSY; unsigned long flags; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct sdhci_host *host = platform_get_drvdata(pdev); struct mmc_host *mmc = host->mmc; if(dev->driver != NULL) { if(mmc_try_claim_host(mmc)) { sdhci_runtime_suspend_host(host); spin_lock_irqsave(&host->lock, flags); if(host->ops->set_clock) host->ops->set_clock(host, 0); spin_unlock_irqrestore(&host->lock, flags); mmc_do_release_host(mmc); rc = 0; } } return rc; }
/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */ static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) { int err, new_state; if (!mmc_try_claim_host(host->mmc)) return 0; clk_enable(host->fclk); omap_hsmmc_context_restore(host); if (mmc_card_can_sleep(host->mmc)) { err = mmc_card_sleep(host->mmc); if (err < 0) { clk_disable(host->fclk); mmc_release_host(host->mmc); return err; } new_state = CARDSLEEP; } else { new_state = REGSLEEP; } if (mmc_slot(host).set_sleep) mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0, new_state == CARDSLEEP); /* FIXME: turn off bus power and perhaps interrupts too */ clk_disable(host->fclk); host->dpm_state = new_state; mmc_release_host(host->mmc); dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && mmc_slot(host).get_cover_state(host->dev, host->slot_id))) return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT); return 0; }
/* Handler for [SLEEP -> ENABLED] transition */ static int omap_hsmmc_sleep_to_enabled(struct omap_hsmmc_host *host) { if (!mmc_try_claim_host(host->mmc)) return 0; clk_enable(host->fclk); omap_hsmmc_context_restore(host); if (mmc_slot(host).set_sleep) mmc_slot(host).set_sleep(host->dev, host->slot_id, 0, host->vdd, host->dpm_state == CARDSLEEP); if (mmc_card_can_sleep(host->mmc)) mmc_card_awake(host->mmc); dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); host->dpm_state = ENABLED; mmc_release_host(host->mmc); return 0; }