|
@@ -23,6 +23,7 @@
|
|
|
#include <linux/scatterlist.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/amba/mmci.h>
|
|
|
+#include <linux/regulator/consumer.h>
|
|
|
|
|
|
#include <asm/cacheflush.h>
|
|
|
#include <asm/div64.h>
|
|
@@ -452,13 +453,28 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|
|
u32 pwr = 0;
|
|
|
unsigned long flags;
|
|
|
|
|
|
- if (host->plat->translate_vdd)
|
|
|
- pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
|
|
|
-
|
|
|
switch (ios->power_mode) {
|
|
|
case MMC_POWER_OFF:
|
|
|
+ if(host->vcc &&
|
|
|
+ regulator_is_enabled(host->vcc))
|
|
|
+ regulator_disable(host->vcc);
|
|
|
break;
|
|
|
case MMC_POWER_UP:
|
|
|
+#ifdef CONFIG_REGULATOR
|
|
|
+ if (host->vcc)
|
|
|
+ /* This implicitly enables the regulator */
|
|
|
+ mmc_regulator_set_ocr(host->vcc, ios->vdd);
|
|
|
+#endif
|
|
|
+ /*
|
|
|
+ * The translate_vdd function is not used if you have
|
|
|
+ * an external regulator, or your design is really weird.
|
|
|
+ * Using it would mean sending in power control BOTH using
|
|
|
+ * a regulator AND the 4 MMCIPWR bits. If we don't have
|
|
|
+ * a regulator, we might have some other platform specific
|
|
|
+ * power control behind this translate function.
|
|
|
+ */
|
|
|
+ if (!host->vcc && host->plat->translate_vdd)
|
|
|
+ pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
|
|
|
/* The ST version does not have this, fall through to POWER_ON */
|
|
|
if (host->hw_designer != AMBA_VENDOR_ST) {
|
|
|
pwr |= MCI_PWR_UP;
|
|
@@ -603,7 +619,29 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
|
|
|
mmc->ops = &mmci_ops;
|
|
|
mmc->f_min = (host->mclk + 511) / 512;
|
|
|
mmc->f_max = min(host->mclk, fmax);
|
|
|
- mmc->ocr_avail = plat->ocr_mask;
|
|
|
+#ifdef CONFIG_REGULATOR
|
|
|
+ /* If we're using the regulator framework, try to fetch a regulator */
|
|
|
+ host->vcc = regulator_get(&dev->dev, "vmmc");
|
|
|
+ if (IS_ERR(host->vcc))
|
|
|
+ host->vcc = NULL;
|
|
|
+ else {
|
|
|
+ int mask = mmc_regulator_get_ocrmask(host->vcc);
|
|
|
+
|
|
|
+ if (mask < 0)
|
|
|
+ dev_err(&dev->dev, "error getting OCR mask (%d)\n",
|
|
|
+ mask);
|
|
|
+ else {
|
|
|
+ host->mmc->ocr_avail = (u32) mask;
|
|
|
+ if (plat->ocr_mask)
|
|
|
+ dev_warn(&dev->dev,
|
|
|
+ "Provided ocr_mask/setpower will not be used "
|
|
|
+ "(using regulator instead)\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ /* Fall back to platform data if no regulator is found */
|
|
|
+ if (host->vcc == NULL)
|
|
|
+ mmc->ocr_avail = plat->ocr_mask;
|
|
|
mmc->caps = plat->capabilities;
|
|
|
|
|
|
/*
|
|
@@ -741,6 +779,10 @@ static int __devexit mmci_remove(struct amba_device *dev)
|
|
|
clk_disable(host->clk);
|
|
|
clk_put(host->clk);
|
|
|
|
|
|
+ if (regulator_is_enabled(host->vcc))
|
|
|
+ regulator_disable(host->vcc);
|
|
|
+ regulator_put(host->vcc);
|
|
|
+
|
|
|
mmc_free_host(mmc);
|
|
|
|
|
|
amba_release_regions(dev);
|