diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-03-23 21:23:47 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2009-03-23 21:51:22 -0400 |
commit | 0329c3773e59aa7e50dc3760a27fb4e098773d0f (patch) | |
tree | 9516656043222a9d87e44387cd5b8a50636eeca4 /arch/arm/mach-omap2 | |
parent | 8466032d862a2e52d73af3311bc97f950aaa36c8 (diff) |
ARM: OMAP3: mmc-twl4030 voltage cleanup
Correct twl4030 MMC power switching: fix voltage ranges reported
for each slot, and handle them fully.
Lies corrected:
- MMC-1 doesn't support the 2.6-2.7 Volt range
- MMC-2 can't normally support anything except 1.8V
Omissions corrected
- MMC-1 *does* handle the 2.8-2.9 Volt range
- MMC-2 can handle 2.5-3.2 Volt cards, given a transceiver
Add transciever support for MMC-2; enable it for Overo and Pandora.
(Depends on something else to have set up pinmuxing for control
signals instead of as MMC2_DAT4..7 pins.)
Also shrink twl4030_hsmmc_info a smidgeon ... padding is all gone.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/board-omap3pandora.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-overo.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mmc-twl4030.c | 127 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mmc-twl4030.h | 3 |
4 files changed, 84 insertions, 48 deletions
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index b3196107afdb..7a46a6563a58 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c | |||
@@ -53,6 +53,7 @@ static struct twl4030_hsmmc_info omap3pandora_mmc[] = { | |||
53 | .gpio_cd = -EINVAL, | 53 | .gpio_cd = -EINVAL, |
54 | .gpio_wp = 127, | 54 | .gpio_wp = 127, |
55 | .ext_clock = 1, | 55 | .ext_clock = 1, |
56 | .transceiver = true, | ||
56 | }, | 57 | }, |
57 | {} /* Terminator */ | 58 | {} /* Terminator */ |
58 | }; | 59 | }; |
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index b92313c8b84b..9c14324d8c68 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c | |||
@@ -214,6 +214,7 @@ static struct twl4030_hsmmc_info mmc[] __initdata = { | |||
214 | .wires = 4, | 214 | .wires = 4, |
215 | .gpio_cd = -EINVAL, | 215 | .gpio_cd = -EINVAL, |
216 | .gpio_wp = -EINVAL, | 216 | .gpio_wp = -EINVAL, |
217 | .transceiver = true, | ||
217 | }, | 218 | }, |
218 | {} /* Terminator */ | 219 | {} /* Terminator */ |
219 | }; | 220 | }; |
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c index 84cac87537a3..df1539e2cd07 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #define VMMC2_315V 0x0c | 44 | #define VMMC2_315V 0x0c |
45 | #define VMMC2_300V 0x0b | 45 | #define VMMC2_300V 0x0b |
46 | #define VMMC2_285V 0x0a | 46 | #define VMMC2_285V 0x0a |
47 | #define VMMC2_280V 0x09 | ||
47 | #define VMMC2_260V 0x08 | 48 | #define VMMC2_260V 0x08 |
48 | #define VMMC2_185V 0x06 | 49 | #define VMMC2_185V 0x06 |
49 | #define VMMC2_DEDICATED 0x2E | 50 | #define VMMC2_DEDICATED 0x2E |
@@ -166,56 +167,73 @@ static int twl_mmc_resume(struct device *dev, int slot) | |||
166 | /* | 167 | /* |
167 | * Sets the MMC voltage in twl4030 | 168 | * Sets the MMC voltage in twl4030 |
168 | */ | 169 | */ |
170 | |||
171 | #define MMC1_OCR (MMC_VDD_165_195 \ | ||
172 | |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32) | ||
173 | #define MMC2_OCR (MMC_VDD_165_195 \ | ||
174 | |MMC_VDD_25_26|MMC_VDD_26_27|MMC_VDD_27_28 \ | ||
175 | |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32) | ||
176 | |||
169 | static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) | 177 | static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) |
170 | { | 178 | { |
171 | int ret; | 179 | int ret; |
172 | u8 vmmc, dev_grp_val; | 180 | u8 vmmc, dev_grp_val; |
173 | 181 | ||
174 | switch (1 << vdd) { | 182 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) { |
175 | case MMC_VDD_35_36: | 183 | /* VMMC1: max 220 mA. And for 8-bit mode, |
176 | case MMC_VDD_34_35: | 184 | * VSIM: max 50 mA |
177 | case MMC_VDD_33_34: | 185 | */ |
178 | case MMC_VDD_32_33: | 186 | switch (1 << vdd) { |
179 | case MMC_VDD_31_32: | 187 | case MMC_VDD_165_195: |
180 | case MMC_VDD_30_31: | ||
181 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) | ||
182 | vmmc = VMMC1_315V; | ||
183 | else | ||
184 | vmmc = VMMC2_315V; | ||
185 | break; | ||
186 | case MMC_VDD_29_30: | ||
187 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) | ||
188 | vmmc = VMMC1_315V; | ||
189 | else | ||
190 | vmmc = VMMC2_300V; | ||
191 | break; | ||
192 | case MMC_VDD_27_28: | ||
193 | case MMC_VDD_26_27: | ||
194 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) | ||
195 | vmmc = VMMC1_285V; | ||
196 | else | ||
197 | vmmc = VMMC2_285V; | ||
198 | break; | ||
199 | case MMC_VDD_25_26: | ||
200 | case MMC_VDD_24_25: | ||
201 | case MMC_VDD_23_24: | ||
202 | case MMC_VDD_22_23: | ||
203 | case MMC_VDD_21_22: | ||
204 | case MMC_VDD_20_21: | ||
205 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) | ||
206 | vmmc = VMMC1_285V; | ||
207 | else | ||
208 | vmmc = VMMC2_260V; | ||
209 | break; | ||
210 | case MMC_VDD_165_195: | ||
211 | if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) | ||
212 | vmmc = VMMC1_185V; | 188 | vmmc = VMMC1_185V; |
213 | else | 189 | /* and VSIM_180V */ |
190 | break; | ||
191 | case MMC_VDD_28_29: | ||
192 | vmmc = VMMC1_285V; | ||
193 | /* and VSIM_280V */ | ||
194 | break; | ||
195 | case MMC_VDD_29_30: | ||
196 | case MMC_VDD_30_31: | ||
197 | vmmc = VMMC1_300V; | ||
198 | /* and VSIM_300V */ | ||
199 | break; | ||
200 | case MMC_VDD_31_32: | ||
201 | vmmc = VMMC1_315V; | ||
202 | /* error if VSIM needed */ | ||
203 | break; | ||
204 | default: | ||
205 | vmmc = 0; | ||
206 | break; | ||
207 | } | ||
208 | } else if (c->twl_vmmc_dev_grp == VMMC2_DEV_GRP) { | ||
209 | /* VMMC2: max 100 mA */ | ||
210 | switch (1 << vdd) { | ||
211 | case MMC_VDD_165_195: | ||
214 | vmmc = VMMC2_185V; | 212 | vmmc = VMMC2_185V; |
215 | break; | 213 | break; |
216 | default: | 214 | case MMC_VDD_25_26: |
217 | vmmc = 0; | 215 | case MMC_VDD_26_27: |
218 | break; | 216 | vmmc = VMMC2_260V; |
217 | break; | ||
218 | case MMC_VDD_27_28: | ||
219 | vmmc = VMMC2_280V; | ||
220 | break; | ||
221 | case MMC_VDD_28_29: | ||
222 | vmmc = VMMC2_285V; | ||
223 | break; | ||
224 | case MMC_VDD_29_30: | ||
225 | case MMC_VDD_30_31: | ||
226 | vmmc = VMMC2_300V; | ||
227 | break; | ||
228 | case MMC_VDD_31_32: | ||
229 | vmmc = VMMC2_315V; | ||
230 | break; | ||
231 | default: | ||
232 | vmmc = 0; | ||
233 | break; | ||
234 | } | ||
235 | } else { | ||
236 | return 0; | ||
219 | } | 237 | } |
220 | 238 | ||
221 | if (vmmc) | 239 | if (vmmc) |
@@ -242,6 +260,14 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, | |||
242 | struct twl_mmc_controller *c = &hsmmc[0]; | 260 | struct twl_mmc_controller *c = &hsmmc[0]; |
243 | struct omap_mmc_platform_data *mmc = dev->platform_data; | 261 | struct omap_mmc_platform_data *mmc = dev->platform_data; |
244 | 262 | ||
263 | /* | ||
264 | * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | ||
265 | * card using the same TWL VMMC1 supply (hsmmc[0]); OMAP has both | ||
266 | * 1.8V and 3.0V modes, controlled by the PBIAS register. | ||
267 | * | ||
268 | * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | ||
269 | * is most naturally TWL VSIM; those pins also use PBIAS. | ||
270 | */ | ||
245 | if (power_on) { | 271 | if (power_on) { |
246 | if (cpu_is_omap2430()) { | 272 | if (cpu_is_omap2430()) { |
247 | reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); | 273 | reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); |
@@ -298,6 +324,12 @@ static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vd | |||
298 | struct twl_mmc_controller *c = &hsmmc[1]; | 324 | struct twl_mmc_controller *c = &hsmmc[1]; |
299 | struct omap_mmc_platform_data *mmc = dev->platform_data; | 325 | struct omap_mmc_platform_data *mmc = dev->platform_data; |
300 | 326 | ||
327 | /* | ||
328 | * Assume TWL VMMC2 (hsmmc[1]) is used only to power the card ... OMAP | ||
329 | * VDDS is used to power the pins, optionally with a transceiver to | ||
330 | * support cards using voltages other than VDDS (1.8V nominal). When a | ||
331 | * transceiver is used, DAT3..7 are muxed as transceiver control pins. | ||
332 | */ | ||
301 | if (power_on) { | 333 | if (power_on) { |
302 | if (mmc->slots[0].internal_clock) { | 334 | if (mmc->slots[0].internal_clock) { |
303 | u32 reg; | 335 | u32 reg; |
@@ -353,10 +385,6 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) | |||
353 | c->mmc, 1); | 385 | c->mmc, 1); |
354 | mmc->slots[0].name = twl->name; | 386 | mmc->slots[0].name = twl->name; |
355 | mmc->nr_slots = 1; | 387 | mmc->nr_slots = 1; |
356 | mmc->slots[0].ocr_mask = MMC_VDD_165_195 | | ||
357 | MMC_VDD_26_27 | MMC_VDD_27_28 | | ||
358 | MMC_VDD_29_30 | | ||
359 | MMC_VDD_30_31 | MMC_VDD_31_32; | ||
360 | mmc->slots[0].wires = c->wires; | 388 | mmc->slots[0].wires = c->wires; |
361 | mmc->slots[0].internal_clock = !c->ext_clock; | 389 | mmc->slots[0].internal_clock = !c->ext_clock; |
362 | mmc->dma_mask = 0xffffffff; | 390 | mmc->dma_mask = 0xffffffff; |
@@ -392,9 +420,14 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) | |||
392 | switch (c->mmc) { | 420 | switch (c->mmc) { |
393 | case 1: | 421 | case 1: |
394 | mmc->slots[0].set_power = twl_mmc1_set_power; | 422 | mmc->slots[0].set_power = twl_mmc1_set_power; |
423 | mmc->slots[0].ocr_mask = MMC1_OCR; | ||
395 | break; | 424 | break; |
396 | case 2: | 425 | case 2: |
397 | mmc->slots[0].set_power = twl_mmc2_set_power; | 426 | mmc->slots[0].set_power = twl_mmc2_set_power; |
427 | if (c->transceiver) | ||
428 | mmc->slots[0].ocr_mask = MMC2_OCR; | ||
429 | else | ||
430 | mmc->slots[0].ocr_mask = MMC_VDD_165_195; | ||
398 | break; | 431 | break; |
399 | default: | 432 | default: |
400 | pr_err("MMC%d configuration not supported!\n", c->mmc); | 433 | pr_err("MMC%d configuration not supported!\n", c->mmc); |
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h index e1c8076400ca..380dde7bcfe3 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.h +++ b/arch/arm/mach-omap2/mmc-twl4030.h | |||
@@ -9,9 +9,10 @@ | |||
9 | struct twl4030_hsmmc_info { | 9 | struct twl4030_hsmmc_info { |
10 | u8 mmc; /* controller 1/2/3 */ | 10 | u8 mmc; /* controller 1/2/3 */ |
11 | u8 wires; /* 1/4/8 wires */ | 11 | u8 wires; /* 1/4/8 wires */ |
12 | bool transceiver; /* MMC-2 option */ | ||
13 | bool ext_clock; /* use external pin for input clock */ | ||
12 | int gpio_cd; /* or -EINVAL */ | 14 | int gpio_cd; /* or -EINVAL */ |
13 | int gpio_wp; /* or -EINVAL */ | 15 | int gpio_wp; /* or -EINVAL */ |
14 | int ext_clock:1; /* use external pin for input clock */ | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | #if defined(CONFIG_TWL4030_CORE) && \ | 18 | #if defined(CONFIG_TWL4030_CORE) && \ |