blob: be2b3deeef1da7acf3fd3f62a665874e3e689a9e [file] [log] [blame]
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +00001/*
2 * linux/arch/mips/jz4740/board-qi_lb60.c
3 *
4 * QI_LB60 board support
5 *
6 * Copyright (c) 2009 Qi Hardware inc.,
7 * Author: Xiangfu Liu <xiangfu@qi-hardware.com>
Lars-Peter Clausenfe749aa2010-11-04 23:25:56 +01008 * Copyright 2010, Lars-Peter Clausen <lars@metafoo.de>
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +00009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 or later
12 * as published by the Free Software Foundation.
13 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/gpio.h>
18
19#include <linux/input.h>
20#include <linux/gpio_keys.h>
21#include <linux/input/matrix_keypad.h>
22#include <linux/spi/spi.h>
23#include <linux/spi/spi_gpio.h>
24#include <linux/power_supply.h>
25#include <linux/power/jz4740-battery.h>
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +010026#include <linux/power/gpio-charger.h>
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000027
28#include <asm/mach-jz4740/jz4740_fb.h>
29#include <asm/mach-jz4740/jz4740_mmc.h>
30#include <asm/mach-jz4740/jz4740_nand.h>
31
32#include <linux/regulator/fixed.h>
33#include <linux/regulator/machine.h>
34
35#include <linux/leds_pwm.h>
36
37#include <asm/mach-jz4740/platform.h>
38
39#include "clock.h"
40
41static bool is_avt2;
42
43/* GPIOs */
44#define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0)
45#define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2)
46
47#define QI_LB60_GPIO_KEYOUT(x) (JZ_GPIO_PORTC(10) + (x))
48#define QI_LB60_GPIO_KEYIN(x) (JZ_GPIO_PORTD(18) + (x))
49#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)
50
51/* NAND */
52static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
Lars-Peter Clausenc8fb4022011-02-08 03:43:54 +010053 .eccbytes = 36,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000054 .eccpos = {
Ralf Baechle70342282013-01-22 12:59:30 +010055 6, 7, 8, 9, 10, 11, 12, 13,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000056 14, 15, 16, 17, 18, 19, 20, 21,
57 22, 23, 24, 25, 26, 27, 28, 29,
58 30, 31, 32, 33, 34, 35, 36, 37,
59 38, 39, 40, 41
Lars-Peter Clausenc8fb4022011-02-08 03:43:54 +010060 },
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000061 .oobfree = {
62 { .offset = 2, .length = 4 },
63 { .offset = 42, .length = 22 }
64 },
65};
66
67/* Early prototypes of the QI LB60 had only 1GB of NAND.
Lucas De Marchi25985ed2011-03-30 22:57:33 -030068 * In order to support these devices as well the partition and ecc layout is
Uwe Kleine-Königb5950762010-11-01 15:38:34 -040069 * initialized depending on the NAND size */
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000070static struct mtd_partition qi_lb60_partitions_1gb[] = {
71 {
72 .name = "NAND BOOT partition",
73 .offset = 0 * 0x100000,
74 .size = 4 * 0x100000,
75 },
76 {
77 .name = "NAND KERNEL partition",
78 .offset = 4 * 0x100000,
79 .size = 4 * 0x100000,
80 },
81 {
82 .name = "NAND ROOTFS partition",
83 .offset = 8 * 0x100000,
84 .size = (504 + 512) * 0x100000,
85 },
86};
87
88static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
Lars-Peter Clausenc8fb4022011-02-08 03:43:54 +010089 .eccbytes = 72,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +000090 .eccpos = {
91 12, 13, 14, 15, 16, 17, 18, 19,
92 20, 21, 22, 23, 24, 25, 26, 27,
93 28, 29, 30, 31, 32, 33, 34, 35,
94 36, 37, 38, 39, 40, 41, 42, 43,
95 44, 45, 46, 47, 48, 49, 50, 51,
96 52, 53, 54, 55, 56, 57, 58, 59,
97 60, 61, 62, 63, 64, 65, 66, 67,
98 68, 69, 70, 71, 72, 73, 74, 75,
99 76, 77, 78, 79, 80, 81, 82, 83
Lars-Peter Clausenc8fb4022011-02-08 03:43:54 +0100100 },
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000101 .oobfree = {
102 { .offset = 2, .length = 10 },
103 { .offset = 84, .length = 44 },
104 },
105};
106
107static struct mtd_partition qi_lb60_partitions_2gb[] = {
108 {
109 .name = "NAND BOOT partition",
110 .offset = 0 * 0x100000,
111 .size = 4 * 0x100000,
112 },
113 {
114 .name = "NAND KERNEL partition",
115 .offset = 4 * 0x100000,
116 .size = 4 * 0x100000,
117 },
118 {
119 .name = "NAND ROOTFS partition",
120 .offset = 8 * 0x100000,
121 .size = (504 + 512 + 1024) * 0x100000,
122 },
123};
124
125static void qi_lb60_nand_ident(struct platform_device *pdev,
126 struct nand_chip *chip, struct mtd_partition **partitions,
127 int *num_partitions)
128{
129 if (chip->page_shift == 12) {
130 chip->ecc.layout = &qi_lb60_ecclayout_2gb;
131 *partitions = qi_lb60_partitions_2gb;
132 *num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
133 } else {
134 chip->ecc.layout = &qi_lb60_ecclayout_1gb;
135 *partitions = qi_lb60_partitions_1gb;
136 *num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
137 }
138}
139
140static struct jz_nand_platform_data qi_lb60_nand_pdata = {
141 .ident_callback = qi_lb60_nand_ident,
142 .busy_gpio = 94,
Maarten ter Huurne56635d72012-03-29 19:17:02 +0200143 .banks = { 1 },
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000144};
145
146/* Keyboard*/
147
148#define KEY_QI_QI KEY_F13
149#define KEY_QI_UPRED KEY_RIGHTALT
150#define KEY_QI_VOLUP KEY_VOLUMEUP
151#define KEY_QI_VOLDOWN KEY_VOLUMEDOWN
152#define KEY_QI_FN KEY_LEFTCTRL
153
154static const uint32_t qi_lb60_keymap[] = {
155 KEY(0, 0, KEY_F1), /* S2 */
156 KEY(0, 1, KEY_F2), /* S3 */
157 KEY(0, 2, KEY_F3), /* S4 */
158 KEY(0, 3, KEY_F4), /* S5 */
159 KEY(0, 4, KEY_F5), /* S6 */
160 KEY(0, 5, KEY_F6), /* S7 */
161 KEY(0, 6, KEY_F7), /* S8 */
162
163 KEY(1, 0, KEY_Q), /* S10 */
164 KEY(1, 1, KEY_W), /* S11 */
165 KEY(1, 2, KEY_E), /* S12 */
166 KEY(1, 3, KEY_R), /* S13 */
167 KEY(1, 4, KEY_T), /* S14 */
168 KEY(1, 5, KEY_Y), /* S15 */
169 KEY(1, 6, KEY_U), /* S16 */
170 KEY(1, 7, KEY_I), /* S17 */
171 KEY(2, 0, KEY_A), /* S18 */
172 KEY(2, 1, KEY_S), /* S19 */
173 KEY(2, 2, KEY_D), /* S20 */
174 KEY(2, 3, KEY_F), /* S21 */
175 KEY(2, 4, KEY_G), /* S22 */
176 KEY(2, 5, KEY_H), /* S23 */
177 KEY(2, 6, KEY_J), /* S24 */
178 KEY(2, 7, KEY_K), /* S25 */
179 KEY(3, 0, KEY_ESC), /* S26 */
180 KEY(3, 1, KEY_Z), /* S27 */
181 KEY(3, 2, KEY_X), /* S28 */
182 KEY(3, 3, KEY_C), /* S29 */
183 KEY(3, 4, KEY_V), /* S30 */
184 KEY(3, 5, KEY_B), /* S31 */
185 KEY(3, 6, KEY_N), /* S32 */
186 KEY(3, 7, KEY_M), /* S33 */
187 KEY(4, 0, KEY_TAB), /* S34 */
188 KEY(4, 1, KEY_CAPSLOCK), /* S35 */
189 KEY(4, 2, KEY_BACKSLASH), /* S36 */
190 KEY(4, 3, KEY_APOSTROPHE), /* S37 */
191 KEY(4, 4, KEY_COMMA), /* S38 */
192 KEY(4, 5, KEY_DOT), /* S39 */
193 KEY(4, 6, KEY_SLASH), /* S40 */
194 KEY(4, 7, KEY_UP), /* S41 */
195 KEY(5, 0, KEY_O), /* S42 */
196 KEY(5, 1, KEY_L), /* S43 */
197 KEY(5, 2, KEY_EQUAL), /* S44 */
198 KEY(5, 3, KEY_QI_UPRED), /* S45 */
199 KEY(5, 4, KEY_SPACE), /* S46 */
200 KEY(5, 5, KEY_QI_QI), /* S47 */
201 KEY(5, 6, KEY_RIGHTCTRL), /* S48 */
202 KEY(5, 7, KEY_LEFT), /* S49 */
203 KEY(6, 0, KEY_F8), /* S50 */
204 KEY(6, 1, KEY_P), /* S51 */
205 KEY(6, 2, KEY_BACKSPACE),/* S52 */
206 KEY(6, 3, KEY_ENTER), /* S53 */
207 KEY(6, 4, KEY_QI_VOLUP), /* S54 */
208 KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */
209 KEY(6, 6, KEY_DOWN), /* S56 */
210 KEY(6, 7, KEY_RIGHT), /* S57 */
211
212 KEY(7, 0, KEY_LEFTSHIFT), /* S58 */
Ralf Baechle70342282013-01-22 12:59:30 +0100213 KEY(7, 1, KEY_LEFTALT), /* S59 */
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000214 KEY(7, 2, KEY_QI_FN), /* S60 */
215};
216
217static const struct matrix_keymap_data qi_lb60_keymap_data = {
218 .keymap = qi_lb60_keymap,
219 .keymap_size = ARRAY_SIZE(qi_lb60_keymap),
220};
221
222static const unsigned int qi_lb60_keypad_cols[] = {
223 QI_LB60_GPIO_KEYOUT(0),
224 QI_LB60_GPIO_KEYOUT(1),
225 QI_LB60_GPIO_KEYOUT(2),
226 QI_LB60_GPIO_KEYOUT(3),
227 QI_LB60_GPIO_KEYOUT(4),
228 QI_LB60_GPIO_KEYOUT(5),
229 QI_LB60_GPIO_KEYOUT(6),
230 QI_LB60_GPIO_KEYOUT(7),
231};
232
233static const unsigned int qi_lb60_keypad_rows[] = {
234 QI_LB60_GPIO_KEYIN(0),
235 QI_LB60_GPIO_KEYIN(1),
236 QI_LB60_GPIO_KEYIN(2),
237 QI_LB60_GPIO_KEYIN(3),
238 QI_LB60_GPIO_KEYIN(4),
239 QI_LB60_GPIO_KEYIN(5),
Lars-Peter Clausenfe749aa2010-11-04 23:25:56 +0100240 QI_LB60_GPIO_KEYIN(6),
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000241 QI_LB60_GPIO_KEYIN8,
242};
243
244static struct matrix_keypad_platform_data qi_lb60_pdata = {
245 .keymap_data = &qi_lb60_keymap_data,
246 .col_gpios = qi_lb60_keypad_cols,
247 .row_gpios = qi_lb60_keypad_rows,
248 .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols),
249 .num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows),
250 .col_scan_delay_us = 10,
251 .debounce_ms = 10,
252 .wakeup = 1,
253 .active_low = 1,
254};
255
256static struct platform_device qi_lb60_keypad = {
257 .name = "matrix-keypad",
258 .id = -1,
259 .dev = {
260 .platform_data = &qi_lb60_pdata,
261 },
262};
263
264/* Display */
265static struct fb_videomode qi_lb60_video_modes[] = {
266 {
267 .name = "320x240",
268 .xres = 320,
269 .yres = 240,
270 .refresh = 30,
271 .left_margin = 140,
272 .right_margin = 273,
273 .upper_margin = 20,
274 .lower_margin = 2,
275 .hsync_len = 1,
276 .vsync_len = 1,
277 .sync = 0,
278 .vmode = FB_VMODE_NONINTERLACED,
279 },
280};
281
282static struct jz4740_fb_platform_data qi_lb60_fb_pdata = {
283 .width = 60,
284 .height = 45,
285 .num_modes = ARRAY_SIZE(qi_lb60_video_modes),
286 .modes = qi_lb60_video_modes,
287 .bpp = 24,
288 .lcd_type = JZ_LCD_TYPE_8BIT_SERIAL,
289 .pixclk_falling_edge = 1,
290};
291
292struct spi_gpio_platform_data spigpio_platform_data = {
293 .sck = JZ_GPIO_PORTC(23),
294 .mosi = JZ_GPIO_PORTC(22),
295 .miso = -1,
296 .num_chipselect = 1,
297};
298
299static struct platform_device spigpio_device = {
300 .name = "spi_gpio",
301 .id = 1,
302 .dev = {
303 .platform_data = &spigpio_platform_data,
304 },
305};
306
307static struct spi_board_info qi_lb60_spi_board_info[] = {
308 {
309 .modalias = "ili8960",
310 .controller_data = (void *)JZ_GPIO_PORTC(21),
311 .chip_select = 0,
312 .bus_num = 1,
313 .max_speed_hz = 30 * 1000,
314 .mode = SPI_3WIRE,
315 },
316};
317
318/* Battery */
319static struct jz_battery_platform_data qi_lb60_battery_pdata = {
Ralf Baechle70342282013-01-22 12:59:30 +0100320 .gpio_charge = JZ_GPIO_PORTC(27),
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000321 .gpio_charge_active_low = 1,
322 .info = {
323 .name = "battery",
324 .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
325 .voltage_max_design = 4200000,
326 .voltage_min_design = 3600000,
327 },
328};
329
330/* GPIO Key: power */
331static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = {
332 [0] = {
333 .code = KEY_POWER,
334 .gpio = JZ_GPIO_PORTD(29),
335 .active_low = 1,
336 .desc = "Power",
337 .wakeup = 1,
338 },
339};
340
341static struct gpio_keys_platform_data qi_lb60_gpio_keys_data = {
342 .nbuttons = ARRAY_SIZE(qi_lb60_gpio_keys_buttons),
343 .buttons = qi_lb60_gpio_keys_buttons,
344};
345
346static struct platform_device qi_lb60_gpio_keys = {
Ralf Baechle70342282013-01-22 12:59:30 +0100347 .name = "gpio-keys",
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000348 .id = -1,
349 .dev = {
350 .platform_data = &qi_lb60_gpio_keys_data,
351 }
352};
353
354static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
355 .gpio_card_detect = QI_LB60_GPIO_SD_CD,
356 .gpio_read_only = -1,
357 .gpio_power = QI_LB60_GPIO_SD_VCC_EN_N,
358 .power_active_low = 1,
359};
360
361/* OHCI */
362static struct regulator_consumer_supply avt2_usb_regulator_consumer =
363 REGULATOR_SUPPLY("vbus", "jz4740-ohci");
364
365static struct regulator_init_data avt2_usb_regulator_init_data = {
366 .num_consumer_supplies = 1,
367 .consumer_supplies = &avt2_usb_regulator_consumer,
368 .constraints = {
369 .name = "USB power",
370 .min_uV = 5000000,
371 .max_uV = 5000000,
372 .valid_modes_mask = REGULATOR_MODE_NORMAL,
373 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
374 },
375};
376
377static struct fixed_voltage_config avt2_usb_regulator_data = {
378 .supply_name = "USB power",
379 .microvolts = 5000000,
380 .gpio = JZ_GPIO_PORTB(17),
381 .init_data = &avt2_usb_regulator_init_data,
382};
383
384static struct platform_device avt2_usb_regulator_device = {
385 .name = "reg-fixed-voltage",
386 .id = -1,
387 .dev = {
388 .platform_data = &avt2_usb_regulator_data,
389 }
390};
391
392/* beeper */
393static struct platform_device qi_lb60_pwm_beeper = {
394 .name = "pwm-beeper",
395 .id = -1,
396 .dev = {
397 .platform_data = (void *)4,
398 },
399};
400
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100401/* charger */
402static char *qi_lb60_batteries[] = {
403 "battery",
404};
405
406static struct gpio_charger_platform_data qi_lb60_charger_pdata = {
407 .name = "usb",
408 .type = POWER_SUPPLY_TYPE_USB,
409 .gpio = JZ_GPIO_PORTD(28),
410 .gpio_active_low = 1,
411 .supplied_to = qi_lb60_batteries,
412 .num_supplicants = ARRAY_SIZE(qi_lb60_batteries),
413};
414
415static struct platform_device qi_lb60_charger_device = {
416 .name = "gpio-charger",
417 .dev = {
418 .platform_data = &qi_lb60_charger_pdata,
419 },
420};
421
Axel Linb33005f32012-01-06 11:30:10 +0800422/* audio */
423static struct platform_device qi_lb60_audio_device = {
424 .name = "qi-lb60-audio",
425 .id = -1,
426};
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100427
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000428static struct platform_device *jz_platform_devices[] __initdata = {
429 &jz4740_udc_device,
430 &jz4740_mmc_device,
431 &jz4740_nand_device,
432 &qi_lb60_keypad,
433 &spigpio_device,
434 &jz4740_framebuffer_device,
435 &jz4740_pcm_device,
436 &jz4740_i2s_device,
437 &jz4740_codec_device,
438 &jz4740_rtc_device,
439 &jz4740_adc_device,
Thierry Redingf6b8a572012-08-22 10:01:24 +0200440 &jz4740_pwm_device,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000441 &qi_lb60_gpio_keys,
442 &qi_lb60_pwm_beeper,
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100443 &qi_lb60_charger_device,
Axel Linb33005f32012-01-06 11:30:10 +0800444 &qi_lb60_audio_device,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000445};
446
447static void __init board_gpio_setup(void)
448{
449 /* We only need to enable/disable pullup here for pins used in generic
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300450 * drivers. Everything else is done by the drivers themselves. */
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000451 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
452 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
453}
454
455static int __init qi_lb60_init_platform_devices(void)
456{
457 jz4740_framebuffer_device.dev.platform_data = &qi_lb60_fb_pdata;
458 jz4740_nand_device.dev.platform_data = &qi_lb60_nand_pdata;
459 jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
460 jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
461
462 jz4740_serial_device_register();
463
464 spi_register_board_info(qi_lb60_spi_board_info,
465 ARRAY_SIZE(qi_lb60_spi_board_info));
466
467 if (is_avt2) {
468 platform_device_register(&avt2_usb_regulator_device);
469 platform_device_register(&jz4740_usb_ohci_device);
470 }
471
472 return platform_add_devices(jz_platform_devices,
473 ARRAY_SIZE(jz_platform_devices));
474
475}
476
477struct jz4740_clock_board_data jz4740_clock_bdata = {
478 .ext_rate = 12000000,
479 .rtc_rate = 32768,
480};
481
482static __init int board_avt2(char *str)
483{
484 qi_lb60_mmc_pdata.card_detect_active_low = 1;
485 is_avt2 = true;
486
487 return 1;
488}
489__setup("avt2", board_avt2);
490
491static int __init qi_lb60_board_setup(void)
492{
493 printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n",
494 is_avt2 ? "AVT2" : "LB60");
495
496 board_gpio_setup();
497
498 if (qi_lb60_init_platform_devices())
Ralf Baechleab75dc02011-11-17 15:07:31 +0000499 panic("Failed to initialize platform devices");
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000500
501 return 0;
502}
503arch_initcall(qi_lb60_board_setup);