diff options
-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 430095725f9f..d7d7109ef47e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
29 | #include <linux/io.h> | 29 | #include <linux/io.h> |
30 | #include <linux/regulator/consumer.h> | ||
30 | 31 | ||
31 | #include <asm/sizes.h> | 32 | #include <asm/sizes.h> |
32 | 33 | ||
@@ -67,8 +68,42 @@ struct pxamci_host { | |||
67 | unsigned int dma_dir; | 68 | unsigned int dma_dir; |
68 | unsigned int dma_drcmrrx; | 69 | unsigned int dma_drcmrrx; |
69 | unsigned int dma_drcmrtx; | 70 | unsigned int dma_drcmrtx; |
71 | |||
72 | struct regulator *vcc; | ||
70 | }; | 73 | }; |
71 | 74 | ||
75 | static inline void pxamci_init_ocr(struct pxamci_host *host) | ||
76 | { | ||
77 | #ifdef CONFIG_REGULATOR | ||
78 | host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); | ||
79 | |||
80 | if (IS_ERR(host->vcc)) | ||
81 | host->vcc = NULL; | ||
82 | else { | ||
83 | host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); | ||
84 | if (host->pdata && host->pdata->ocr_mask) | ||
85 | dev_warn(mmc_dev(host->mmc), | ||
86 | "ocr_mask/setpower will not be used\n"); | ||
87 | } | ||
88 | #endif | ||
89 | if (host->vcc == NULL) { | ||
90 | /* fall-back to platform data */ | ||
91 | host->mmc->ocr_avail = host->pdata ? | ||
92 | host->pdata->ocr_mask : | ||
93 | MMC_VDD_32_33 | MMC_VDD_33_34; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) | ||
98 | { | ||
99 | #ifdef CONFIG_REGULATOR | ||
100 | if (host->vcc) | ||
101 | mmc_regulator_set_ocr(host->vcc, vdd); | ||
102 | #endif | ||
103 | if (!host->vcc && host->pdata && host->pdata->setpower) | ||
104 | host->pdata->setpower(mmc_dev(host->mmc), vdd); | ||
105 | } | ||
106 | |||
72 | static void pxamci_stop_clock(struct pxamci_host *host) | 107 | static void pxamci_stop_clock(struct pxamci_host *host) |
73 | { | 108 | { |
74 | if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { | 109 | 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) | |||
438 | if (host->power_mode != ios->power_mode) { | 473 | if (host->power_mode != ios->power_mode) { |
439 | host->power_mode = ios->power_mode; | 474 | host->power_mode = ios->power_mode; |
440 | 475 | ||
441 | if (host->pdata && host->pdata->setpower) | 476 | pxamci_set_power(host, ios->vdd); |
442 | host->pdata->setpower(mmc_dev(mmc), ios->vdd); | ||
443 | 477 | ||
444 | if (ios->power_mode == MMC_POWER_ON) | 478 | if (ios->power_mode == MMC_POWER_ON) |
445 | host->cmdat |= CMDAT_INIT; | 479 | host->cmdat |= CMDAT_INIT; |
@@ -562,9 +596,8 @@ static int pxamci_probe(struct platform_device *pdev) | |||
562 | mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 | 596 | mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 |
563 | : host->clkrate; | 597 | : host->clkrate; |
564 | 598 | ||
565 | mmc->ocr_avail = host->pdata ? | 599 | pxamci_init_ocr(host); |
566 | host->pdata->ocr_mask : | 600 | |
567 | MMC_VDD_32_33|MMC_VDD_33_34; | ||
568 | mmc->caps = 0; | 601 | mmc->caps = 0; |
569 | host->cmdat = 0; | 602 | host->cmdat = 0; |
570 | if (!cpu_is_pxa25x()) { | 603 | if (!cpu_is_pxa25x()) { |
@@ -661,6 +694,9 @@ static int pxamci_remove(struct platform_device *pdev) | |||
661 | if (mmc) { | 694 | if (mmc) { |
662 | struct pxamci_host *host = mmc_priv(mmc); | 695 | struct pxamci_host *host = mmc_priv(mmc); |
663 | 696 | ||
697 | if (host->vcc) | ||
698 | regulator_put(host->vcc); | ||
699 | |||
664 | if (host->pdata && host->pdata->exit) | 700 | if (host->pdata && host->pdata->exit) |
665 | host->pdata->exit(&pdev->dev, mmc); | 701 | host->pdata->exit(&pdev->dev, mmc); |
666 | 702 | ||