diff options
Diffstat (limited to 'arch/arm/mach-omap2/hsmmc.c')
-rw-r--r-- | arch/arm/mach-omap2/hsmmc.c | 120 |
1 files changed, 107 insertions, 13 deletions
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 9ad229594b46..1ef54b036103 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | static u16 control_pbias_offset; | 25 | static u16 control_pbias_offset; |
26 | static u16 control_devconf1_offset; | 26 | static u16 control_devconf1_offset; |
27 | static u16 control_mmc1; | ||
27 | 28 | ||
28 | #define HSMMC_NAME_LEN 9 | 29 | #define HSMMC_NAME_LEN 9 |
29 | 30 | ||
@@ -42,7 +43,7 @@ static int hsmmc_get_context_loss(struct device *dev) | |||
42 | #define hsmmc_get_context_loss NULL | 43 | #define hsmmc_get_context_loss NULL |
43 | #endif | 44 | #endif |
44 | 45 | ||
45 | static void hsmmc1_before_set_reg(struct device *dev, int slot, | 46 | static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, |
46 | int power_on, int vdd) | 47 | int power_on, int vdd) |
47 | { | 48 | { |
48 | u32 reg, prog_io; | 49 | u32 reg, prog_io; |
@@ -95,7 +96,7 @@ static void hsmmc1_before_set_reg(struct device *dev, int slot, | |||
95 | } | 96 | } |
96 | } | 97 | } |
97 | 98 | ||
98 | static void hsmmc1_after_set_reg(struct device *dev, int slot, | 99 | static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, |
99 | int power_on, int vdd) | 100 | int power_on, int vdd) |
100 | { | 101 | { |
101 | u32 reg; | 102 | u32 reg; |
@@ -119,6 +120,60 @@ static void hsmmc1_after_set_reg(struct device *dev, int slot, | |||
119 | } | 120 | } |
120 | } | 121 | } |
121 | 122 | ||
123 | static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot, | ||
124 | int power_on, int vdd) | ||
125 | { | ||
126 | u32 reg; | ||
127 | |||
128 | /* | ||
129 | * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | ||
130 | * card with Vcc regulator (from twl4030 or whatever). OMAP has both | ||
131 | * 1.8V and 3.0V modes, controlled by the PBIAS register. | ||
132 | * | ||
133 | * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | ||
134 | * is most naturally TWL VSIM; those pins also use PBIAS. | ||
135 | * | ||
136 | * FIXME handle VMMC1A as needed ... | ||
137 | */ | ||
138 | reg = omap_ctrl_readl(control_pbias_offset); | ||
139 | reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ | | ||
140 | OMAP4_USBC1_ICUSB_PWRDNZ); | ||
141 | omap_ctrl_writel(reg, control_pbias_offset); | ||
142 | } | ||
143 | |||
144 | static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot, | ||
145 | int power_on, int vdd) | ||
146 | { | ||
147 | u32 reg; | ||
148 | |||
149 | if (power_on) { | ||
150 | reg = omap_ctrl_readl(control_pbias_offset); | ||
151 | reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ; | ||
152 | if ((1 << vdd) <= MMC_VDD_165_195) | ||
153 | reg &= ~OMAP4_MMC1_PBIASLITE_VMODE; | ||
154 | else | ||
155 | reg |= OMAP4_MMC1_PBIASLITE_VMODE; | ||
156 | reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ | | ||
157 | OMAP4_USBC1_ICUSB_PWRDNZ); | ||
158 | omap_ctrl_writel(reg, control_pbias_offset); | ||
159 | /* 4 microsec delay for comparator to generate an error*/ | ||
160 | udelay(4); | ||
161 | reg = omap_ctrl_readl(control_pbias_offset); | ||
162 | if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR) { | ||
163 | pr_err("Pbias Voltage is not same as LDO\n"); | ||
164 | /* Caution : On VMODE_ERROR Power Down MMC IO */ | ||
165 | reg &= ~(OMAP4_MMC1_PWRDNZ | OMAP4_USBC1_ICUSB_PWRDNZ); | ||
166 | omap_ctrl_writel(reg, control_pbias_offset); | ||
167 | } | ||
168 | } else { | ||
169 | reg = omap_ctrl_readl(control_pbias_offset); | ||
170 | reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | | ||
171 | OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PWRDNZ | | ||
172 | OMAP4_USBC1_ICUSB_PWRDNZ); | ||
173 | omap_ctrl_writel(reg, control_pbias_offset); | ||
174 | } | ||
175 | } | ||
176 | |||
122 | static void hsmmc23_before_set_reg(struct device *dev, int slot, | 177 | static void hsmmc23_before_set_reg(struct device *dev, int slot, |
123 | int power_on, int vdd) | 178 | int power_on, int vdd) |
124 | { | 179 | { |
@@ -139,6 +194,12 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot, | |||
139 | } | 194 | } |
140 | } | 195 | } |
141 | 196 | ||
197 | static int nop_mmc_set_power(struct device *dev, int slot, int power_on, | ||
198 | int vdd) | ||
199 | { | ||
200 | return 0; | ||
201 | } | ||
202 | |||
142 | static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; | 203 | static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; |
143 | 204 | ||
144 | void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) | 205 | void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) |
@@ -146,13 +207,28 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) | |||
146 | struct omap2_hsmmc_info *c; | 207 | struct omap2_hsmmc_info *c; |
147 | int nr_hsmmc = ARRAY_SIZE(hsmmc_data); | 208 | int nr_hsmmc = ARRAY_SIZE(hsmmc_data); |
148 | int i; | 209 | int i; |
210 | u32 reg; | ||
149 | 211 | ||
150 | if (cpu_is_omap2430()) { | 212 | if (!cpu_is_omap44xx()) { |
151 | control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; | 213 | if (cpu_is_omap2430()) { |
152 | control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | 214 | control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; |
215 | control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | ||
216 | } else { | ||
217 | control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | ||
218 | control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | ||
219 | } | ||
153 | } else { | 220 | } else { |
154 | control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | 221 | control_pbias_offset = OMAP44XX_CONTROL_PBIAS_LITE; |
155 | control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | 222 | control_mmc1 = OMAP44XX_CONTROL_MMC1; |
223 | reg = omap_ctrl_readl(control_mmc1); | ||
224 | reg |= (OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 | | ||
225 | OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1); | ||
226 | reg &= ~(OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 | | ||
227 | OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3); | ||
228 | reg |= (OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL | | ||
229 | OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL | | ||
230 | OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL); | ||
231 | omap_ctrl_writel(reg, control_mmc1); | ||
156 | } | 232 | } |
157 | 233 | ||
158 | for (c = controllers; c->mmc; c++) { | 234 | for (c = controllers; c->mmc; c++) { |
@@ -216,11 +292,27 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) | |||
216 | */ | 292 | */ |
217 | mmc->slots[0].ocr_mask = c->ocr_mask; | 293 | mmc->slots[0].ocr_mask = c->ocr_mask; |
218 | 294 | ||
295 | if (cpu_is_omap3517() || cpu_is_omap3505()) | ||
296 | mmc->slots[0].set_power = nop_mmc_set_power; | ||
297 | else | ||
298 | mmc->slots[0].features |= HSMMC_HAS_PBIAS; | ||
299 | |||
219 | switch (c->mmc) { | 300 | switch (c->mmc) { |
220 | case 1: | 301 | case 1: |
221 | /* on-chip level shifting via PBIAS0/PBIAS1 */ | 302 | if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { |
222 | mmc->slots[0].before_set_reg = hsmmc1_before_set_reg; | 303 | /* on-chip level shifting via PBIAS0/PBIAS1 */ |
223 | mmc->slots[0].after_set_reg = hsmmc1_after_set_reg; | 304 | if (cpu_is_omap44xx()) { |
305 | mmc->slots[0].before_set_reg = | ||
306 | omap4_hsmmc1_before_set_reg; | ||
307 | mmc->slots[0].after_set_reg = | ||
308 | omap4_hsmmc1_after_set_reg; | ||
309 | } else { | ||
310 | mmc->slots[0].before_set_reg = | ||
311 | omap_hsmmc1_before_set_reg; | ||
312 | mmc->slots[0].after_set_reg = | ||
313 | omap_hsmmc1_after_set_reg; | ||
314 | } | ||
315 | } | ||
224 | 316 | ||
225 | /* Omap3630 HSMMC1 supports only 4-bit */ | 317 | /* Omap3630 HSMMC1 supports only 4-bit */ |
226 | if (cpu_is_omap3630() && c->wires > 4) { | 318 | if (cpu_is_omap3630() && c->wires > 4) { |
@@ -235,9 +327,11 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) | |||
235 | c->wires = 4; | 327 | c->wires = 4; |
236 | /* FALLTHROUGH */ | 328 | /* FALLTHROUGH */ |
237 | case 3: | 329 | case 3: |
238 | /* off-chip level shifting, or none */ | 330 | if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { |
239 | mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; | 331 | /* off-chip level shifting, or none */ |
240 | mmc->slots[0].after_set_reg = NULL; | 332 | mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; |
333 | mmc->slots[0].after_set_reg = NULL; | ||
334 | } | ||
241 | break; | 335 | break; |
242 | default: | 336 | default: |
243 | pr_err("MMC%d configuration not supported!\n", c->mmc); | 337 | pr_err("MMC%d configuration not supported!\n", c->mmc); |