Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a48edc4 authored by Tim Kryger's avatar Tim Kryger Committed by Ulf Hansson
Browse files

mmc: sdhci: Use mmc core regulator infrastucture



Switch the common SDHCI code over to use mmc_host's regulator pointers
and remove the ones in the sdhci_host structure.  Additionally, use the
common mmc_regulator_get_supply function to get the regulators and set
the ocr_avail mask.

This change sets the ocr_avail directly based upon the voltage ranges
supported which ensures ocr_avail is set correctly while allowing the
use of regulators that can't provide exactly 1.8v, 3.0v, or 3.3v.

Signed-off-by: default avatarTim Kryger <tim.kryger@gmail.com>
Signed-off-by: default avatarMarkus Mayer <markus.mayer@linaro.org>
Reviewed-by: default avatarMatt Porter <mporter@linaro.org>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 2e42da59
Loading
Loading
Loading
Loading
+36 −61
Original line number Original line Diff line number Diff line
@@ -1223,6 +1223,7 @@ EXPORT_SYMBOL_GPL(sdhci_set_clock);
static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
			    unsigned short vdd)
			    unsigned short vdd)
{
{
	struct mmc_host *mmc = host->mmc;
	u8 pwr = 0;
	u8 pwr = 0;


	if (mode != MMC_POWER_OFF) {
	if (mode != MMC_POWER_OFF) {
@@ -1284,9 +1285,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
			mdelay(10);
			mdelay(10);
	}
	}


	if (host->vmmc) {
	if (!IS_ERR(mmc->supply.vmmc)) {
		spin_unlock_irq(&host->lock);
		spin_unlock_irq(&host->lock);
		mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd);
		mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, vdd);
		spin_lock_irq(&host->lock);
		spin_lock_irq(&host->lock);
	}
	}
}
}
@@ -1440,13 +1441,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
{
{
	unsigned long flags;
	unsigned long flags;
	u8 ctrl;
	u8 ctrl;
	struct mmc_host *mmc = host->mmc;


	spin_lock_irqsave(&host->lock, flags);
	spin_lock_irqsave(&host->lock, flags);


	if (host->flags & SDHCI_DEVICE_DEAD) {
	if (host->flags & SDHCI_DEVICE_DEAD) {
		spin_unlock_irqrestore(&host->lock, flags);
		spin_unlock_irqrestore(&host->lock, flags);
		if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
		if (!IS_ERR(mmc->supply.vmmc) &&
			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
		    ios->power_mode == MMC_POWER_OFF)
			mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, 0);
		return;
		return;
	}
	}


@@ -1707,6 +1710,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
						struct mmc_ios *ios)
						struct mmc_ios *ios)
{
{
	struct mmc_host *mmc = host->mmc;
	u16 ctrl;
	u16 ctrl;
	int ret;
	int ret;


@@ -1725,8 +1729,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
		ctrl &= ~SDHCI_CTRL_VDD_180;
		ctrl &= ~SDHCI_CTRL_VDD_180;
		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);


