Root/arch/mips/jz4740/board-a320.c

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 */
54static 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 */
62static 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
69static 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
82static 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
111static uint8_t a320_nand_bbt_pattern[] = {'b', 'b', 't', '8' };
112
113static 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
125static 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
142static 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
153static 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 */
163static 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
173static 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
185static 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
196static 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
204static struct platform_device a320_backlight_device = {
205    .name = "pwm-backlight",
206    .id = -1,
207    .dev = {
208        .platform_data = &a320_backlight_pdata,
209    },
210};
211
212static 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 */
223static 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
240static char *a320_batteries[] = {
241    "battery",
242};
243
244static 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
253static 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 */
263static 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
341static struct gpio_keys_platform_data a320_gpio_keys_pdata = {
342    .buttons = a320_buttons,
343    .nbuttons = ARRAY_SIZE(a320_buttons),
344    .rep = 1,
345};
346
347static 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
355static 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
380static 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
391static 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
404struct jz4740_clock_board_data jz4740_clock_bdata = {
405    .ext_rate = 12000000,
406    .rtc_rate = 32768,
407};
408
409static 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
423arch_initcall(a320_board_setup);
424

Archive Download this file



interactive