aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2009-09-22 09:41:40 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-09-22 15:49:05 -0400
commit34e84f39a27d059a3e6ec6e8b94aafa702e6f220 (patch)
tree263bf7ee2a9f6b4ce86f89a82806fb73ff3c41d7 /drivers
parent6ef297f86b62f187c59475784208f75c2ed8ccd8 (diff)
ARM: 5721/1: MMCI enable the use of a regulator
This enables the use of a regulator to power the MMCI/PL180 PrimeCell. The OCR mask is calculated and voltage is set using the new MMC core functions for discovering voltage ranges in regulators. The platform translate_vdd function which basically controls the 4 lines out of the PL180 is disabled if you use a regulator instead. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/mmci.c50
-rw-r--r--drivers/mmc/host/mmci.h1
2 files changed, 47 insertions, 4 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 79205e565c07..3d1e5329da12 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -23,6 +23,7 @@
23#include <linux/scatterlist.h> 23#include <linux/scatterlist.h>
24#include <linux/gpio.h> 24#include <linux/gpio.h>
25#include <linux/amba/mmci.h> 25#include <linux/amba/mmci.h>
26#include <linux/regulator/consumer.h>
26 27
27#include <asm/cacheflush.h> 28#include <asm/cacheflush.h>
28#include <asm/div64.h> 29#include <asm/div64.h>
@@ -452,13 +453,28 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
452 u32 pwr = 0; 453 u32 pwr = 0;
453 unsigned long flags; 454 unsigned long flags;
454 455
455 if (host->plat->translate_vdd)
456 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
457
458 switch (ios->power_mode) { 456 switch (ios->power_mode) {
459 case MMC_POWER_OFF: 457 case MMC_POWER_OFF:
458 if(host->vcc &&
459 regulator_is_enabled(host->vcc))
460 regulator_disable(host->vcc);
460 break; 461 break;
461 case MMC_POWER_UP: 462 case MMC_POWER_UP:
463#ifdef CONFIG_REGULATOR
464 if (host->vcc)
465 /* This implicitly enables the regulator */
466 mmc_regulator_set_ocr(host->vcc, ios->vdd);
467#endif
468 /*
469 * The translate_vdd function is not used if you have
470 * an external regulator, or your design is really weird.
471 * Using it would mean sending in power control BOTH using
472 * a regulator AND the 4 MMCIPWR bits. If we don't have
473 * a regulator, we might have some other platform specific
474 * power control behind this translate function.
475 */
476 if (!host->vcc && host->plat->translate_vdd)
477 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
462 /* The ST version does not have this, fall through to POWER_ON */ 478 /* The ST version does not have this, fall through to POWER_ON */
463 if (host->hw_designer != AMBA_VENDOR_ST) { 479 if (host->hw_designer != AMBA_VENDOR_ST) {
464 pwr |= MCI_PWR_UP; 480 pwr |= MCI_PWR_UP;
@@ -603,7 +619,29 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
603 mmc->ops = &mmci_ops; 619 mmc->ops = &mmci_ops;
604 mmc->f_min = (host->mclk + 511) / 512; 620 mmc->f_min = (host->mclk + 511) / 512;
605 mmc->f_max = min(host->mclk, fmax); 621 mmc->f_max = min(host->mclk, fmax);
606 mmc->ocr_avail = plat->ocr_mask; 622#ifdef CONFIG_REGULATOR
623 /* If we're using the regulator framework, try to fetch a regulator */
624 host->vcc = regulator_get(&dev->dev, "vmmc");
625 if (IS_ERR(host->vcc))
626 host->vcc = NULL;
627 else {
628 int mask = mmc_regulator_get_ocrmask(host->vcc);
629
630 if (mask < 0)
631 dev_err(&dev->dev, "error getting OCR mask (%d)\n",
632 mask);
633 else {
634 host->mmc->ocr_avail = (u32) mask;
635 if (plat->ocr_mask)
636 dev_warn(&dev->dev,
637 "Provided ocr_mask/setpower will not be used "
638 "(using regulator instead)\n");
639 }
640 }
641#endif
642 /* Fall back to platform data if no regulator is found */
643 if (host->vcc == NULL)
644 mmc->ocr_avail = plat->ocr_mask;
607 mmc->caps = plat->capabilities; 645 mmc->caps = plat->capabilities;
608 646
609 /* 647 /*
@@ -741,6 +779,10 @@ static int __devexit mmci_remove(struct amba_device *dev)
741 clk_disable(host->clk); 779 clk_disable(host->clk);
742 clk_put(host->clk); 780 clk_put(host->clk);
743 781
782 if (regulator_is_enabled(host->vcc))
783 regulator_disable(host->vcc);
784 regulator_put(host->vcc);
785
744 mmc_free_host(mmc); 786 mmc_free_host(mmc);
745 787
746 amba_release_regions(dev); 788 amba_release_regions(dev);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a7f9a51a0a3e..1ceb9a90f59b 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -175,6 +175,7 @@ struct mmci_host {
175 struct scatterlist *sg_ptr; 175 struct scatterlist *sg_ptr;
176 unsigned int sg_off; 176 unsigned int sg_off;
177 unsigned int size; 177 unsigned int size;
178 struct regulator *vcc;
178}; 179};
179 180
180static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) 181static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)