		if (host->vqmmc) {
		if (!IS_ERR(mmc->supply.vqmmc)) {
			ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
						    3600000);
			if (ret) {
			if (ret) {
				pr_warning("%s: Switching to 3.3V signalling voltage "
				pr_warning("%s: Switching to 3.3V signalling voltage "
						" failed\n", mmc_hostname(host->mmc));
						" failed\n", mmc_hostname(host->mmc));
@@ -1746,8 +1751,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,


		return -EAGAIN;
		return -EAGAIN;
	case MMC_SIGNAL_VOLTAGE_180:
	case MMC_SIGNAL_VOLTAGE_180:
		if (host->vqmmc) {
		if (!IS_ERR(mmc->supply.vqmmc)) {
			ret = regulator_set_voltage(host->vqmmc,
			ret = regulator_set_voltage(mmc->supply.vqmmc,
					1700000, 1950000);
					1700000, 1950000);
			if (ret) {
			if (ret) {
				pr_warning("%s: Switching to 1.8V signalling voltage "
				pr_warning("%s: Switching to 1.8V signalling voltage "
@@ -1776,8 +1781,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,


		return -EAGAIN;
		return -EAGAIN;
	case MMC_SIGNAL_VOLTAGE_120:
	case MMC_SIGNAL_VOLTAGE_120:
		if (host->vqmmc) {
		if (!IS_ERR(mmc->supply.vqmmc)) {
			ret = regulator_set_voltage(host->vqmmc, 1100000, 1300000);
			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
						    1300000);
			if (ret) {
			if (ret) {
				pr_warning("%s: Switching to 1.2V signalling voltage "
				pr_warning("%s: Switching to 1.2V signalling voltage "
						" failed\n", mmc_hostname(host->mmc));
						" failed\n", mmc_hostname(host->mmc));
@@ -2962,17 +2968,14 @@ int sdhci_add_host(struct sdhci_host *host)
	    !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
	    !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
		mmc->caps |= MMC_CAP_NEEDS_POLL;
		mmc->caps |= MMC_CAP_NEEDS_POLL;


	/* If there are external regulators, get them */
	if (mmc_regulator_get_supply(mmc) == -EPROBE_DEFER)
		return -EPROBE_DEFER;

	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
	host->vqmmc = regulator_get_optional(mmc_dev(mmc), "vqmmc");
	if (!IS_ERR(mmc->supply.vqmmc)) {
	if (IS_ERR_OR_NULL(host->vqmmc)) {
		ret = regulator_enable(mmc->supply.vqmmc);
		if (PTR_ERR(host->vqmmc) < 0) {
		if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
			pr_info("%s: no vqmmc regulator found\n",
				mmc_hostname(mmc));
			host->vqmmc = NULL;
		}
	} else {
		ret = regulator_enable(host->vqmmc);
		if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
						    1950000))
						    1950000))
			caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
			caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
					SDHCI_SUPPORT_SDR50 |
					SDHCI_SUPPORT_SDR50 |
@@ -2980,7 +2983,7 @@ int sdhci_add_host(struct sdhci_host *host)
		if (ret) {
		if (ret) {
			pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
			pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
				mmc_hostname(mmc), ret);
				mmc_hostname(mmc), ret);
			host->vqmmc = NULL;
			mmc->supply.vqmmc = NULL;
		}
		}
	}
	}


@@ -3041,34 +3044,6 @@ int sdhci_add_host(struct sdhci_host *host)


	ocr_avail = 0;
	ocr_avail = 0;


	host->vmmc = regulator_get_optional(mmc_dev(mmc), "vmmc");
	if (IS_ERR_OR_NULL(host->vmmc)) {
		if (PTR_ERR(host->vmmc) < 0) {
			pr_info("%s: no vmmc regulator found\n",
				mmc_hostname(mmc));
			host->vmmc = NULL;
		}
	}

#ifdef CONFIG_REGULATOR
	/*
	 * Voltage range check makes sense only if regulator reports
	 * any voltage value.
	 */
	if (host->vmmc && regulator_get_voltage(host->vmmc) > 0) {
		ret = regulator_is_supported_voltage(host->vmmc, 2700000,
			3600000);
		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
			caps[0] &= ~SDHCI_CAN_VDD_330;
		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
			caps[0] &= ~SDHCI_CAN_VDD_300;
		ret = regulator_is_supported_voltage(host->vmmc, 1700000,
			1950000);
		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
			caps[0] &= ~SDHCI_CAN_VDD_180;
	}
#endif /* CONFIG_REGULATOR */

	/*
	/*
	 * According to SD Host Controller spec v3.00, if the Host System
	 * According to SD Host Controller spec v3.00, if the Host System
	 * can afford more than 150mA, Host Driver should set XPC to 1. Also
	 * can afford more than 150mA, Host Driver should set XPC to 1. Also
@@ -3077,8 +3052,8 @@ int sdhci_add_host(struct sdhci_host *host)
	 * value.
	 * value.
	 */
	 */
	max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
	max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
	if (!max_current_caps && host->vmmc) {
	if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
		u32 curr = regulator_get_current_limit(host->vmmc);
		u32 curr = regulator_get_current_limit(mmc->supply.vmmc);
		if (curr > 0) {
		if (curr > 0) {


			/* convert to SDHCI_MAX_CURRENT format */
			/* convert to SDHCI_MAX_CURRENT format */
@@ -3118,8 +3093,11 @@ int sdhci_add_host(struct sdhci_host *host)
				   SDHCI_MAX_CURRENT_MULTIPLIER;
				   SDHCI_MAX_CURRENT_MULTIPLIER;
	}
	}


	if (mmc->ocr_avail)
		ocr_avail &= mmc->ocr_avail;

	if (host->ocr_mask)
	if (host->ocr_mask)
		ocr_avail = host->ocr_mask;
		ocr_avail &= host->ocr_mask;


	mmc->ocr_avail = ocr_avail;
	mmc->ocr_avail = ocr_avail;
	mmc->ocr_avail_sdio = ocr_avail;
	mmc->ocr_avail_sdio = ocr_avail;
@@ -3273,6 +3251,7 @@ EXPORT_SYMBOL_GPL(sdhci_add_host);


void sdhci_remove_host(struct sdhci_host *host, int dead)
void sdhci_remove_host(struct sdhci_host *host, int dead)
{
{
	struct mmc_host *mmc = host->mmc;
	unsigned long flags;
	unsigned long flags;


	if (dead) {
	if (dead) {
@@ -3310,15 +3289,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)


	tasklet_kill(&host->finish_tasklet);
	tasklet_kill(&host->finish_tasklet);


	if (host->vmmc) {
	if (!IS_ERR(mmc->supply.vmmc))
		regulator_disable(host->vmmc);
		regulator_disable(mmc->supply.vmmc);
		regulator_put(host->vmmc);
	}


	if (host->vqmmc) {
	if (!IS_ERR(mmc->supply.vqmmc))
		regulator_disable(host->vqmmc);
		regulator_disable(mmc->supply.vqmmc);
		regulator_put(host->vqmmc);
	}


	if (host->adma_desc)
	if (host->adma_desc)
		dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
		dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+0 −3
Original line number Original line Diff line number Diff line
@@ -104,9 +104,6 @@ struct sdhci_host {


	const struct sdhci_ops *ops;	/* Low level hw interface */
	const struct sdhci_ops *ops;	/* Low level hw interface */


	struct regulator *vmmc;		/* Power regulator (vmmc) */
	struct regulator *vqmmc;	/* Signaling regulator (vccq) */

	/* Internal data */
	/* Internal data */
	struct mmc_host *mmc;	/* MMC structure */
	struct mmc_host *mmc;	/* MMC structure */
	u64 dma_mask;		/* custom DMA mask */
	u64 dma_mask;		/* custom DMA mask */