diff options
author | Alberto Panizzo <maramaopercheseimorto@gmail.com> | 2010-11-01 20:05:37 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-01-08 21:49:06 -0500 |
commit | 74b66954ebfcef9bc26d9c377d32fbd46b4ddc32 (patch) | |
tree | 7df0ff132dbed06d5bc049b1d43b736d33849f34 /drivers/mmc/host/mxcmmc.c | |
parent | 930e2fe7593b10033c0cd68fb818c3dec365391a (diff) |
mmc: mxcmmc: Allow binding a regulator to manage the MMC card voltage
This implementation is based on the pxamci.c driver and it will
be used to support the mx31_3ds machine.
Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/mxcmmc.c')
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index bdd2cbb87cba..1a7f48c3c554 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/gpio.h> | 33 | #include <linux/gpio.h> |
34 | #include <linux/regulator/consumer.h> | ||
34 | 35 | ||
35 | #include <asm/dma.h> | 36 | #include <asm/dma.h> |
36 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
@@ -141,10 +142,45 @@ struct mxcmci_host { | |||
141 | 142 | ||
142 | struct work_struct datawork; | 143 | struct work_struct datawork; |
143 | spinlock_t lock; | 144 | spinlock_t lock; |
145 | |||
146 | struct regulator *vcc; | ||
144 | }; | 147 | }; |
145 | 148 | ||
146 | static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); | 149 | static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); |
147 | 150 | ||
151 | static inline void mxcmci_init_ocr(struct mxcmci_host *host) | ||
152 | { | ||
153 | #ifdef CONFIG_REGULATOR | ||
154 | host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); | ||
155 | |||
156 | if (IS_ERR(host->vcc)) { | ||
157 | host->vcc = NULL; | ||
158 | } else { | ||
159 | host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); | ||
160 | if (host->pdata && host->pdata->ocr_avail) | ||
161 | dev_warn(mmc_dev(host->mmc), | ||
162 | "pdata->ocr_avail will not be used\n"); | ||
163 | } | ||
164 | #endif | ||
165 | if (host->vcc == NULL) { | ||
166 | /* fall-back to platform data */ | ||
167 | if (host->pdata && host->pdata->ocr_avail) | ||
168 | host->mmc->ocr_avail = host->pdata->ocr_avail; | ||
169 | else | ||
170 | host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | static inline void mxcmci_set_power(struct mxcmci_host *host, unsigned int vdd) | ||
175 | { | ||
176 | #ifdef CONFIG_REGULATOR | ||
177 | if (host->vcc) | ||
178 | mmc_regulator_set_ocr(host->vcc, vdd); | ||
179 | #endif | ||
180 | if (host->pdata && host->pdata->setpower) | ||
181 | host->pdata->setpower(mmc_dev(host->mmc), vdd); | ||
182 | } | ||
183 | |||
148 | static inline int mxcmci_use_dma(struct mxcmci_host *host) | 184 | static inline int mxcmci_use_dma(struct mxcmci_host *host) |
149 | { | 185 | { |
150 | return host->do_dma; | 186 | return host->do_dma; |
@@ -680,9 +716,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
680 | host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; | 716 | host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; |
681 | 717 | ||
682 | if (host->power_mode != ios->power_mode) { | 718 | if (host->power_mode != ios->power_mode) { |
683 | if (host->pdata && host->pdata->setpower) | 719 | mxcmci_set_power(host, ios->vdd); |
684 | host->pdata->setpower(mmc_dev(mmc), ios->vdd); | ||
685 | host->power_mode = ios->power_mode; | 720 | host->power_mode = ios->power_mode; |
721 | |||
686 | if (ios->power_mode == MMC_POWER_ON) | 722 | if (ios->power_mode == MMC_POWER_ON) |
687 | host->cmdat |= CMD_DAT_CONT_INIT; | 723 | host->cmdat |= CMD_DAT_CONT_INIT; |
688 | } | 724 | } |
@@ -807,10 +843,7 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
807 | host->pdata = pdev->dev.platform_data; | 843 | host->pdata = pdev->dev.platform_data; |
808 | spin_lock_init(&host->lock); | 844 | spin_lock_init(&host->lock); |
809 | 845 | ||
810 | if (host->pdata && host->pdata->ocr_avail) | 846 | mxcmci_init_ocr(host); |
811 | mmc->ocr_avail = host->pdata->ocr_avail; | ||
812 | else | ||
813 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | ||
814 | 847 | ||
815 | if (host->pdata && host->pdata->dat3_card_detect) | 848 | if (host->pdata && host->pdata->dat3_card_detect) |
816 | host->default_irq_mask = | 849 | host->default_irq_mask = |
@@ -915,6 +948,9 @@ static int mxcmci_remove(struct platform_device *pdev) | |||
915 | 948 | ||
916 | mmc_remove_host(mmc); | 949 | mmc_remove_host(mmc); |
917 | 950 | ||
951 | if (host->vcc) | ||
952 | regulator_put(host->vcc); | ||
953 | |||
918 | if (host->pdata && host->pdata->exit) | 954 | if (host->pdata && host->pdata->exit) |
919 | host->pdata->exit(&pdev->dev, mmc); | 955 | host->pdata->exit(&pdev->dev, mmc); |
920 | 956 | ||