diff options
author | Tony Lindgren <tony@atomide.com> | 2010-02-26 18:31:12 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-02-26 18:31:12 -0500 |
commit | 9418c65f9bd861d0f7e39aab9cfb3aa6f2275d11 (patch) | |
tree | 73c496cfc8d05b75a57fbad2569fcf897cd1b0b5 /arch | |
parent | 7b97f3edf35fdb41e507e5711ac1d6221cf7abf2 (diff) |
omap2: Initialize Menelaus and MMC for N8X0
Initialize MMC for N8X0
Based on an earlier patches from Nokia released kernel
sources at:
http://repository.maemo.org/pool/os2008/free/source/k/kernel-source-rx-34/
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/board-n8x0.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 9de03f8e2e68..4cab0522d7ce 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/stddef.h> | 19 | #include <linux/stddef.h> |
20 | #include <linux/i2c.h> | ||
20 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
21 | #include <linux/usb/musb.h> | 22 | #include <linux/usb/musb.h> |
22 | 23 | ||
@@ -25,11 +26,17 @@ | |||
25 | 26 | ||
26 | #include <plat/board.h> | 27 | #include <plat/board.h> |
27 | #include <plat/common.h> | 28 | #include <plat/common.h> |
29 | #include <plat/menelaus.h> | ||
28 | #include <mach/irqs.h> | 30 | #include <mach/irqs.h> |
29 | #include <plat/mcspi.h> | 31 | #include <plat/mcspi.h> |
30 | #include <plat/onenand.h> | 32 | #include <plat/onenand.h> |
33 | #include <plat/mmc.h> | ||
31 | #include <plat/serial.h> | 34 | #include <plat/serial.h> |
32 | 35 | ||
36 | static int slot1_cover_open; | ||
37 | static int slot2_cover_open; | ||
38 | static struct device *mmc_device; | ||
39 | |||
33 | static struct omap2_mcspi_device_config p54spi_mcspi_config = { | 40 | static struct omap2_mcspi_device_config p54spi_mcspi_config = { |
34 | .turbo_mode = 0, | 41 | .turbo_mode = 0, |
35 | .single_channel = 1, | 42 | .single_channel = 1, |
@@ -96,6 +103,442 @@ static void __init n8x0_onenand_init(void) {} | |||
96 | 103 | ||
97 | #endif | 104 | #endif |
98 | 105 | ||
106 | #if defined(CONFIG_MENELAUS) && \ | ||
107 | (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)) | ||
108 | |||
109 | /* | ||
110 | * On both N800 and N810, only the first of the two MMC controllers is in use. | ||
111 | * The two MMC slots are multiplexed via Menelaus companion chip over I2C. | ||
112 | * On N800, both slots are powered via Menelaus. On N810, only one of the | ||
113 | * slots is powered via Menelaus. The N810 EMMC is powered via GPIO. | ||
114 | * | ||
115 | * VMMC slot 1 on both N800 and N810 | ||
116 | * VDCDC3_APE and VMCS2_APE slot 2 on N800 | ||
117 | * GPIO23 and GPIO9 slot 2 EMMC on N810 | ||
118 | * | ||
119 | */ | ||
120 | #define N8X0_SLOT_SWITCH_GPIO 96 | ||
121 | #define N810_EMMC_VSD_GPIO 23 | ||
122 | #define NN810_EMMC_VIO_GPIO 9 | ||
123 | |||
124 | static int n8x0_mmc_switch_slot(struct device *dev, int slot) | ||
125 | { | ||
126 | #ifdef CONFIG_MMC_DEBUG | ||
127 | dev_dbg(dev, "Choose slot %d\n", slot + 1); | ||
128 | #endif | ||
129 | gpio_set_value(N8X0_SLOT_SWITCH_GPIO, slot); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int n8x0_mmc_set_power_menelaus(struct device *dev, int slot, | ||
134 | int power_on, int vdd) | ||
135 | { | ||
136 | int mV; | ||
137 | |||
138 | #ifdef CONFIG_MMC_DEBUG | ||
139 | dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1, | ||
140 | power_on ? "on" : "off", vdd); | ||
141 | #endif | ||
142 | if (slot == 0) { | ||
143 | if (!power_on) | ||
144 | return menelaus_set_vmmc(0); | ||
145 | switch (1 << vdd) { | ||
146 | case MMC_VDD_33_34: | ||
147 | case MMC_VDD_32_33: | ||
148 | case MMC_VDD_31_32: | ||
149 | mV = 3100; | ||
150 | break; | ||
151 | case MMC_VDD_30_31: | ||
152 | mV = 3000; | ||
153 | break; | ||
154 | case MMC_VDD_28_29: | ||
155 | mV = 2800; | ||
156 | break; | ||
157 | case MMC_VDD_165_195: | ||
158 | mV = 1850; | ||
159 | break; | ||
160 | default: | ||
161 | BUG(); | ||
162 | } | ||
163 | return menelaus_set_vmmc(mV); | ||
164 | } else { | ||
165 | if (!power_on) | ||
166 | return menelaus_set_vdcdc(3, 0); | ||
167 | switch (1 << vdd) { | ||
168 | case MMC_VDD_33_34: | ||
169 | case MMC_VDD_32_33: | ||
170 | mV = 3300; | ||
171 | break; | ||
172 | case MMC_VDD_30_31: | ||
173 | case MMC_VDD_29_30: | ||
174 | mV = 3000; | ||
175 | break; | ||
176 | case MMC_VDD_28_29: | ||
177 | case MMC_VDD_27_28: | ||
178 | mV = 2800; | ||
179 | break; | ||
180 | case MMC_VDD_24_25: | ||
181 | case MMC_VDD_23_24: | ||
182 | mV = 2400; | ||
183 | break; | ||
184 | case MMC_VDD_22_23: | ||
185 | case MMC_VDD_21_22: | ||
186 | mV = 2200; | ||
187 | break; | ||
188 | case MMC_VDD_20_21: | ||
189 | mV = 2000; | ||
190 | break; | ||
191 | case MMC_VDD_165_195: | ||
192 | mV = 1800; | ||
193 | break; | ||
194 | default: | ||
195 | BUG(); | ||
196 | } | ||
197 | return menelaus_set_vdcdc(3, mV); | ||
198 | } | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void n810_set_power_emmc(struct device *dev, | ||
203 | int power_on) | ||
204 | { | ||
205 | dev_dbg(dev, "Set EMMC power %s\n", power_on ? "on" : "off"); | ||
206 | |||
207 | if (power_on) { | ||
208 | gpio_set_value(N810_EMMC_VSD_GPIO, 1); | ||
209 | msleep(1); | ||
210 | gpio_set_value(NN810_EMMC_VIO_GPIO, 1); | ||
211 | msleep(1); | ||
212 | } else { | ||
213 | gpio_set_value(NN810_EMMC_VIO_GPIO, 0); | ||
214 | msleep(50); | ||
215 | gpio_set_value(N810_EMMC_VSD_GPIO, 0); | ||
216 | msleep(50); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static int n8x0_mmc_set_power(struct device *dev, int slot, int power_on, | ||
221 | int vdd) | ||
222 | { | ||
223 | if (machine_is_nokia_n800() || slot == 0) | ||
224 | return n8x0_mmc_set_power_menelaus(dev, slot, power_on, vdd); | ||
225 | |||
226 | n810_set_power_emmc(dev, power_on); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int n8x0_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode) | ||
232 | { | ||
233 | int r; | ||
234 | |||
235 | dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1, | ||
236 | bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull"); | ||
237 | BUG_ON(slot != 0 && slot != 1); | ||
238 | slot++; | ||
239 | switch (bus_mode) { | ||
240 | case MMC_BUSMODE_OPENDRAIN: | ||
241 | r = menelaus_set_mmc_opendrain(slot, 1); | ||
242 | break; | ||
243 | case MMC_BUSMODE_PUSHPULL: | ||
244 | r = menelaus_set_mmc_opendrain(slot, 0); | ||
245 | break; | ||
246 | default: | ||
247 | BUG(); | ||
248 | } | ||
249 | if (r != 0 && printk_ratelimit()) | ||
250 | dev_err(dev, "MMC: unable to set bus mode for slot %d\n", | ||
251 | slot); | ||
252 | return r; | ||
253 | } | ||
254 | |||
255 | static int n8x0_mmc_get_cover_state(struct device *dev, int slot) | ||
256 | { | ||
257 | slot++; | ||
258 | BUG_ON(slot != 1 && slot != 2); | ||
259 | if (slot == 1) | ||
260 | return slot1_cover_open; | ||
261 | else | ||
262 | return slot2_cover_open; | ||
263 | } | ||
264 | |||
265 | static void n8x0_mmc_callback(void *data, u8 card_mask) | ||
266 | { | ||
267 | int bit, *openp, index; | ||
268 | |||
269 | if (machine_is_nokia_n800()) { | ||
270 | bit = 1 << 1; | ||
271 | openp = &slot2_cover_open; | ||
272 | index = 1; | ||
273 | } else { | ||
274 | bit = 1; | ||
275 | openp = &slot1_cover_open; | ||
276 | index = 0; | ||
277 | } | ||
278 | |||
279 | if (card_mask & bit) | ||
280 | *openp = 1; | ||
281 | else | ||
282 | *openp = 0; | ||
283 | |||
284 | omap_mmc_notify_cover_event(mmc_device, index, *openp); | ||
285 | } | ||
286 | |||
287 | void n8x0_mmc_slot1_cover_handler(void *arg, int closed_state) | ||
288 | { | ||
289 | if (mmc_device == NULL) | ||
290 | return; | ||
291 | |||
292 | slot1_cover_open = !closed_state; | ||
293 | omap_mmc_notify_cover_event(mmc_device, 0, closed_state); | ||
294 | } | ||
295 | |||
296 | static int n8x0_mmc_late_init(struct device *dev) | ||
297 | { | ||
298 | int r, bit, *openp; | ||
299 | int vs2sel; | ||
300 | |||
301 | mmc_device = dev; | ||
302 | |||
303 | r = menelaus_set_slot_sel(1); | ||
304 | if (r < 0) | ||
305 | return r; | ||
306 | |||
307 | if (machine_is_nokia_n800()) | ||
308 | vs2sel = 0; | ||
309 | else | ||
310 | vs2sel = 2; | ||
311 | |||
312 | r = menelaus_set_mmc_slot(2, 0, vs2sel, 1); | ||
313 | if (r < 0) | ||
314 | return r; | ||
315 | |||
316 | n8x0_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */ | ||
317 | n8x0_mmc_set_power(dev, 1, MMC_POWER_ON, 16); | ||
318 | |||
319 | r = menelaus_set_mmc_slot(1, 1, 0, 1); | ||
320 | if (r < 0) | ||
321 | return r; | ||
322 | r = menelaus_set_mmc_slot(2, 1, vs2sel, 1); | ||
323 | if (r < 0) | ||
324 | return r; | ||
325 | |||
326 | r = menelaus_get_slot_pin_states(); | ||
327 | if (r < 0) | ||
328 | return r; | ||
329 | |||
330 | if (machine_is_nokia_n800()) { | ||
331 | bit = 1 << 1; | ||
332 | openp = &slot2_cover_open; | ||
333 | } else { | ||
334 | bit = 1; | ||
335 | openp = &slot1_cover_open; | ||
336 | slot2_cover_open = 0; | ||
337 | } | ||
338 | |||
339 | /* All slot pin bits seem to be inversed until first switch change */ | ||
340 | if (r == 0xf || r == (0xf & ~bit)) | ||
341 | r = ~r; | ||
342 | |||
343 | if (r & bit) | ||
344 | *openp = 1; | ||
345 | else | ||
346 | *openp = 0; | ||
347 | |||
348 | r = menelaus_register_mmc_callback(n8x0_mmc_callback, NULL); | ||
349 | |||
350 | return r; | ||
351 | } | ||
352 | |||
353 | static void n8x0_mmc_shutdown(struct device *dev) | ||
354 | { | ||
355 | int vs2sel; | ||
356 | |||
357 | if (machine_is_nokia_n800()) | ||
358 | vs2sel = 0; | ||
359 | else | ||
360 | vs2sel = 2; | ||
361 | |||
362 | menelaus_set_mmc_slot(1, 0, 0, 0); | ||
363 | menelaus_set_mmc_slot(2, 0, vs2sel, 0); | ||
364 | } | ||
365 | |||
366 | static void n8x0_mmc_cleanup(struct device *dev) | ||
367 | { | ||
368 | menelaus_unregister_mmc_callback(); | ||
369 | |||
370 | gpio_free(N8X0_SLOT_SWITCH_GPIO); | ||
371 | |||
372 | if (machine_is_nokia_n810()) { | ||
373 | gpio_free(N810_EMMC_VSD_GPIO); | ||
374 | gpio_free(NN810_EMMC_VIO_GPIO); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * MMC controller1 has two slots that are multiplexed via I2C. | ||
380 | * MMC controller2 is not in use. | ||
381 | */ | ||
382 | static struct omap_mmc_platform_data mmc1_data = { | ||
383 | .nr_slots = 2, | ||
384 | .switch_slot = n8x0_mmc_switch_slot, | ||
385 | .init = n8x0_mmc_late_init, | ||
386 | .cleanup = n8x0_mmc_cleanup, | ||
387 | .shutdown = n8x0_mmc_shutdown, | ||
388 | .max_freq = 24000000, | ||
389 | .dma_mask = 0xffffffff, | ||
390 | .slots[0] = { | ||
391 | .wires = 4, | ||
392 | .set_power = n8x0_mmc_set_power, | ||
393 | .set_bus_mode = n8x0_mmc_set_bus_mode, | ||
394 | .get_cover_state = n8x0_mmc_get_cover_state, | ||
395 | .ocr_mask = MMC_VDD_165_195 | MMC_VDD_30_31 | | ||
396 | MMC_VDD_32_33 | MMC_VDD_33_34, | ||
397 | .name = "internal", | ||
398 | }, | ||
399 | .slots[1] = { | ||
400 | .set_power = n8x0_mmc_set_power, | ||
401 | .set_bus_mode = n8x0_mmc_set_bus_mode, | ||
402 | .get_cover_state = n8x0_mmc_get_cover_state, | ||
403 | .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21 | | ||
404 | MMC_VDD_21_22 | MMC_VDD_22_23 | | ||
405 | MMC_VDD_23_24 | MMC_VDD_24_25 | | ||
406 | MMC_VDD_27_28 | MMC_VDD_28_29 | | ||
407 | MMC_VDD_29_30 | MMC_VDD_30_31 | | ||
408 | MMC_VDD_32_33 | MMC_VDD_33_34, | ||
409 | .name = "external", | ||
410 | }, | ||
411 | }; | ||
412 | |||
413 | static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC]; | ||
414 | |||
415 | void __init n8x0_mmc_init(void) | ||
416 | |||
417 | { | ||
418 | int err; | ||
419 | |||
420 | if (machine_is_nokia_n810()) { | ||
421 | mmc1_data.slots[0].name = "external"; | ||
422 | |||
423 | /* | ||
424 | * Some Samsung Movinand chips do not like open-ended | ||
425 | * multi-block reads and fall to braind-dead state | ||
426 | * while doing so. Reducing the number of blocks in | ||
427 | * the transfer or delays in clock disable do not help | ||
428 | */ | ||
429 | mmc1_data.slots[1].name = "internal"; | ||
430 | mmc1_data.slots[1].ban_openended = 1; | ||
431 | } | ||
432 | |||
433 | err = gpio_request(N8X0_SLOT_SWITCH_GPIO, "MMC slot switch"); | ||
434 | if (err) | ||
435 | return err; | ||
436 | |||
437 | gpio_direction_output(N8X0_SLOT_SWITCH_GPIO, 0); | ||
438 | |||
439 | if (machine_is_nokia_n810()) { | ||
440 | err = gpio_request(N810_EMMC_VSD_GPIO, "MMC slot 2 Vddf"); | ||
441 | if (err) { | ||
442 | gpio_free(N8X0_SLOT_SWITCH_GPIO); | ||
443 | return err; | ||
444 | } | ||
445 | gpio_direction_output(N810_EMMC_VSD_GPIO, 0); | ||
446 | |||
447 | err = gpio_request(NN810_EMMC_VIO_GPIO, "MMC slot 2 Vdd"); | ||
448 | if (err) { | ||
449 | gpio_free(N8X0_SLOT_SWITCH_GPIO); | ||
450 | gpio_free(N810_EMMC_VSD_GPIO); | ||
451 | return err; | ||
452 | } | ||
453 | gpio_direction_output(NN810_EMMC_VIO_GPIO, 0); | ||
454 | } | ||
455 | |||
456 | mmc_data[0] = &mmc1_data; | ||
457 | omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC); | ||
458 | } | ||
459 | #else | ||
460 | |||
461 | void __init n8x0_mmc_init(void) | ||
462 | { | ||
463 | } | ||
464 | |||
465 | void n8x0_mmc_slot1_cover_handler(void *arg, int state) | ||
466 | { | ||
467 | } | ||
468 | |||
469 | #endif /* CONFIG_MMC_OMAP */ | ||
470 | |||
471 | #ifdef CONFIG_MENELAUS | ||
472 | |||
473 | static int n8x0_auto_sleep_regulators(void) | ||
474 | { | ||
475 | u32 val; | ||
476 | int ret; | ||
477 | |||
478 | val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \ | ||
479 | | EN_VAUX_SLEEP | EN_VIO_SLEEP \ | ||
480 | | EN_VMEM_SLEEP | EN_DC3_SLEEP \ | ||
481 | | EN_VC_SLEEP | EN_DC2_SLEEP; | ||
482 | |||
483 | ret = menelaus_set_regulator_sleep(1, val); | ||
484 | if (ret < 0) { | ||
485 | printk(KERN_ERR "Could not set regulators to sleep on " | ||
486 | "menelaus: %u\n", ret); | ||
487 | return ret; | ||
488 | } | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int n8x0_auto_voltage_scale(void) | ||
493 | { | ||
494 | int ret; | ||
495 | |||
496 | ret = menelaus_set_vcore_hw(1400, 1050); | ||
497 | if (ret < 0) { | ||
498 | printk(KERN_ERR "Could not set VCORE voltage on " | ||
499 | "menelaus: %u\n", ret); | ||
500 | return ret; | ||
501 | } | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int n8x0_menelaus_late_init(struct device *dev) | ||
506 | { | ||
507 | int ret; | ||
508 | |||
509 | ret = n8x0_auto_voltage_scale(); | ||
510 | if (ret < 0) | ||
511 | return ret; | ||
512 | ret = n8x0_auto_sleep_regulators(); | ||
513 | if (ret < 0) | ||
514 | return ret; | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] = { | ||
519 | { | ||
520 | I2C_BOARD_INFO("menelaus", 0x72), | ||
521 | .irq = INT_24XX_SYS_NIRQ, | ||
522 | }, | ||
523 | }; | ||
524 | |||
525 | static struct menelaus_platform_data n8x0_menelaus_platform_data = { | ||
526 | .late_init = n8x0_menelaus_late_init, | ||
527 | }; | ||
528 | |||
529 | static void __init n8x0_menelaus_init(void) | ||
530 | { | ||
531 | n8x0_i2c_board_info_1[0].platform_data = &n8x0_menelaus_platform_data; | ||
532 | omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1, | ||
533 | ARRAY_SIZE(n8x0_i2c_board_info_1)); | ||
534 | } | ||
535 | |||
536 | #else | ||
537 | static inline void __init n8x0_menelaus_init(void) | ||
538 | { | ||
539 | } | ||
540 | #endif | ||
541 | |||
99 | static void __init n8x0_map_io(void) | 542 | static void __init n8x0_map_io(void) |
100 | { | 543 | { |
101 | omap2_set_globals_242x(); | 544 | omap2_set_globals_242x(); |
@@ -116,7 +559,9 @@ static void __init n8x0_init_machine(void) | |||
116 | ARRAY_SIZE(n800_spi_board_info)); | 559 | ARRAY_SIZE(n800_spi_board_info)); |
117 | 560 | ||
118 | omap_serial_init(); | 561 | omap_serial_init(); |
562 | n8x0_menelaus_init(); | ||
119 | n8x0_onenand_init(); | 563 | n8x0_onenand_init(); |
564 | n8x0_mmc_init(); | ||
120 | } | 565 | } |
121 | 566 | ||
122 | MACHINE_START(NOKIA_N800, "Nokia N800") | 567 | MACHINE_START(NOKIA_N800, "Nokia N800") |