Commit | Line | Data |
---|---|---|
90c62bf0 | 1 | /* |
d02a900b | 2 | * linux/arch/arm/mach-omap2/hsmmc.c |
90c62bf0 TL |
3 | * |
4 | * Copyright (C) 2007-2008 Texas Instruments | |
5 | * Copyright (C) 2008 Nokia Corporation | |
6 | * Author: Texas Instruments | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
db0fefc5 AH |
12 | #include <linux/kernel.h> |
13 | #include <linux/slab.h> | |
14 | #include <linux/string.h> | |
90c62bf0 | 15 | #include <linux/delay.h> |
90c62bf0 | 16 | #include <mach/hardware.h> |
ce491cf8 | 17 | #include <plat/mmc.h> |
e3df0fb4 | 18 | #include <plat/omap-pm.h> |
90c62bf0 | 19 | |
d02a900b | 20 | #include "hsmmc.h" |
4814ced5 | 21 | #include "control.h" |
90c62bf0 | 22 | |
db0fefc5 | 23 | #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) |
90c62bf0 TL |
24 | |
25 | static u16 control_pbias_offset; | |
26 | static u16 control_devconf1_offset; | |
c83c8e6c | 27 | static u16 control_mmc1; |
90c62bf0 TL |
28 | |
29 | #define HSMMC_NAME_LEN 9 | |
30 | ||
68ff0423 | 31 | static struct hsmmc_controller { |
b583f26d DB |
32 | char name[HSMMC_NAME_LEN + 1]; |
33 | } hsmmc[OMAP34XX_NR_MMC]; | |
90c62bf0 | 34 | |
1887bde3 DK |
35 | #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) |
36 | ||
68ff0423 | 37 | static int hsmmc_get_context_loss(struct device *dev) |
1887bde3 | 38 | { |
e3df0fb4 | 39 | return omap_pm_get_dev_context_loss_count(dev); |
1887bde3 DK |
40 | } |
41 | ||
42 | #else | |
68ff0423 | 43 | #define hsmmc_get_context_loss NULL |
1887bde3 DK |
44 | #endif |
45 | ||
c83c8e6c | 46 | static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, |
db0fefc5 | 47 | int power_on, int vdd) |
90c62bf0 | 48 | { |
555d503f | 49 | u32 reg, prog_io; |
90c62bf0 TL |
50 | struct omap_mmc_platform_data *mmc = dev->platform_data; |
51 | ||
ce6f0016 AH |
52 | if (mmc->slots[0].remux) |
53 | mmc->slots[0].remux(dev, slot, power_on); | |
54 | ||
0329c377 DB |
55 | /* |
56 | * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | |
b583f26d | 57 | * card with Vcc regulator (from twl4030 or whatever). OMAP has both |
0329c377 DB |
58 | * 1.8V and 3.0V modes, controlled by the PBIAS register. |
59 | * | |
60 | * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | |
61 | * is most naturally TWL VSIM; those pins also use PBIAS. | |
b583f26d DB |
62 | * |
63 | * FIXME handle VMMC1A as needed ... | |
0329c377 | 64 | */ |
90c62bf0 TL |
65 | if (power_on) { |
66 | if (cpu_is_omap2430()) { | |
67 | reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); | |
68 | if ((1 << vdd) >= MMC_VDD_30_31) | |
69 | reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE; | |
70 | else | |
71 | reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE; | |
72 | omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); | |
73 | } | |
74 | ||
75 | if (mmc->slots[0].internal_clock) { | |
76 | reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); | |
77 | reg |= OMAP2_MMCSDIO1ADPCLKISEL; | |
78 | omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); | |
79 | } | |
80 | ||
81 | reg = omap_ctrl_readl(control_pbias_offset); | |
555d503f M |
82 | if (cpu_is_omap3630()) { |
83 | /* Set MMC I/O to 52Mhz */ | |
84 | prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1); | |
85 | prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL; | |
86 | omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1); | |
87 | } else { | |
88 | reg |= OMAP2_PBIASSPEEDCTRL0; | |
89 | } | |
90c62bf0 TL |
90 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; |
91 | omap_ctrl_writel(reg, control_pbias_offset); | |
db0fefc5 AH |
92 | } else { |
93 | reg = omap_ctrl_readl(control_pbias_offset); | |
94 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; | |
95 | omap_ctrl_writel(reg, control_pbias_offset); | |
96 | } | |
97 | } | |
98 | ||
c83c8e6c | 99 | static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, |
db0fefc5 AH |
100 | int power_on, int vdd) |
101 | { | |
102 | u32 reg; | |
90c62bf0 | 103 | |
db0fefc5 AH |
104 | /* 100ms delay required for PBIAS configuration */ |
105 | msleep(100); | |
90c62bf0 | 106 | |
db0fefc5 | 107 | if (power_on) { |
90c62bf0 TL |
108 | reg = omap_ctrl_readl(control_pbias_offset); |
109 | reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); | |
110 | if ((1 << vdd) <= MMC_VDD_165_195) | |
111 | reg &= ~OMAP2_PBIASLITEVMODE0; | |
112 | else | |
113 | reg |= OMAP2_PBIASLITEVMODE0; | |
114 | omap_ctrl_writel(reg, control_pbias_offset); | |
115 | } else { | |
90c62bf0 TL |
116 | reg = omap_ctrl_readl(control_pbias_offset); |
117 | reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | | |
118 | OMAP2_PBIASLITEVMODE0); | |
119 | omap_ctrl_writel(reg, control_pbias_offset); | |
120 | } | |
90c62bf0 TL |
121 | } |
122 | ||
c83c8e6c | 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 | */ | |
dcf5ef3f SS |
138 | reg = omap4_ctrl_pad_readl(control_pbias_offset); |
139 | reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | | |
140 | OMAP4_MMC1_PWRDNZ_MASK | | |
141 | OMAP4_USBC1_ICUSB_PWRDNZ_MASK); | |
142 | omap4_ctrl_pad_writel(reg, control_pbias_offset); | |
c83c8e6c | 143 | } |
144 | ||
145 | static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot, | |
146 | int power_on, int vdd) | |
147 | { | |
148 | u32 reg; | |
149 | ||
150 | if (power_on) { | |
dcf5ef3f SS |
151 | reg = omap4_ctrl_pad_readl(control_pbias_offset); |
152 | reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK; | |
c83c8e6c | 153 | if ((1 << vdd) <= MMC_VDD_165_195) |
dcf5ef3f | 154 | reg &= ~OMAP4_MMC1_PBIASLITE_VMODE_MASK; |
c83c8e6c | 155 | else |
dcf5ef3f SS |
156 | reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK; |
157 | reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | | |
158 | OMAP4_MMC1_PWRDNZ_MASK | | |
159 | OMAP4_USBC1_ICUSB_PWRDNZ_MASK); | |
160 | omap4_ctrl_pad_writel(reg, control_pbias_offset); | |
c83c8e6c | 161 | /* 4 microsec delay for comparator to generate an error*/ |
162 | udelay(4); | |
dcf5ef3f SS |
163 | reg = omap4_ctrl_pad_readl(control_pbias_offset); |
164 | if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) { | |
c83c8e6c | 165 | pr_err("Pbias Voltage is not same as LDO\n"); |
166 | /* Caution : On VMODE_ERROR Power Down MMC IO */ | |
dcf5ef3f SS |
167 | reg &= ~(OMAP4_MMC1_PWRDNZ_MASK | |
168 | OMAP4_USBC1_ICUSB_PWRDNZ_MASK); | |
169 | omap4_ctrl_pad_writel(reg, control_pbias_offset); | |
c83c8e6c | 170 | } |
171 | } else { | |
dcf5ef3f SS |
172 | reg = omap4_ctrl_pad_readl(control_pbias_offset); |
173 | reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | | |
174 | OMAP4_MMC1_PWRDNZ_MASK | | |
175 | OMAP4_MMC1_PBIASLITE_VMODE_MASK | | |
176 | OMAP4_USBC1_ICUSB_PWRDNZ_MASK); | |
177 | omap4_ctrl_pad_writel(reg, control_pbias_offset); | |
c83c8e6c | 178 | } |
179 | } | |
180 | ||
db0fefc5 AH |
181 | static void hsmmc23_before_set_reg(struct device *dev, int slot, |
182 | int power_on, int vdd) | |
90c62bf0 | 183 | { |
90c62bf0 | 184 | struct omap_mmc_platform_data *mmc = dev->platform_data; |
b583f26d | 185 | |
ce6f0016 AH |
186 | if (mmc->slots[0].remux) |
187 | mmc->slots[0].remux(dev, slot, power_on); | |
188 | ||
90c62bf0 | 189 | if (power_on) { |
db0fefc5 | 190 | /* Only MMC2 supports a CLKIN */ |
90c62bf0 TL |
191 | if (mmc->slots[0].internal_clock) { |
192 | u32 reg; | |
193 | ||
194 | reg = omap_ctrl_readl(control_devconf1_offset); | |
195 | reg |= OMAP2_MMCSDIO2ADPCLKISEL; | |
196 | omap_ctrl_writel(reg, control_devconf1_offset); | |
197 | } | |
9b7c18e0 | 198 | } |
9b7c18e0 AH |
199 | } |
200 | ||
03e7e170 | 201 | static int nop_mmc_set_power(struct device *dev, int slot, int power_on, |
202 | int vdd) | |
203 | { | |
204 | return 0; | |
205 | } | |
206 | ||
90c62bf0 TL |
207 | static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; |
208 | ||
68ff0423 | 209 | void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) |
90c62bf0 | 210 | { |
68ff0423 | 211 | struct omap2_hsmmc_info *c; |
90c62bf0 | 212 | int nr_hsmmc = ARRAY_SIZE(hsmmc_data); |
a6c7fdd2 | 213 | int i; |
c83c8e6c | 214 | u32 reg; |
90c62bf0 | 215 | |
c83c8e6c | 216 | if (!cpu_is_omap44xx()) { |
217 | if (cpu_is_omap2430()) { | |
218 | control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; | |
219 | control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | |
220 | } else { | |
221 | control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | |
222 | control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | |
223 | } | |
90c62bf0 | 224 | } else { |
dcf5ef3f SS |
225 | control_pbias_offset = |
226 | OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE; | |
227 | control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1; | |
228 | reg = omap4_ctrl_pad_readl(control_mmc1); | |
229 | reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK | | |
230 | OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK); | |
231 | reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK | | |
232 | OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK); | |
233 | reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK| | |
234 | OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK | | |
235 | OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK); | |
236 | omap4_ctrl_pad_writel(reg, control_mmc1); | |
90c62bf0 TL |
237 | } |
238 | ||
239 | for (c = controllers; c->mmc; c++) { | |
68ff0423 | 240 | struct hsmmc_controller *hc = hsmmc + c->mmc - 1; |
90c62bf0 TL |
241 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; |
242 | ||
243 | if (!c->mmc || c->mmc > nr_hsmmc) { | |
244 | pr_debug("MMC%d: no such controller\n", c->mmc); | |
245 | continue; | |
246 | } | |
247 | if (mmc) { | |
248 | pr_debug("MMC%d: already configured\n", c->mmc); | |
249 | continue; | |
250 | } | |
251 | ||
68ff0423 AH |
252 | mmc = kzalloc(sizeof(struct omap_mmc_platform_data), |
253 | GFP_KERNEL); | |
90c62bf0 TL |
254 | if (!mmc) { |
255 | pr_err("Cannot allocate memory for mmc device!\n"); | |
a6c7fdd2 | 256 | goto done; |
90c62bf0 TL |
257 | } |
258 | ||
e51151a5 | 259 | if (c->name) |
68ff0423 | 260 | strncpy(hc->name, c->name, HSMMC_NAME_LEN); |
e51151a5 | 261 | else |
68ff0423 | 262 | snprintf(hc->name, ARRAY_SIZE(hc->name), |
e51151a5 | 263 | "mmc%islot%i", c->mmc, 1); |
68ff0423 | 264 | mmc->slots[0].name = hc->name; |
90c62bf0 | 265 | mmc->nr_slots = 1; |
3a63833e | 266 | mmc->slots[0].caps = c->caps; |
90c62bf0 TL |
267 | mmc->slots[0].internal_clock = !c->ext_clock; |
268 | mmc->dma_mask = 0xffffffff; | |
91a0b089 | 269 | if (cpu_is_omap44xx()) |
270 | mmc->reg_offset = OMAP4_MMC_REG_OFFSET; | |
271 | else | |
272 | mmc->reg_offset = 0; | |
90c62bf0 | 273 | |
68ff0423 | 274 | mmc->get_context_loss_count = hsmmc_get_context_loss; |
1887bde3 | 275 | |
db0fefc5 AH |
276 | mmc->slots[0].switch_pin = c->gpio_cd; |
277 | mmc->slots[0].gpio_wp = c->gpio_wp; | |
90c62bf0 | 278 | |
ce6f0016 | 279 | mmc->slots[0].remux = c->remux; |
ed199f7e | 280 | mmc->slots[0].init_card = c->init_card; |
ce6f0016 | 281 | |
db0fefc5 AH |
282 | if (c->cover_only) |
283 | mmc->slots[0].cover = 1; | |
90c62bf0 | 284 | |
23d99bb9 AH |
285 | if (c->nonremovable) |
286 | mmc->slots[0].nonremovable = 1; | |
287 | ||
dd498eff DK |
288 | if (c->power_saving) |
289 | mmc->slots[0].power_saving = 1; | |
290 | ||
1df58db8 AH |
291 | if (c->no_off) |
292 | mmc->slots[0].no_off = 1; | |
293 | ||
e0eb2424 AH |
294 | if (c->vcc_aux_disable_is_sleep) |
295 | mmc->slots[0].vcc_aux_disable_is_sleep = 1; | |
296 | ||
b583f26d DB |
297 | /* NOTE: MMC slots should have a Vcc regulator set up. |
298 | * This may be from a TWL4030-family chip, another | |
299 | * controllable regulator, or a fixed supply. | |
300 | * | |
301 | * temporary HACK: ocr_mask instead of fixed supply | |
90c62bf0 | 302 | */ |
b583f26d | 303 | mmc->slots[0].ocr_mask = c->ocr_mask; |
90c62bf0 | 304 | |
03e7e170 | 305 | if (cpu_is_omap3517() || cpu_is_omap3505()) |
306 | mmc->slots[0].set_power = nop_mmc_set_power; | |
307 | else | |
308 | mmc->slots[0].features |= HSMMC_HAS_PBIAS; | |
309 | ||
07ad64b6 MC |
310 | if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0)) |
311 | mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET; | |
312 | ||
90c62bf0 TL |
313 | switch (c->mmc) { |
314 | case 1: | |
03e7e170 | 315 | if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { |
316 | /* on-chip level shifting via PBIAS0/PBIAS1 */ | |
c83c8e6c | 317 | if (cpu_is_omap44xx()) { |
318 | mmc->slots[0].before_set_reg = | |
319 | omap4_hsmmc1_before_set_reg; | |
320 | mmc->slots[0].after_set_reg = | |
321 | omap4_hsmmc1_after_set_reg; | |
322 | } else { | |
323 | mmc->slots[0].before_set_reg = | |
324 | omap_hsmmc1_before_set_reg; | |
325 | mmc->slots[0].after_set_reg = | |
326 | omap_hsmmc1_after_set_reg; | |
327 | } | |
03e7e170 | 328 | } |
41fd03d6 M |
329 | |
330 | /* Omap3630 HSMMC1 supports only 4-bit */ | |
3a63833e SG |
331 | if (cpu_is_omap3630() && |
332 | (c->caps & MMC_CAP_8_BIT_DATA)) { | |
333 | c->caps &= ~MMC_CAP_8_BIT_DATA; | |
334 | c->caps |= MMC_CAP_4_BIT_DATA; | |
335 | mmc->slots[0].caps = c->caps; | |
41fd03d6 | 336 | } |
90c62bf0 TL |
337 | break; |
338 | case 2: | |
b583f26d DB |
339 | if (c->ext_clock) |
340 | c->transceiver = 1; | |
3a63833e SG |
341 | if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) { |
342 | c->caps &= ~MMC_CAP_8_BIT_DATA; | |
343 | c->caps |= MMC_CAP_4_BIT_DATA; | |
344 | } | |
b583f26d | 345 | /* FALLTHROUGH */ |
07d83cc9 | 346 | case 3: |
03e7e170 | 347 | if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { |
348 | /* off-chip level shifting, or none */ | |
349 | mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; | |
350 | mmc->slots[0].after_set_reg = NULL; | |
351 | } | |
07d83cc9 | 352 | break; |
90c62bf0 TL |
353 | default: |
354 | pr_err("MMC%d configuration not supported!\n", c->mmc); | |
07d83cc9 | 355 | kfree(mmc); |
90c62bf0 TL |
356 | continue; |
357 | } | |
358 | hsmmc_data[c->mmc - 1] = mmc; | |
359 | } | |
360 | ||
361 | omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC); | |
01971f65 DB |
362 | |
363 | /* pass the device nodes back to board setup code */ | |
364 | for (c = controllers; c->mmc; c++) { | |
365 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; | |
366 | ||
367 | if (!c->mmc || c->mmc > nr_hsmmc) | |
368 | continue; | |
369 | c->dev = mmc->dev; | |
370 | } | |
a6c7fdd2 AK |
371 | |
372 | done: | |
373 | for (i = 0; i < nr_hsmmc; i++) | |
374 | kfree(hsmmc_data[i]); | |
90c62bf0 TL |
375 | } |
376 | ||
377 | #endif |