/* 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;
}
예제 #2
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;
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
파일: core.c 프로젝트: Mcjesus15/Zio_Kernel
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;
}