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