Commit | Line | Data |
---|---|---|
90c62bf0 TL |
1 | /* |
2 | * linux/arch/arm/mach-omap2/mmc-twl4030.c | |
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 | */ | |
12 | #include <linux/err.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/gpio.h> | |
b583f26d DB |
19 | #include <linux/mmc/host.h> |
20 | #include <linux/regulator/consumer.h> | |
90c62bf0 TL |
21 | |
22 | #include <mach/hardware.h> | |
23 | #include <mach/control.h> | |
24 | #include <mach/mmc.h> | |
25 | #include <mach/board.h> | |
26 | ||
27 | #include "mmc-twl4030.h" | |
28 | ||
90c62bf0 | 29 | |
b583f26d DB |
30 | #if defined(CONFIG_REGULATOR) && \ |
31 | (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) | |
90c62bf0 TL |
32 | |
33 | static u16 control_pbias_offset; | |
34 | static u16 control_devconf1_offset; | |
35 | ||
36 | #define HSMMC_NAME_LEN 9 | |
37 | ||
38 | static struct twl_mmc_controller { | |
39 | struct omap_mmc_platform_data *mmc; | |
b583f26d DB |
40 | /* Vcc == configured supply |
41 | * Vcc_alt == optional | |
42 | * - MMC1, supply for DAT4..DAT7 | |
43 | * - MMC2/MMC2, external level shifter voltage supply, for | |
44 | * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) | |
45 | */ | |
46 | struct regulator *vcc; | |
47 | struct regulator *vcc_aux; | |
48 | char name[HSMMC_NAME_LEN + 1]; | |
49 | } hsmmc[OMAP34XX_NR_MMC]; | |
90c62bf0 TL |
50 | |
51 | static int twl_mmc_card_detect(int irq) | |
52 | { | |
53 | unsigned i; | |
54 | ||
55 | for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { | |
56 | struct omap_mmc_platform_data *mmc; | |
57 | ||
58 | mmc = hsmmc[i].mmc; | |
59 | if (!mmc) | |
60 | continue; | |
61 | if (irq != mmc->slots[0].card_detect_irq) | |
62 | continue; | |
63 | ||
64 | /* NOTE: assumes card detect signal is active-low */ | |
65 | return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); | |
66 | } | |
67 | return -ENOSYS; | |
68 | } | |
69 | ||
70 | static int twl_mmc_get_ro(struct device *dev, int slot) | |
71 | { | |
72 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
73 | ||
74 | /* NOTE: assumes write protect signal is active-high */ | |
75 | return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); | |
76 | } | |
77 | ||
8d75e98b AH |
78 | static int twl_mmc_get_cover_state(struct device *dev, int slot) |
79 | { | |
80 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
81 | ||
82 | /* NOTE: assumes card detect signal is active-low */ | |
83 | return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); | |
84 | } | |
85 | ||
90c62bf0 TL |
86 | /* |
87 | * MMC Slot Initialization. | |
88 | */ | |
89 | static int twl_mmc_late_init(struct device *dev) | |
90 | { | |
91 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
92 | int ret = 0; | |
93 | int i; | |
94 | ||
b583f26d DB |
95 | /* MMC/SD/SDIO doesn't require a card detect switch */ |
96 | if (gpio_is_valid(mmc->slots[0].switch_pin)) { | |
97 | ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); | |
98 | if (ret) | |
99 | goto done; | |
100 | ret = gpio_direction_input(mmc->slots[0].switch_pin); | |
101 | if (ret) | |
102 | goto err; | |
103 | } | |
90c62bf0 | 104 | |
b583f26d | 105 | /* require at least main regulator */ |
90c62bf0 TL |
106 | for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { |
107 | if (hsmmc[i].name == mmc->slots[0].name) { | |
b583f26d DB |
108 | struct regulator *reg; |
109 | ||
90c62bf0 | 110 | hsmmc[i].mmc = mmc; |
b583f26d DB |
111 | |
112 | reg = regulator_get(dev, "vmmc"); | |
113 | if (IS_ERR(reg)) { | |
114 | dev_dbg(dev, "vmmc regulator missing\n"); | |
115 | /* HACK: until fixed.c regulator is usable, | |
116 | * we don't require a main regulator | |
117 | * for MMC2 or MMC3 | |
118 | */ | |
119 | if (i != 0) | |
120 | break; | |
121 | ret = PTR_ERR(reg); | |
22833044 | 122 | hsmmc[i].vcc = NULL; |
b583f26d DB |
123 | goto err; |
124 | } | |
125 | hsmmc[i].vcc = reg; | |
126 | mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg); | |
127 | ||
128 | /* allow an aux regulator */ | |
129 | reg = regulator_get(dev, "vmmc_aux"); | |
130 | hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg; | |
131 | ||
132 | /* UGLY HACK: workaround regulator framework bugs. | |
133 | * When the bootloader leaves a supply active, it's | |
134 | * initialized with zero usecount ... and we can't | |
135 | * disable it without first enabling it. Until the | |
136 | * framework is fixed, we need a workaround like this | |
137 | * (which is safe for MMC, but not in general). | |
138 | */ | |
139 | if (regulator_is_enabled(hsmmc[i].vcc) > 0) { | |
140 | regulator_enable(hsmmc[i].vcc); | |
141 | regulator_disable(hsmmc[i].vcc); | |
142 | } | |
143 | if (hsmmc[i].vcc_aux) { | |
144 | if (regulator_is_enabled(reg) > 0) { | |
145 | regulator_enable(reg); | |
146 | regulator_disable(reg); | |
147 | } | |
148 | } | |
149 | ||
90c62bf0 TL |
150 | break; |
151 | } | |
152 | } | |
153 | ||
154 | return 0; | |
155 | ||
156 | err: | |
157 | gpio_free(mmc->slots[0].switch_pin); | |
158 | done: | |
159 | mmc->slots[0].card_detect_irq = 0; | |
160 | mmc->slots[0].card_detect = NULL; | |
161 | ||
162 | dev_err(dev, "err %d configuring card detect\n", ret); | |
163 | return ret; | |
164 | } | |
165 | ||
166 | static void twl_mmc_cleanup(struct device *dev) | |
167 | { | |
168 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
22833044 | 169 | int i; |
90c62bf0 TL |
170 | |
171 | gpio_free(mmc->slots[0].switch_pin); | |
22833044 RQ |
172 | for(i = 0; i < ARRAY_SIZE(hsmmc); i++) { |
173 | regulator_put(hsmmc[i].vcc); | |
174 | regulator_put(hsmmc[i].vcc_aux); | |
175 | } | |
90c62bf0 TL |
176 | } |
177 | ||
178 | #ifdef CONFIG_PM | |
179 | ||
180 | static int twl_mmc_suspend(struct device *dev, int slot) | |
181 | { | |
182 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
183 | ||
184 | disable_irq(mmc->slots[0].card_detect_irq); | |
185 | return 0; | |
186 | } | |
187 | ||
188 | static int twl_mmc_resume(struct device *dev, int slot) | |
189 | { | |
190 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
191 | ||
192 | enable_irq(mmc->slots[0].card_detect_irq); | |
193 | return 0; | |
194 | } | |
195 | ||
196 | #else | |
197 | #define twl_mmc_suspend NULL | |
198 | #define twl_mmc_resume NULL | |
199 | #endif | |
200 | ||
1887bde3 DK |
201 | #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) |
202 | ||
203 | static int twl4030_mmc_get_context_loss(struct device *dev) | |
204 | { | |
205 | /* FIXME: PM DPS not implemented yet */ | |
206 | return 0; | |
207 | } | |
208 | ||
209 | #else | |
210 | #define twl4030_mmc_get_context_loss NULL | |
211 | #endif | |
212 | ||
90c62bf0 TL |
213 | static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, |
214 | int vdd) | |
215 | { | |
216 | u32 reg; | |
217 | int ret = 0; | |
218 | struct twl_mmc_controller *c = &hsmmc[0]; | |
219 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
220 | ||
0329c377 DB |
221 | /* |
222 | * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | |
b583f26d | 223 | * card with Vcc regulator (from twl4030 or whatever). OMAP has both |
0329c377 DB |
224 | * 1.8V and 3.0V modes, controlled by the PBIAS register. |
225 | * | |
226 | * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | |
227 | * is most naturally TWL VSIM; those pins also use PBIAS. | |
b583f26d DB |
228 | * |
229 | * FIXME handle VMMC1A as needed ... | |
0329c377 | 230 | */ |
90c62bf0 TL |
231 | if (power_on) { |
232 | if (cpu_is_omap2430()) { | |
233 | reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); | |
234 | if ((1 << vdd) >= MMC_VDD_30_31) | |
235 | reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE; | |
236 | else | |
237 | reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE; | |
238 | omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); | |
239 | } | |
240 | ||
241 | if (mmc->slots[0].internal_clock) { | |
242 | reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); | |
243 | reg |= OMAP2_MMCSDIO1ADPCLKISEL; | |
244 | omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); | |
245 | } | |
246 | ||
247 | reg = omap_ctrl_readl(control_pbias_offset); | |
248 | reg |= OMAP2_PBIASSPEEDCTRL0; | |
249 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; | |
250 | omap_ctrl_writel(reg, control_pbias_offset); | |
251 | ||
b583f26d | 252 | ret = mmc_regulator_set_ocr(c->vcc, vdd); |
90c62bf0 TL |
253 | |
254 | /* 100ms delay required for PBIAS configuration */ | |
255 | msleep(100); | |
256 | reg = omap_ctrl_readl(control_pbias_offset); | |
257 | reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); | |
258 | if ((1 << vdd) <= MMC_VDD_165_195) | |
259 | reg &= ~OMAP2_PBIASLITEVMODE0; | |
260 | else | |
261 | reg |= OMAP2_PBIASLITEVMODE0; | |
262 | omap_ctrl_writel(reg, control_pbias_offset); | |
263 | } else { | |
264 | reg = omap_ctrl_readl(control_pbias_offset); | |
265 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; | |
266 | omap_ctrl_writel(reg, control_pbias_offset); | |
267 | ||
b583f26d | 268 | ret = mmc_regulator_set_ocr(c->vcc, 0); |
90c62bf0 TL |
269 | |
270 | /* 100ms delay required for PBIAS configuration */ | |
271 | msleep(100); | |
272 | reg = omap_ctrl_readl(control_pbias_offset); | |
273 | reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | | |
274 | OMAP2_PBIASLITEVMODE0); | |
275 | omap_ctrl_writel(reg, control_pbias_offset); | |
276 | } | |
277 | ||
278 | return ret; | |
279 | } | |
280 | ||
b583f26d | 281 | static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd) |
90c62bf0 | 282 | { |
b583f26d | 283 | int ret = 0; |
762ad3a4 | 284 | struct twl_mmc_controller *c = NULL; |
90c62bf0 | 285 | struct omap_mmc_platform_data *mmc = dev->platform_data; |
762ad3a4 GI |
286 | int i; |
287 | ||
288 | for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { | |
289 | if (mmc == hsmmc[i].mmc) { | |
290 | c = &hsmmc[i]; | |
291 | break; | |
292 | } | |
293 | } | |
294 | ||
295 | if (c == NULL) | |
296 | return -ENODEV; | |
90c62bf0 | 297 | |
b583f26d DB |
298 | /* If we don't see a Vcc regulator, assume it's a fixed |
299 | * voltage always-on regulator. | |
300 | */ | |
301 | if (!c->vcc) | |
302 | return 0; | |
303 | ||
0329c377 | 304 | /* |
b583f26d | 305 | * Assume Vcc regulator is used only to power the card ... OMAP |
0329c377 DB |
306 | * VDDS is used to power the pins, optionally with a transceiver to |
307 | * support cards using voltages other than VDDS (1.8V nominal). When a | |
308 | * transceiver is used, DAT3..7 are muxed as transceiver control pins. | |
b583f26d DB |
309 | * |
310 | * In some cases this regulator won't support enable/disable; | |
311 | * e.g. it's a fixed rail for a WLAN chip. | |
312 | * | |
313 | * In other cases vcc_aux switches interface power. Example, for | |
314 | * eMMC cards it represents VccQ. Sometimes transceivers or SDIO | |
315 | * chips/cards need an interface voltage rail too. | |
0329c377 | 316 | */ |
90c62bf0 | 317 | if (power_on) { |
b583f26d | 318 | /* only MMC2 supports a CLKIN */ |
90c62bf0 TL |
319 | if (mmc->slots[0].internal_clock) { |
320 | u32 reg; | |
321 | ||
322 | reg = omap_ctrl_readl(control_devconf1_offset); | |
323 | reg |= OMAP2_MMCSDIO2ADPCLKISEL; | |
324 | omap_ctrl_writel(reg, control_devconf1_offset); | |
325 | } | |
b583f26d DB |
326 | ret = mmc_regulator_set_ocr(c->vcc, vdd); |
327 | /* enable interface voltage rail, if needed */ | |
328 | if (ret == 0 && c->vcc_aux) { | |
329 | ret = regulator_enable(c->vcc_aux); | |
330 | if (ret < 0) | |
331 | ret = mmc_regulator_set_ocr(c->vcc, 0); | |
332 | } | |
90c62bf0 | 333 | } else { |
b583f26d DB |
334 | if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0) |
335 | ret = regulator_disable(c->vcc_aux); | |
336 | if (ret == 0) | |
337 | ret = mmc_regulator_set_ocr(c->vcc, 0); | |
90c62bf0 TL |
338 | } |
339 | ||
340 | return ret; | |
341 | } | |
342 | ||
9b7c18e0 AH |
343 | static int twl_mmc1_set_sleep(struct device *dev, int slot, int sleep, int vdd, |
344 | int cardsleep) | |
345 | { | |
346 | struct twl_mmc_controller *c = &hsmmc[0]; | |
347 | int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; | |
348 | ||
349 | return regulator_set_mode(c->vcc, mode); | |
350 | } | |
351 | ||
352 | static int twl_mmc23_set_sleep(struct device *dev, int slot, int sleep, int vdd, | |
353 | int cardsleep) | |
354 | { | |
355 | struct twl_mmc_controller *c = NULL; | |
356 | struct omap_mmc_platform_data *mmc = dev->platform_data; | |
357 | int i, err, mode; | |
358 | ||
359 | for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { | |
360 | if (mmc == hsmmc[i].mmc) { | |
361 | c = &hsmmc[i]; | |
362 | break; | |
363 | } | |
364 | } | |
365 | ||
366 | if (c == NULL) | |
367 | return -ENODEV; | |
368 | ||
369 | /* | |
370 | * If we don't see a Vcc regulator, assume it's a fixed | |
371 | * voltage always-on regulator. | |
372 | */ | |
373 | if (!c->vcc) | |
374 | return 0; | |
375 | ||
376 | mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; | |
377 | ||
378 | if (!c->vcc_aux) | |
379 | return regulator_set_mode(c->vcc, mode); | |
380 | ||
381 | if (cardsleep) { | |
382 | /* VCC can be turned off if card is asleep */ | |
383 | struct regulator *vcc_aux = c->vcc_aux; | |
384 | ||
385 | c->vcc_aux = NULL; | |
386 | if (sleep) | |
387 | err = twl_mmc23_set_power(dev, slot, 0, 0); | |
388 | else | |
389 | err = twl_mmc23_set_power(dev, slot, 1, vdd); | |
390 | c->vcc_aux = vcc_aux; | |
391 | } else | |
392 | err = regulator_set_mode(c->vcc, mode); | |
393 | if (err) | |
394 | return err; | |
395 | return regulator_set_mode(c->vcc_aux, mode); | |
396 | } | |
397 | ||
90c62bf0 TL |
398 | static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; |
399 | ||
400 | void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) | |
401 | { | |
402 | struct twl4030_hsmmc_info *c; | |
403 | int nr_hsmmc = ARRAY_SIZE(hsmmc_data); | |
404 | ||
405 | if (cpu_is_omap2430()) { | |
406 | control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; | |
407 | control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | |
408 | nr_hsmmc = 2; | |
409 | } else { | |
410 | control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | |
411 | control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | |
412 | } | |
413 | ||
414 | for (c = controllers; c->mmc; c++) { | |
415 | struct twl_mmc_controller *twl = hsmmc + c->mmc - 1; | |
416 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; | |
417 | ||
418 | if (!c->mmc || c->mmc > nr_hsmmc) { | |
419 | pr_debug("MMC%d: no such controller\n", c->mmc); | |
420 | continue; | |
421 | } | |
422 | if (mmc) { | |
423 | pr_debug("MMC%d: already configured\n", c->mmc); | |
424 | continue; | |
425 | } | |
426 | ||
427 | mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); | |
428 | if (!mmc) { | |
429 | pr_err("Cannot allocate memory for mmc device!\n"); | |
430 | return; | |
431 | } | |
432 | ||
e51151a5 AH |
433 | if (c->name) |
434 | strncpy(twl->name, c->name, HSMMC_NAME_LEN); | |
435 | else | |
436 | snprintf(twl->name, ARRAY_SIZE(twl->name), | |
437 | "mmc%islot%i", c->mmc, 1); | |
90c62bf0 TL |
438 | mmc->slots[0].name = twl->name; |
439 | mmc->nr_slots = 1; | |
90c62bf0 TL |
440 | mmc->slots[0].wires = c->wires; |
441 | mmc->slots[0].internal_clock = !c->ext_clock; | |
442 | mmc->dma_mask = 0xffffffff; | |
b583f26d | 443 | mmc->init = twl_mmc_late_init; |
90c62bf0 | 444 | |
b583f26d | 445 | /* note: twl4030 card detect GPIOs can disable VMMCx ... */ |
90c62bf0 | 446 | if (gpio_is_valid(c->gpio_cd)) { |
90c62bf0 TL |
447 | mmc->cleanup = twl_mmc_cleanup; |
448 | mmc->suspend = twl_mmc_suspend; | |
449 | mmc->resume = twl_mmc_resume; | |
450 | ||
451 | mmc->slots[0].switch_pin = c->gpio_cd; | |
452 | mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd); | |
8d75e98b AH |
453 | if (c->cover_only) |
454 | mmc->slots[0].get_cover_state = twl_mmc_get_cover_state; | |
455 | else | |
456 | mmc->slots[0].card_detect = twl_mmc_card_detect; | |
90c62bf0 TL |
457 | } else |
458 | mmc->slots[0].switch_pin = -EINVAL; | |
459 | ||
1887bde3 DK |
460 | mmc->get_context_loss_count = |
461 | twl4030_mmc_get_context_loss; | |
462 | ||
90c62bf0 TL |
463 | /* write protect normally uses an OMAP gpio */ |
464 | if (gpio_is_valid(c->gpio_wp)) { | |
465 | gpio_request(c->gpio_wp, "mmc_wp"); | |
466 | gpio_direction_input(c->gpio_wp); | |
467 | ||
468 | mmc->slots[0].gpio_wp = c->gpio_wp; | |
469 | mmc->slots[0].get_ro = twl_mmc_get_ro; | |
470 | } else | |
471 | mmc->slots[0].gpio_wp = -EINVAL; | |
472 | ||
23d99bb9 AH |
473 | if (c->nonremovable) |
474 | mmc->slots[0].nonremovable = 1; | |
475 | ||
dd498eff DK |
476 | if (c->power_saving) |
477 | mmc->slots[0].power_saving = 1; | |
478 | ||
b583f26d DB |
479 | /* NOTE: MMC slots should have a Vcc regulator set up. |
480 | * This may be from a TWL4030-family chip, another | |
481 | * controllable regulator, or a fixed supply. | |
482 | * | |
483 | * temporary HACK: ocr_mask instead of fixed supply | |
90c62bf0 | 484 | */ |
b583f26d | 485 | mmc->slots[0].ocr_mask = c->ocr_mask; |
90c62bf0 TL |
486 | |
487 | switch (c->mmc) { | |
488 | case 1: | |
b583f26d | 489 | /* on-chip level shifting via PBIAS0/PBIAS1 */ |
90c62bf0 | 490 | mmc->slots[0].set_power = twl_mmc1_set_power; |
9b7c18e0 | 491 | mmc->slots[0].set_sleep = twl_mmc1_set_sleep; |
90c62bf0 TL |
492 | break; |
493 | case 2: | |
b583f26d DB |
494 | if (c->ext_clock) |
495 | c->transceiver = 1; | |
496 | if (c->transceiver && c->wires > 4) | |
497 | c->wires = 4; | |
498 | /* FALLTHROUGH */ | |
07d83cc9 | 499 | case 3: |
b583f26d DB |
500 | /* off-chip level shifting, or none */ |
501 | mmc->slots[0].set_power = twl_mmc23_set_power; | |
9b7c18e0 | 502 | mmc->slots[0].set_sleep = twl_mmc23_set_sleep; |
07d83cc9 | 503 | break; |
90c62bf0 TL |
504 | default: |
505 | pr_err("MMC%d configuration not supported!\n", c->mmc); | |
07d83cc9 | 506 | kfree(mmc); |
90c62bf0 TL |
507 | continue; |
508 | } | |
509 | hsmmc_data[c->mmc - 1] = mmc; | |
510 | } | |
511 | ||
512 | omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC); | |
01971f65 DB |
513 | |
514 | /* pass the device nodes back to board setup code */ | |
515 | for (c = controllers; c->mmc; c++) { | |
516 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; | |
517 | ||
518 | if (!c->mmc || c->mmc > nr_hsmmc) | |
519 | continue; | |
520 | c->dev = mmc->dev; | |
521 | } | |
90c62bf0 TL |
522 | } |
523 | ||
524 | #endif |