diff options
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 46 | 
1 files changed, 41 insertions, 5 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 430095725f9..d7d7109ef47 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -27,6 +27,7 @@  #include <linux/err.h>  #include <linux/mmc/host.h>  #include <linux/io.h> +#include <linux/regulator/consumer.h>  #include <asm/sizes.h> @@ -67,8 +68,42 @@ struct pxamci_host {  	unsigned int		dma_dir;  	unsigned int		dma_drcmrrx;  	unsigned int		dma_drcmrtx; + +	struct regulator	*vcc;  }; +static inline void pxamci_init_ocr(struct pxamci_host *host) +{ +#ifdef CONFIG_REGULATOR +	host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + +	if (IS_ERR(host->vcc)) +		host->vcc = NULL; +	else { +		host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); +		if (host->pdata && host->pdata->ocr_mask) +			dev_warn(mmc_dev(host->mmc), +				"ocr_mask/setpower will not be used\n"); +	} +#endif +	if (host->vcc == NULL) { +		/* fall-back to platform data */ +		host->mmc->ocr_avail = host->pdata ? +			host->pdata->ocr_mask : +			MMC_VDD_32_33 | MMC_VDD_33_34; +	} +} + +static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) +{ +#ifdef CONFIG_REGULATOR +	if (host->vcc) +		mmc_regulator_set_ocr(host->vcc, vdd); +#endif +	if (!host->vcc && host->pdata && host->pdata->setpower) +		host->pdata->setpower(mmc_dev(host->mmc), vdd); +} +  static void pxamci_stop_clock(struct pxamci_host *host)  {  	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { @@ -438,8 +473,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	if (host->power_mode != ios->power_mode) {  		host->power_mode = ios->power_mode; -		if (host->pdata && host->pdata->setpower) -			host->pdata->setpower(mmc_dev(mmc), ios->vdd); +		pxamci_set_power(host, ios->vdd);  		if (ios->power_mode == MMC_POWER_ON)  			host->cmdat |= CMDAT_INIT; @@ -562,9 +596,8 @@ static int pxamci_probe(struct platform_device *pdev)  	mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000  							  : host->clkrate; -	mmc->ocr_avail = host->pdata ? -			 host->pdata->ocr_mask : -			 MMC_VDD_32_33|MMC_VDD_33_34; +	pxamci_init_ocr(host); +  	mmc->caps = 0;  	host->cmdat = 0;  	if (!cpu_is_pxa25x()) { @@ -661,6 +694,9 @@ static int pxamci_remove(struct platform_device *pdev)  	if (mmc) {  		struct pxamci_host *host = mmc_priv(mmc); +		if (host->vcc) +			regulator_put(host->vcc); +  		if (host->pdata && host->pdata->exit)  			host->pdata->exit(&pdev->dev, mmc);  |