diff options
author | Linus Walleij <linus.walleij@stericsson.com> | 2009-09-22 09:41:40 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 15:49:05 -0400 |
commit | 34e84f39a27d059a3e6ec6e8b94aafa702e6f220 (patch) | |
tree | 263bf7ee2a9f6b4ce86f89a82806fb73ff3c41d7 /drivers | |
parent | 6ef297f86b62f187c59475784208f75c2ed8ccd8 (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.c | 50 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 1 |
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 | ||
180 | static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) | 181 | static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) |