Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[cascardo/linux.git] / drivers / mmc / host / mmci.c
index bf7c05b..705a589 100644 (file)
 #include <linux/clk.h>
 #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>
 #include <asm/io.h>
 #include <asm/sizes.h>
-#include <asm/mach/mmc.h>
 
 #include "mmci.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;
@@ -537,7 +553,7 @@ static void mmci_check_status(unsigned long data)
 
 static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 {
-       struct mmc_platform_data *plat = dev->dev.platform_data;
+       struct mmci_platform_data *plat = dev->dev.platform_data;
        struct mmci_host *host;
        struct mmc_host *mmc;
        int ret;
@@ -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;
 
        /*
@@ -640,7 +678,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
-#ifdef CONFIG_GPIOLIB
        if (gpio_is_valid(plat->gpio_cd)) {
                ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
                if (ret == 0)
@@ -659,7 +696,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                else if (ret != -ENOSYS)
                        goto err_gpio_wp;
        }
-#endif
 
        ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
        if (ret)
@@ -741,6 +777,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);