Root/
1 | /* |
2 | * linux/arch/mips/jz4740/board-a320.c |
3 | * |
4 | * JZ4740 A320 board setup routines. |
5 | * |
6 | * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. |
7 | * Copyright (c) 2009 Ignacio Garcia Perez <iggarpe@gmail.com> |
8 | * Copyright (c) 2010-2011 Maarten ter Huurne <maarten@treewalker.org> |
9 | * |
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 as |
12 | * published by the Free Software Foundation. |
13 | */ |
14 | |
15 | #include <linux/init.h> |
16 | #include <linux/sched.h> |
17 | #include <linux/ioport.h> |
18 | #include <linux/mm.h> |
19 | #include <linux/console.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/gpio.h> |
23 | #include <linux/i2c.h> |
24 | #include <linux/i2c-gpio.h> |
25 | #include <linux/power_supply.h> |
26 | #include <linux/power/gpio-charger.h> |
27 | #include <linux/power/jz4740-battery.h> |
28 | |
29 | #include <linux/pwm_backlight.h> |
30 | #include <linux/input.h> |
31 | #include <linux/gpio_keys.h> |
32 | |
33 | #include <asm/cpu.h> |
34 | #include <asm/bootinfo.h> |
35 | #include <asm/mipsregs.h> |
36 | #include <asm/reboot.h> |
37 | |
38 | #include <asm/mach-jz4740/gpio.h> |
39 | #include <asm/mach-jz4740/jz4740_fb.h> |
40 | #include <asm/mach-jz4740/jz4740_mmc.h> |
41 | #include <asm/mach-jz4740/jz4740_nand.h> |
42 | #include <asm/mach-jz4740/platform.h> |
43 | |
44 | #include "clock.h" |
45 | |
46 | /* |
47 | * This is called by the panic reboot delay loop if panic=<n> parameter |
48 | * is passed to the kernel. The A320 does not have any LEDs, so the best |
49 | * we can do is to blink the LCD backlight. |
50 | * |
51 | * TODO(MtH): This should use the backlight driver instead of directly |
52 | * manipulating the GPIO pin. |
53 | */ |
54 | static long a320_panic_blink_callback(int time) |
55 | { |
56 | gpio_direction_output(JZ_GPIO_PORTD(31), (time / 500) & 1); |
57 | return 0; |
58 | } |
59 | |
60 | #ifdef CONFIG_I2C_GPIO |
61 | /* I2C over GPIO pins */ |
62 | static struct i2c_gpio_platform_data a320_i2c_pdata = { |
63 | .sda_pin = JZ_GPIO_PORTD(23), |
64 | .scl_pin = JZ_GPIO_PORTD(24), |
65 | .udelay = 2, |
66 | .timeout = 3 * HZ, |
67 | }; |
68 | |
69 | static struct platform_device a320_i2c_device = { |
70 | .name = "i2c-gpio", |
71 | .id = -1, |
72 | .dev = { |
73 | .platform_data = &a320_i2c_pdata, |
74 | }, |
75 | }; |
76 | #endif |
77 | |
78 | /* NAND */ |
79 | #define A320_NAND_PAGE_SIZE (4096ull) |
80 | #define A320_NAND_ERASE_BLOCK_SIZE (128 * A320_NAND_PAGE_SIZE) |
81 | |
82 | static struct mtd_partition a320_nand_partitions[] = { |
83 | { .name = "SPL", |
84 | .offset = 0 * A320_NAND_ERASE_BLOCK_SIZE, |
85 | .size = 1 * A320_NAND_ERASE_BLOCK_SIZE, |
86 | /* MtH: Read-only until we can trust it. */ |
87 | .mask_flags = MTD_WRITEABLE, |
88 | }, |
89 | { .name = "uC/OS-II loader", |
90 | .offset = 1 * A320_NAND_ERASE_BLOCK_SIZE, |
91 | .size = 2 * A320_NAND_ERASE_BLOCK_SIZE, |
92 | /* MtH: Read-only until we can trust it. */ |
93 | .mask_flags = MTD_WRITEABLE, |
94 | }, |
95 | /* erase block 3 is empty (maybe alternative location for bbt?) */ |
96 | /* erase block 4 contains the bad block table */ |
97 | { .name = "uC/OS-II Z:", |
98 | .offset = 5 * A320_NAND_ERASE_BLOCK_SIZE, |
99 | .size = 127 * A320_NAND_ERASE_BLOCK_SIZE, |
100 | /* MtH: Read-only until we can trust it. */ |
101 | .mask_flags = MTD_WRITEABLE, |
102 | }, |
103 | { .name = "uC/OS-II A:", |
104 | .offset = 132 * A320_NAND_ERASE_BLOCK_SIZE, |
105 | .size = (8192 - 132) * A320_NAND_ERASE_BLOCK_SIZE, |
106 | /* MtH: Read-only until we can trust it. */ |
107 | .mask_flags = MTD_WRITEABLE, |
108 | }, |
109 | }; |
110 | |
111 | static uint8_t a320_nand_bbt_pattern[] = {'b', 'b', 't', '8' }; |
112 | |
113 | static struct nand_bbt_descr a320_nand_bbt_main_descr = { |
114 | .options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT, |
115 | /* TODO(MtH): Maybe useful flags for the future: |
116 | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_VERSION | NAND_BBT_PERCHIP |
117 | */ |
118 | .pages = { 4 * A320_NAND_ERASE_BLOCK_SIZE / A320_NAND_PAGE_SIZE }, |
119 | .maxblocks = 1, |
120 | .pattern = a320_nand_bbt_pattern, |
121 | .len = ARRAY_SIZE(a320_nand_bbt_pattern), |
122 | .offs = 128 - ARRAY_SIZE(a320_nand_bbt_pattern), |
123 | }; |
124 | |
125 | static struct nand_ecclayout a320_nand_ecc_layout = { |
126 | .eccbytes = 72, |
127 | .eccpos = { |
128 | 4, 5, 6, 7, 8, 9, 10, 11, 12, /* sector 0 */ |
129 | 16, 17, 18, 19, 20, 21, 22, 23, 24, /* sector 1 */ |
130 | 28, 29, 30, 31, 32, 33, 34, 35, 36, /* sector 2 */ |
131 | 40, 41, 42, 43, 44, 45, 46, 47, 48, /* sector 3 */ |
132 | 52, 53, 54, 55, 56, 57, 58, 59, 60, /* sector 4 */ |
133 | 64, 65, 66, 67, 68, 69, 70, 71, 72, /* sector 5 */ |
134 | 76, 77, 78, 79, 80, 81, 82, 83, 84, /* sector 6 */ |
135 | 88, 89, 90, 91, 92, 93, 94, 95, 96, /* sector 7 */ |
136 | }, |
137 | .oobfree = { |
138 | { .offset = 100, .length = 22 }, |
139 | } |
140 | }; |
141 | |
142 | static void a320_nand_ident(struct platform_device *pdev, |
143 | struct nand_chip *chip, |
144 | struct mtd_partition **partitions, |
145 | int *num_partitions) |
146 | { |
147 | chip->options |= NAND_USE_FLASH_BBT; |
148 | chip->bbt_td = &a320_nand_bbt_main_descr; |
149 | /* MtH: I did not find a mirror bbt yet, but it might exist. */ |
150 | chip->bbt_md = NULL; |
151 | } |
152 | |
153 | static struct jz_nand_platform_data a320_nand_pdata = { |
154 | .num_partitions = ARRAY_SIZE(a320_nand_partitions), |
155 | .partitions = a320_nand_partitions, |
156 | .ecc_layout = &a320_nand_ecc_layout, |
157 | .busy_gpio = JZ_GPIO_PORTC(30), |
158 | .banks = { 1, 2, 3, 4 }, |
159 | .ident_callback = a320_nand_ident, |
160 | }; |
161 | |
162 | /* Display */ |
163 | static struct fb_videomode a320_video_modes[] = { |
164 | { |
165 | .name = "320x240", |
166 | .xres = 320, |
167 | .yres = 240, |
168 | // TODO(MtH): Set refresh or pixclock. |
169 | .vmode = FB_VMODE_NONINTERLACED, |
170 | }, |
171 | }; |
172 | |
173 | static struct jz4740_fb_platform_data a320_fb_pdata = { |
174 | .width = 60, |
175 | .height = 45, |
176 | .num_modes = ARRAY_SIZE(a320_video_modes), |
177 | .modes = a320_video_modes, |
178 | .bpp = 16, |
179 | .lcd_type = JZ_LCD_TYPE_SMART_PARALLEL_16_BIT, |
180 | .pixclk_falling_edge = 0, |
181 | .chip_select_active_low = 1, |
182 | .register_select_active_low = 1, |
183 | }; |
184 | |
185 | static int a320_backlight_notify(struct device *dev, int brightness) |
186 | { |
187 | if (!gpio_get_value(JZ_GPIO_PORTB(18))) { |
188 | /* RESET_N pin of the ILI chip is pulled down, |
189 | so force backlight off. */ |
190 | return 0; |
191 | } |
192 | |
193 | return brightness; |
194 | } |
195 | |
196 | static struct platform_pwm_backlight_data a320_backlight_pdata = { |
197 | .pwm_id = 7, |
198 | .max_brightness = 255, |
199 | .dft_brightness = 100, |
200 | .pwm_period_ns = 5000000, |
201 | .notify = a320_backlight_notify, |
202 | }; |
203 | |
204 | static struct platform_device a320_backlight_device = { |
205 | .name = "pwm-backlight", |
206 | .id = -1, |
207 | .dev = { |
208 | .platform_data = &a320_backlight_pdata, |
209 | }, |
210 | }; |
211 | |
212 | static struct jz4740_mmc_platform_data a320_mmc_pdata = { |
213 | .gpio_card_detect = JZ_GPIO_PORTB(29), |
214 | .gpio_read_only = -1, |
215 | .gpio_power = -1, |
216 | // TODO(MtH): I don't know which GPIO pin the SD power is connected to. |
217 | // Booboo left power alone, but I don't know why. |
218 | //.gpio_power = GPIO_SD_VCC_EN_N, |
219 | //.power_active_low = 1, |
220 | }; |
221 | |
222 | /* Battery */ |
223 | static struct jz_battery_platform_data a320_battery_pdata = { |
224 | // TODO(MtH): Sometimes while charging, the GPIO pin quickly flips between |
225 | // 0 and 1. This causes a very high CPU load because the kernel |
226 | // will invoke a hotplug event handler process on every status |
227 | // change. Until it is clear how to avoid or handle that, it |
228 | // is better not to use the charge status. |
229 | //.gpio_charge = JZ_GPIO_PORTB(30), |
230 | .gpio_charge = -1, |
231 | .gpio_charge_active_low = 1, |
232 | .info = { |
233 | .name = "battery", |
234 | .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, |
235 | .voltage_max_design = 4200000, |
236 | .voltage_min_design = 3600000, |
237 | }, |
238 | }; |
239 | |
240 | static char *a320_batteries[] = { |
241 | "battery", |
242 | }; |
243 | |
244 | static struct gpio_charger_platform_data a320_charger_pdata = { |
245 | .name = "usb", |
246 | .type = POWER_SUPPLY_TYPE_USB, |
247 | .gpio = JZ_GPIO_PORTD(28), |
248 | .gpio_active_low = 0, |
249 | .supplied_to = a320_batteries, |
250 | .num_supplicants = ARRAY_SIZE(a320_batteries), |
251 | }; |
252 | |
253 | static struct platform_device a320_charger_device = { |
254 | .name = "gpio-charger", |
255 | .dev = { |
256 | .platform_data = &a320_charger_pdata, |
257 | }, |
258 | }; |
259 | |
260 | /* Note that the microswitch buttons need debounce while the rubber buttons |
261 | * do not need it. |
262 | */ |
263 | static struct gpio_keys_button a320_buttons[] = { |
264 | /* D-pad up */ { |
265 | .gpio = JZ_GPIO_PORTD(6), |
266 | .active_low = 1, |
267 | .code = KEY_UP, |
268 | }, |
269 | /* D-pad down */ { |
270 | .gpio = JZ_GPIO_PORTD(27), |
271 | .active_low = 1, |
272 | .code = KEY_DOWN, |
273 | }, |
274 | /* D-pad left */ { |
275 | .gpio = JZ_GPIO_PORTD(5), |
276 | .active_low = 1, |
277 | .code = KEY_LEFT, |
278 | }, |
279 | /* D-pad right */ { |
280 | .gpio = JZ_GPIO_PORTD(18), |
281 | .active_low = 1, |
282 | .code = KEY_RIGHT, |
283 | }, |
284 | /* A button */ { |
285 | .gpio = JZ_GPIO_PORTD(0), |
286 | .active_low = 1, |
287 | .code = KEY_LEFTCTRL, |
288 | }, |
289 | /* B button */ { |
290 | .gpio = JZ_GPIO_PORTD(1), |
291 | .active_low = 1, |
292 | .code = KEY_LEFTALT, |
293 | }, |
294 | /* X button */ { |
295 | .gpio = JZ_GPIO_PORTD(19), |
296 | .active_low = 1, |
297 | .code = KEY_SPACE, |
298 | }, |
299 | /* Y button */ { |
300 | .gpio = JZ_GPIO_PORTD(2), |
301 | .active_low = 1, |
302 | .code = KEY_LEFTSHIFT, |
303 | }, |
304 | /* Left shoulder button */ { |
305 | .gpio = JZ_GPIO_PORTD(14), |
306 | .active_low = 1, |
307 | .code = KEY_TAB, |
308 | .debounce_interval = 5, |
309 | }, |
310 | /* Right shoulder button */ { |
311 | .gpio = JZ_GPIO_PORTD(15), |
312 | .active_low = 1, |
313 | .code = KEY_BACKSPACE, |
314 | .debounce_interval = 5, |
315 | }, |
316 | /* START button */ { |
317 | .gpio = JZ_GPIO_PORTC(17), |
318 | .active_low = 1, |
319 | .code = KEY_ENTER, |
320 | .debounce_interval = 5, |
321 | }, |
322 | /* SELECT button */ { |
323 | .gpio = JZ_GPIO_PORTD(17), |
324 | .active_low = 1, |
325 | .code = KEY_ESC, |
326 | .debounce_interval = 5, |
327 | }, |
328 | /* POWER slider */ { |
329 | .gpio = JZ_GPIO_PORTD(29), |
330 | .active_low = 1, |
331 | .code = KEY_POWER, |
332 | .wakeup = 1, |
333 | }, |
334 | /* POWER hold */ { |
335 | .gpio = JZ_GPIO_PORTD(22), |
336 | .active_low = 1, |
337 | .code = KEY_PAUSE, |
338 | }, |
339 | }; |
340 | |
341 | static struct gpio_keys_platform_data a320_gpio_keys_pdata = { |
342 | .buttons = a320_buttons, |
343 | .nbuttons = ARRAY_SIZE(a320_buttons), |
344 | .rep = 1, |
345 | }; |
346 | |
347 | static struct platform_device a320_gpio_keys_device = { |
348 | .name = "gpio-keys", |
349 | .id = -1, |
350 | .dev = { |
351 | .platform_data = &a320_gpio_keys_pdata, |
352 | }, |
353 | }; |
354 | |
355 | static struct platform_device *jz_platform_devices[] __initdata = { |
356 | #ifdef CONFIG_I2C_JZ47XX |
357 | &jz4740_i2c_device, |
358 | #endif |
359 | #ifdef CONFIG_I2C_GPIO |
360 | &a320_i2c_device, |
361 | #endif |
362 | /* USB host is not usable since the PCB does not route the pins to |
363 | * a place where new wires can be soldered. */ |
364 | /*&jz4740_usb_ohci_device,*/ |
365 | &jz4740_udc_device, |
366 | &jz4740_mmc_device, |
367 | &jz4740_nand_device, |
368 | &jz4740_framebuffer_device, |
369 | &jz4740_pcm_device, |
370 | &jz4740_i2s_device, |
371 | &jz4740_codec_device, |
372 | &jz4740_rtc_device, |
373 | &jz4740_adc_device, |
374 | &jz4740_wdt_device, |
375 | &a320_charger_device, |
376 | &a320_backlight_device, |
377 | &a320_gpio_keys_device, |
378 | }; |
379 | |
380 | static void __init board_gpio_setup(void) |
381 | { |
382 | /* We only need to enable/disable pullup here for pins used in generic |
383 | * drivers. Everything else is done by the drivers themselves. */ |
384 | |
385 | /* Disable pullup of the USB detection pin: on the A320 pullup or not |
386 | * seems to make no difference, but on A330 the signal will be unstable |
387 | * when the pullup is enabled. */ |
388 | jz_gpio_disable_pullup(JZ_GPIO_PORTD(28)); |
389 | } |
390 | |
391 | static int __init a320_init_platform_devices(void) |
392 | { |
393 | jz4740_framebuffer_device.dev.platform_data = &a320_fb_pdata; |
394 | jz4740_nand_device.dev.platform_data = &a320_nand_pdata; |
395 | jz4740_adc_device.dev.platform_data = &a320_battery_pdata; |
396 | jz4740_mmc_device.dev.platform_data = &a320_mmc_pdata; |
397 | |
398 | jz4740_serial_device_register(); |
399 | |
400 | return platform_add_devices(jz_platform_devices, |
401 | ARRAY_SIZE(jz_platform_devices)); |
402 | } |
403 | |
404 | struct jz4740_clock_board_data jz4740_clock_bdata = { |
405 | .ext_rate = 12000000, |
406 | .rtc_rate = 32768, |
407 | }; |
408 | |
409 | static int __init a320_board_setup(void) |
410 | { |
411 | printk(KERN_INFO "JZ4740 A320 board setup\n"); |
412 | |
413 | panic_blink = a320_panic_blink_callback; |
414 | |
415 | board_gpio_setup(); |
416 | |
417 | if (a320_init_platform_devices()) |
418 | panic("Failed to initalize platform devices\n"); |
419 | |
420 | return 0; |
421 | } |
422 | |
423 | arch_initcall(a320_board_setup); |
424 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9