blob: 9dd051edb411f2a5b68f2f5b4ae77bfbe6115d57 [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,
Maarten ter Huurne56635d72012-03-29 19:17:02 +0200143 .banks = { 1 },
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000144};
145
Lars-Peter Clausencd145af2014-12-02 20:48:26 +0100146static struct gpiod_lookup_table qi_lb60_nand_gpio_table = {
147 .dev_id = "jz4740-nand.0",
148 .table = {
149 GPIO_LOOKUP("Bank C", 30, "busy", 0),
150 { },
151 },
152};
153
154
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000155/* Keyboard*/
156
157#define KEY_QI_QI KEY_F13
158#define KEY_QI_UPRED KEY_RIGHTALT
159#define KEY_QI_VOLUP KEY_VOLUMEUP
160#define KEY_QI_VOLDOWN KEY_VOLUMEDOWN
161#define KEY_QI_FN KEY_LEFTCTRL
162
163static const uint32_t qi_lb60_keymap[] = {
164 KEY(0, 0, KEY_F1), /* S2 */
165 KEY(0, 1, KEY_F2), /* S3 */
166 KEY(0, 2, KEY_F3), /* S4 */
167 KEY(0, 3, KEY_F4), /* S5 */
168 KEY(0, 4, KEY_F5), /* S6 */
169 KEY(0, 5, KEY_F6), /* S7 */
170 KEY(0, 6, KEY_F7), /* S8 */
171
172 KEY(1, 0, KEY_Q), /* S10 */
173 KEY(1, 1, KEY_W), /* S11 */
174 KEY(1, 2, KEY_E), /* S12 */
175 KEY(1, 3, KEY_R), /* S13 */
176 KEY(1, 4, KEY_T), /* S14 */
177 KEY(1, 5, KEY_Y), /* S15 */
178 KEY(1, 6, KEY_U), /* S16 */
179 KEY(1, 7, KEY_I), /* S17 */
180 KEY(2, 0, KEY_A), /* S18 */
181 KEY(2, 1, KEY_S), /* S19 */
182 KEY(2, 2, KEY_D), /* S20 */
183 KEY(2, 3, KEY_F), /* S21 */
184 KEY(2, 4, KEY_G), /* S22 */
185 KEY(2, 5, KEY_H), /* S23 */
186 KEY(2, 6, KEY_J), /* S24 */
187 KEY(2, 7, KEY_K), /* S25 */
188 KEY(3, 0, KEY_ESC), /* S26 */
189 KEY(3, 1, KEY_Z), /* S27 */
190 KEY(3, 2, KEY_X), /* S28 */
191 KEY(3, 3, KEY_C), /* S29 */
192 KEY(3, 4, KEY_V), /* S30 */
193 KEY(3, 5, KEY_B), /* S31 */
194 KEY(3, 6, KEY_N), /* S32 */
195 KEY(3, 7, KEY_M), /* S33 */
196 KEY(4, 0, KEY_TAB), /* S34 */
197 KEY(4, 1, KEY_CAPSLOCK), /* S35 */
198 KEY(4, 2, KEY_BACKSLASH), /* S36 */
199 KEY(4, 3, KEY_APOSTROPHE), /* S37 */
200 KEY(4, 4, KEY_COMMA), /* S38 */
201 KEY(4, 5, KEY_DOT), /* S39 */
202 KEY(4, 6, KEY_SLASH), /* S40 */
203 KEY(4, 7, KEY_UP), /* S41 */
204 KEY(5, 0, KEY_O), /* S42 */
205 KEY(5, 1, KEY_L), /* S43 */
206 KEY(5, 2, KEY_EQUAL), /* S44 */
207 KEY(5, 3, KEY_QI_UPRED), /* S45 */
208 KEY(5, 4, KEY_SPACE), /* S46 */
209 KEY(5, 5, KEY_QI_QI), /* S47 */
210 KEY(5, 6, KEY_RIGHTCTRL), /* S48 */
211 KEY(5, 7, KEY_LEFT), /* S49 */
212 KEY(6, 0, KEY_F8), /* S50 */
213 KEY(6, 1, KEY_P), /* S51 */
214 KEY(6, 2, KEY_BACKSPACE),/* S52 */
215 KEY(6, 3, KEY_ENTER), /* S53 */
216 KEY(6, 4, KEY_QI_VOLUP), /* S54 */
217 KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */
218 KEY(6, 6, KEY_DOWN), /* S56 */
219 KEY(6, 7, KEY_RIGHT), /* S57 */
220
221 KEY(7, 0, KEY_LEFTSHIFT), /* S58 */
Ralf Baechle70342282013-01-22 12:59:30 +0100222 KEY(7, 1, KEY_LEFTALT), /* S59 */
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000223 KEY(7, 2, KEY_QI_FN), /* S60 */
224};
225
226static const struct matrix_keymap_data qi_lb60_keymap_data = {
227 .keymap = qi_lb60_keymap,
228 .keymap_size = ARRAY_SIZE(qi_lb60_keymap),
229};
230
231static const unsigned int qi_lb60_keypad_cols[] = {
232 QI_LB60_GPIO_KEYOUT(0),
233 QI_LB60_GPIO_KEYOUT(1),
234 QI_LB60_GPIO_KEYOUT(2),
235 QI_LB60_GPIO_KEYOUT(3),
236 QI_LB60_GPIO_KEYOUT(4),
237 QI_LB60_GPIO_KEYOUT(5),
238 QI_LB60_GPIO_KEYOUT(6),
239 QI_LB60_GPIO_KEYOUT(7),
240};
241
242static const unsigned int qi_lb60_keypad_rows[] = {
243 QI_LB60_GPIO_KEYIN(0),
244 QI_LB60_GPIO_KEYIN(1),
245 QI_LB60_GPIO_KEYIN(2),
246 QI_LB60_GPIO_KEYIN(3),
247 QI_LB60_GPIO_KEYIN(4),
248 QI_LB60_GPIO_KEYIN(5),
Lars-Peter Clausenfe749aa2010-11-04 23:25:56 +0100249 QI_LB60_GPIO_KEYIN(6),
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000250 QI_LB60_GPIO_KEYIN8,
251};
252
253static struct matrix_keypad_platform_data qi_lb60_pdata = {
254 .keymap_data = &qi_lb60_keymap_data,
255 .col_gpios = qi_lb60_keypad_cols,
256 .row_gpios = qi_lb60_keypad_rows,
257 .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols),
258 .num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows),
259 .col_scan_delay_us = 10,
260 .debounce_ms = 10,
261 .wakeup = 1,
262 .active_low = 1,
263};
264
265static struct platform_device qi_lb60_keypad = {
266 .name = "matrix-keypad",
267 .id = -1,
268 .dev = {
269 .platform_data = &qi_lb60_pdata,
270 },
271};
272
273/* Display */
274static struct fb_videomode qi_lb60_video_modes[] = {
275 {
276 .name = "320x240",
277 .xres = 320,
278 .yres = 240,
279 .refresh = 30,
280 .left_margin = 140,
281 .right_margin = 273,
282 .upper_margin = 20,
283 .lower_margin = 2,
284 .hsync_len = 1,
285 .vsync_len = 1,
286 .sync = 0,
287 .vmode = FB_VMODE_NONINTERLACED,
288 },
289};
290
291static struct jz4740_fb_platform_data qi_lb60_fb_pdata = {
292 .width = 60,
293 .height = 45,
294 .num_modes = ARRAY_SIZE(qi_lb60_video_modes),
295 .modes = qi_lb60_video_modes,
296 .bpp = 24,
297 .lcd_type = JZ_LCD_TYPE_8BIT_SERIAL,
298 .pixclk_falling_edge = 1,
299};
300
301struct spi_gpio_platform_data spigpio_platform_data = {
302 .sck = JZ_GPIO_PORTC(23),
303 .mosi = JZ_GPIO_PORTC(22),
304 .miso = -1,
305 .num_chipselect = 1,
306};
307
308static struct platform_device spigpio_device = {
309 .name = "spi_gpio",
310 .id = 1,
311 .dev = {
312 .platform_data = &spigpio_platform_data,
313 },
314};
315
316static struct spi_board_info qi_lb60_spi_board_info[] = {
317 {
318 .modalias = "ili8960",
319 .controller_data = (void *)JZ_GPIO_PORTC(21),
320 .chip_select = 0,
321 .bus_num = 1,
322 .max_speed_hz = 30 * 1000,
323 .mode = SPI_3WIRE,
324 },
325};
326
327/* Battery */
328static struct jz_battery_platform_data qi_lb60_battery_pdata = {
Ralf Baechle70342282013-01-22 12:59:30 +0100329 .gpio_charge = JZ_GPIO_PORTC(27),
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000330 .gpio_charge_active_low = 1,
331 .info = {
332 .name = "battery",
333 .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
334 .voltage_max_design = 4200000,
335 .voltage_min_design = 3600000,
336 },
337};
338
339/* GPIO Key: power */
340static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = {
341 [0] = {
342 .code = KEY_POWER,
343 .gpio = JZ_GPIO_PORTD(29),
344 .active_low = 1,
345 .desc = "Power",
346 .wakeup = 1,
347 },
348};
349
350static struct gpio_keys_platform_data qi_lb60_gpio_keys_data = {
351 .nbuttons = ARRAY_SIZE(qi_lb60_gpio_keys_buttons),
352 .buttons = qi_lb60_gpio_keys_buttons,
353};
354
355static struct platform_device qi_lb60_gpio_keys = {
Ralf Baechle70342282013-01-22 12:59:30 +0100356 .name = "gpio-keys",
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000357 .id = -1,
358 .dev = {
359 .platform_data = &qi_lb60_gpio_keys_data,
360 }
361};
362
363static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
364 .gpio_card_detect = QI_LB60_GPIO_SD_CD,
365 .gpio_read_only = -1,
366 .gpio_power = QI_LB60_GPIO_SD_VCC_EN_N,
367 .power_active_low = 1,
368};
369
370/* OHCI */
371static struct regulator_consumer_supply avt2_usb_regulator_consumer =
372 REGULATOR_SUPPLY("vbus", "jz4740-ohci");
373
374static struct regulator_init_data avt2_usb_regulator_init_data = {
375 .num_consumer_supplies = 1,
376 .consumer_supplies = &avt2_usb_regulator_consumer,
377 .constraints = {
378 .name = "USB power",
379 .min_uV = 5000000,
380 .max_uV = 5000000,
381 .valid_modes_mask = REGULATOR_MODE_NORMAL,
382 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
383 },
384};
385
386static struct fixed_voltage_config avt2_usb_regulator_data = {
387 .supply_name = "USB power",
388 .microvolts = 5000000,
389 .gpio = JZ_GPIO_PORTB(17),
390 .init_data = &avt2_usb_regulator_init_data,
391};
392
393static struct platform_device avt2_usb_regulator_device = {
394 .name = "reg-fixed-voltage",
395 .id = -1,
396 .dev = {
397 .platform_data = &avt2_usb_regulator_data,
398 }
399};
400
401/* beeper */
402static struct platform_device qi_lb60_pwm_beeper = {
403 .name = "pwm-beeper",
404 .id = -1,
405 .dev = {
406 .platform_data = (void *)4,
407 },
408};
409
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100410/* charger */
411static char *qi_lb60_batteries[] = {
412 "battery",
413};
414
415static struct gpio_charger_platform_data qi_lb60_charger_pdata = {
416 .name = "usb",
417 .type = POWER_SUPPLY_TYPE_USB,
418 .gpio = JZ_GPIO_PORTD(28),
419 .gpio_active_low = 1,
420 .supplied_to = qi_lb60_batteries,
421 .num_supplicants = ARRAY_SIZE(qi_lb60_batteries),
422};
423
424static struct platform_device qi_lb60_charger_device = {
425 .name = "gpio-charger",
426 .dev = {
427 .platform_data = &qi_lb60_charger_pdata,
428 },
429};
430
Axel Linb33005f32012-01-06 11:30:10 +0800431/* audio */
432static struct platform_device qi_lb60_audio_device = {
433 .name = "qi-lb60-audio",
434 .id = -1,
435};
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100436
Lars-Peter Clausen218e18a2014-04-22 22:46:35 +0200437static struct gpiod_lookup_table qi_lb60_audio_gpio_table = {
438 .dev_id = "qi-lb60-audio",
439 .table = {
440 GPIO_LOOKUP("Bank B", 29, "snd", 0),
441 GPIO_LOOKUP("Bank D", 4, "amp", 0),
442 { },
443 },
444};
445
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000446static struct platform_device *jz_platform_devices[] __initdata = {
447 &jz4740_udc_device,
Apelete Seketelic330fd92013-12-19 22:11:43 +0100448 &jz4740_udc_xceiv_device,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000449 &jz4740_mmc_device,
450 &jz4740_nand_device,
451 &qi_lb60_keypad,
452 &spigpio_device,
453 &jz4740_framebuffer_device,
454 &jz4740_pcm_device,
455 &jz4740_i2s_device,
456 &jz4740_codec_device,
457 &jz4740_rtc_device,
458 &jz4740_adc_device,
Thierry Redingf6b8a572012-08-22 10:01:24 +0200459 &jz4740_pwm_device,
Lars-Peter Clausencdcb90a2013-05-30 18:25:03 +0200460 &jz4740_dma_device,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000461 &qi_lb60_gpio_keys,
462 &qi_lb60_pwm_beeper,
Lars-Peter Clausen0b4cf182011-02-08 03:43:53 +0100463 &qi_lb60_charger_device,
Axel Linb33005f32012-01-06 11:30:10 +0800464 &qi_lb60_audio_device,
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000465};
466
467static void __init board_gpio_setup(void)
468{
469 /* We only need to enable/disable pullup here for pins used in generic
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300470 * drivers. Everything else is done by the drivers themselves. */
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000471 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
472 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
473}
474
475static int __init qi_lb60_init_platform_devices(void)
476{
477 jz4740_framebuffer_device.dev.platform_data = &qi_lb60_fb_pdata;
478 jz4740_nand_device.dev.platform_data = &qi_lb60_nand_pdata;
479 jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
480 jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
481
Lars-Peter Clausen218e18a2014-04-22 22:46:35 +0200482 gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
Lars-Peter Clausencd145af2014-12-02 20:48:26 +0100483 gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
Lars-Peter Clausen218e18a2014-04-22 22:46:35 +0200484
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000485 jz4740_serial_device_register();
486
487 spi_register_board_info(qi_lb60_spi_board_info,
488 ARRAY_SIZE(qi_lb60_spi_board_info));
489
490 if (is_avt2) {
491 platform_device_register(&avt2_usb_regulator_device);
492 platform_device_register(&jz4740_usb_ohci_device);
493 }
494
495 return platform_add_devices(jz_platform_devices,
496 ARRAY_SIZE(jz_platform_devices));
497
498}
499
500struct jz4740_clock_board_data jz4740_clock_bdata = {
501 .ext_rate = 12000000,
502 .rtc_rate = 32768,
503};
504
505static __init int board_avt2(char *str)
506{
507 qi_lb60_mmc_pdata.card_detect_active_low = 1;
508 is_avt2 = true;
509
510 return 1;
511}
512__setup("avt2", board_avt2);
513
514static int __init qi_lb60_board_setup(void)
515{
516 printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n",
517 is_avt2 ? "AVT2" : "LB60");
518
519 board_gpio_setup();
520
521 if (qi_lb60_init_platform_devices())
Ralf Baechleab75dc02011-11-17 15:07:31 +0000522 panic("Failed to initialize platform devices");
Lars-Peter Clausene6b78c42010-07-17 11:16:29 +0000523
524 return 0;
525}
526arch_initcall(qi_lb60_board_setup);