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

Source at commit 1be551a8eb58178b009ac645c537deb68ada70f9 created 7 years 2 months ago.
By Lars-Peter Clausen, mmc: jz4740: Use a regulator for power control
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.h>
30#include <linux/pwm_backlight.h>
31#include <linux/input.h>
32#include <linux/gpio_keys.h>
33
34#include <media/radio-rda5807.h>
35
36#include <asm/cpu.h>
37#include <asm/bootinfo.h>
38#include <asm/mipsregs.h>
39#include <asm/reboot.h>
40
41#include <asm/mach-jz4740/gpio.h>
42#include <asm/mach-jz4740/jz4740_fb.h>
43#include <asm/mach-jz4740/jz4740_mmc.h>
44#include <asm/mach-jz4740/jz4740_nand.h>
45#include <asm/mach-jz4740/platform.h>
46
47#include "clock.h"
48
49/*
50 * This is called by the panic reboot delay loop if panic=<n> parameter
51 * is passed to the kernel. The A320 does not have any LEDs, so the best
52 * we can do is to blink the LCD backlight.
53 *
54 * TODO(MtH): This should use the backlight driver instead of directly
55 * manipulating the GPIO pin.
56 */
57static long a320_panic_blink_callback(int time)
58{
59    gpio_direction_output(JZ_GPIO_PORTD(31), (time / 500) & 1);
60    return 0;
61}
62
63#ifdef CONFIG_I2C_GPIO
64/* I2C over GPIO pins */
65static struct i2c_gpio_platform_data a320_i2c_pdata = {
66    .sda_pin = JZ_GPIO_PORTD(23),
67    .scl_pin = JZ_GPIO_PORTD(24),
68    .udelay = 2,
69    .timeout = 3 * HZ,
70};
71
72static struct platform_device a320_i2c_device = {
73    .name = "i2c-gpio",
74    .id = 0,
75    .dev = {
76        .platform_data = &a320_i2c_pdata,
77    },
78};
79#endif
80
81/* NAND */
82#define A320_NAND_PAGE_SIZE (4096ull)
83#define A320_NAND_ERASE_BLOCK_SIZE (128 * A320_NAND_PAGE_SIZE)
84
85static struct mtd_partition a320_nand_partitions[] = {
86    { .name = "SPL",
87      .offset = 0 * A320_NAND_ERASE_BLOCK_SIZE,
88      .size = 64 * A320_NAND_PAGE_SIZE,
89    },
90    { .name = "uC/OS-II loader",
91      .offset = 64 * A320_NAND_PAGE_SIZE,
92      .size = 192 * A320_NAND_PAGE_SIZE,
93    },
94    /* erase block 3 is empty (maybe alternative location for bbt?) */
95    /* erase block 4 contains the bad block table */
96    { .name = "uC/OS-II Z:",
97      .offset = 5 * A320_NAND_ERASE_BLOCK_SIZE,
98      .size = 127 * A320_NAND_ERASE_BLOCK_SIZE,
99    },
100    { .name = "uC/OS-II A:",
101      .offset = 132 * A320_NAND_ERASE_BLOCK_SIZE,
102      .size = (8192 - 132) * A320_NAND_ERASE_BLOCK_SIZE,
103    },
104};
105
106static uint8_t a320_nand_bbt_pattern[] = {'b', 'b', 't', '8' };
107
108static struct nand_bbt_descr a320_nand_bbt_main_descr = {
109    .options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT,
110    /* TODO(MtH): Maybe useful flags for the future:
111    NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_VERSION | NAND_BBT_PERCHIP
112    */
113    .pages = { 4 * A320_NAND_ERASE_BLOCK_SIZE / A320_NAND_PAGE_SIZE },
114    .maxblocks = 1,
115    .pattern = a320_nand_bbt_pattern,
116    .len = ARRAY_SIZE(a320_nand_bbt_pattern),
117    .offs = 128 - ARRAY_SIZE(a320_nand_bbt_pattern),
118};
119
120static struct nand_ecclayout a320_nand_ecc_layout = {
121    .eccbytes = 72,
122    .eccpos = {
123         4, 5, 6, 7, 8, 9, 10, 11, 12, /* sector 0 */
124        16, 17, 18, 19, 20, 21, 22, 23, 24, /* sector 1 */
125        28, 29, 30, 31, 32, 33, 34, 35, 36, /* sector 2 */
126        40, 41, 42, 43, 44, 45, 46, 47, 48, /* sector 3 */
127        52, 53, 54, 55, 56, 57, 58, 59, 60, /* sector 4 */
128        64, 65, 66, 67, 68, 69, 70, 71, 72, /* sector 5 */
129        76, 77, 78, 79, 80, 81, 82, 83, 84, /* sector 6 */
130        88, 89, 90, 91, 92, 93, 94, 95, 96, /* sector 7 */
131    },
132    .oobfree = {
133        { .offset = 100, .length = 22 },
134    }
135};
136
137static void a320_nand_ident(struct platform_device *pdev,
138                struct nand_chip *chip,
139                struct mtd_partition **partitions,
140                int *num_partitions)
141{
142    chip->bbt_options |= NAND_BBT_USE_FLASH;
143    chip->bbt_td = &a320_nand_bbt_main_descr;
144    /* MtH: I did not find a mirror bbt yet, but it might exist. */
145    chip->bbt_md = NULL;
146}
147
148static struct jz_nand_platform_data a320_nand_pdata = {
149    .num_partitions = ARRAY_SIZE(a320_nand_partitions),
150    .partitions = a320_nand_partitions,
151    .ecc_layout = &a320_nand_ecc_layout,
152    .busy_gpio = JZ_GPIO_PORTC(30),
153    .banks = { 1, 2, 3, 4 },
154    .ident_callback = a320_nand_ident,
155};
156
157/* Display */
158static struct fb_videomode a320_video_modes[] = {
159    {
160        .name = "320x240",
161        .xres = 320,
162        .yres = 240,
163        // TODO(MtH): Set refresh or pixclock.
164        .vmode = FB_VMODE_NONINTERLACED,
165    },
166};
167
168static struct jz4740_fb_platform_data a320_fb_pdata = {
169    .width = 60,
170    .height = 45,
171    .num_modes = ARRAY_SIZE(a320_video_modes),
172    .modes = a320_video_modes,
173    .bpp = 16,
174    .lcd_type = JZ_LCD_TYPE_SMART_PARALLEL_16_BIT,
175    .pixclk_falling_edge = 0,
176    .chip_select_active_low = 1,
177    .register_select_active_low = 1,
178};
179
180static int a320_backlight_notify(struct device *dev, int brightness)
181{
182    if (!gpio_get_value(JZ_GPIO_PORTB(18))) {
183        /* RESET_N pin of the ILI chip is pulled down,
184           so force backlight off. */
185        return 0;
186    }
187
188    return brightness;
189}
190
191static struct platform_pwm_backlight_data a320_backlight_pdata = {
192    .max_brightness = 255,
193    .dft_brightness = 145,
194    .pwm_period_ns = 1000000,
195    .notify = a320_backlight_notify,
196};
197
198static struct platform_device a320_backlight_device = {
199    .name = "pwm-backlight",
200    .id = -1,
201    .dev = {
202        .platform_data = &a320_backlight_pdata,
203    },
204};
205
206struct pwm_lookup a320_pwm_table[] = {
207    PWM_LOOKUP("jz4740-pwm", 7, "pwm-backlight", 0),
208};
209
210static struct regulator_consumer_supply a320_mmc_regulator_consumer =
211    REGULATOR_SUPPLY("vmmc", "jz4740-mmc.0");
212
213static struct regulator_init_data a320_mmc_regulator_init_data = {
214    .num_consumer_supplies = 1,
215    .consumer_supplies = &a320_mmc_regulator_consumer,
216    .constraints = {
217        .name = "MMC power",
218        .min_uV = 3300000,
219        .max_uV = 3300000,
220        .valid_modes_mask = REGULATOR_MODE_NORMAL,
221        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
222    },
223};
224
225static struct fixed_voltage_config a320_mmc_regulator_data = {
226    .supply_name = "MMC power",
227    .microvolts = 3300000,
228    .init_data = &a320_mmc_regulator_init_data,
229};
230
231static struct platform_device a320_mmc_regulator_device = {
232    .name = "reg-fixed-voltage",
233    .id = -1,
234    .dev = {
235        .platform_data = &a320_mmc_regulator_data,
236    }
237};
238
239static struct jz4740_mmc_platform_data a320_mmc_pdata = {
240    .gpio_card_detect = JZ_GPIO_PORTB(29),
241    .gpio_read_only = -1,
242};
243
244/* Battery */
245static struct jz_battery_platform_data a320_battery_pdata = {
246    // TODO(MtH): Sometimes while charging, the GPIO pin quickly flips between
247    // 0 and 1. This causes a very high CPU load because the kernel
248    // will invoke a hotplug event handler process on every status
249    // change. Until it is clear how to avoid or handle that, it
250    // is better not to use the charge status.
251    //.gpio_charge = JZ_GPIO_PORTB(30),
252    .gpio_charge = -1,
253    .gpio_charge_active_low = 1,
254    .info = {
255        .name = "battery",
256        .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
257        .voltage_max_design = 4150000,
258        .voltage_min_design = 3450000,
259    },
260};
261
262static char *a320_batteries[] = {
263    "battery",
264};
265
266static struct gpio_charger_platform_data a320_charger_pdata = {
267    .name = "usb",
268    .type = POWER_SUPPLY_TYPE_USB,
269    .gpio = JZ_GPIO_PORTD(28),
270    .gpio_active_low = 0,
271    .supplied_to = a320_batteries,
272    .num_supplicants = ARRAY_SIZE(a320_batteries),
273};
274
275static struct platform_device a320_charger_device = {
276    .name = "gpio-charger",
277    .dev = {
278        .platform_data = &a320_charger_pdata,
279    },
280};
281
282/* Note that the microswitch buttons need debounce while the rubber buttons
283 * do not need it.
284 */
285static struct gpio_keys_button a320_buttons[] = {
286    /* D-pad up */ {
287        .gpio = JZ_GPIO_PORTD(6),
288        .active_low = 1,
289        .code = KEY_UP,
290    },
291    /* D-pad down */ {
292        .gpio = JZ_GPIO_PORTD(27),
293        .active_low = 1,
294        .code = KEY_DOWN,
295    },
296    /* D-pad left */ {
297        .gpio = JZ_GPIO_PORTD(5),
298        .active_low = 1,
299        .code = KEY_LEFT,
300    },
301    /* D-pad right */ {
302        .gpio = JZ_GPIO_PORTD(18),
303        .active_low = 1,
304        .code = KEY_RIGHT,
305    },
306    /* A button */ {
307        .gpio = JZ_GPIO_PORTD(0),
308        .active_low = 1,
309        .code = KEY_LEFTCTRL,
310    },
311    /* B button */ {
312        .gpio = JZ_GPIO_PORTD(1),
313        .active_low = 1,
314        .code = KEY_LEFTALT,
315    },
316    /* X button */ {
317        .gpio = JZ_GPIO_PORTD(19),
318        .active_low = 1,
319        .code = KEY_SPACE,
320    },
321    /* Y button */ {
322        .gpio = JZ_GPIO_PORTD(2),
323        .active_low = 1,
324        .code = KEY_LEFTSHIFT,
325    },
326    /* Left shoulder button */ {
327        .gpio = JZ_GPIO_PORTD(14),
328        .active_low = 1,
329        .code = KEY_TAB,
330        .debounce_interval = 5,
331    },
332    /* Right shoulder button */ {
333        .gpio = JZ_GPIO_PORTD(15),
334        .active_low = 1,
335        .code = KEY_BACKSPACE,
336        .debounce_interval = 5,
337    },
338    /* START button */ {
339        .gpio = JZ_GPIO_PORTC(17),
340        .active_low = 1,
341        .code = KEY_ENTER,
342        .debounce_interval = 5,
343    },
344    /* SELECT button */ {
345        .gpio = JZ_GPIO_PORTD(17),
346        .active_low = 1,
347        .code = KEY_ESC,
348        .debounce_interval = 5,
349    },
350    /* POWER slider */ {
351        .gpio = JZ_GPIO_PORTD(29),
352        .active_low = 1,
353        .code = KEY_POWER,
354        .wakeup = 1,
355    },
356    /* POWER hold */ {
357        .gpio = JZ_GPIO_PORTD(22),
358        .active_low = 1,
359        .code = KEY_PAUSE,
360    },
361};
362
363static struct gpio_keys_platform_data a320_gpio_keys_pdata = {
364    .buttons = a320_buttons,
365    .nbuttons = ARRAY_SIZE(a320_buttons),
366    .rep = 1,
367};
368
369static struct platform_device a320_gpio_keys_device = {
370    .name = "gpio-keys",
371    .id = -1,
372    .dev = {
373        .platform_data = &a320_gpio_keys_pdata,
374    },
375};
376
377/* Audio */
378static struct platform_device a320_audio_device = {
379    .name = "a320-audio",
380    .id = -1,
381};
382
383static struct platform_device *jz_platform_devices[] __initdata = {
384#ifdef CONFIG_I2C_JZ47XX
385    &jz4740_i2c_device,
386#endif
387#ifdef CONFIG_I2C_GPIO
388    &a320_i2c_device,
389#endif
390    /* USB host is not usable since the PCB does not route the pins to
391     * a place where new wires can be soldered. */
392    /*&jz4740_usb_ohci_device,*/
393    &jz4740_udc_device,
394    &jz4740_mmc_device,
395    &jz4740_nand_device,
396    &jz4740_framebuffer_device,
397    &jz4740_pcm_device,
398    &jz4740_i2s_device,
399    &jz4740_codec_device,
400    &jz4740_rtc_device,
401    &jz4740_adc_device,
402    &jz4740_wdt_device,
403    &a320_charger_device,
404    &jz4740_pwm_device,
405    &a320_backlight_device,
406    &a320_gpio_keys_device,
407    &a320_audio_device,
408    &a320_mmc_regulator_device,
409};
410
411static void __init board_gpio_setup(void)
412{
413    /* We only need to enable/disable pullup here for pins used in generic
414     * drivers. Everything else is done by the drivers themselves. */
415
416    /* Disable pullup of the USB detection pin: on the A320 pullup or not
417     * seems to make no difference, but on A330 the signal will be unstable
418     * when the pullup is enabled. */
419    jz_gpio_disable_pullup(JZ_GPIO_PORTD(28));
420}
421
422static int __init a320_init_platform_devices(void)
423{
424    jz4740_framebuffer_device.dev.platform_data = &a320_fb_pdata;
425    jz4740_nand_device.dev.platform_data = &a320_nand_pdata;
426    jz4740_adc_device.dev.platform_data = &a320_battery_pdata;
427    jz4740_mmc_device.dev.platform_data = &a320_mmc_pdata;
428
429    jz4740_serial_device_register();
430
431    pwm_add_table(a320_pwm_table, ARRAY_SIZE(a320_pwm_table));
432
433    return platform_add_devices(jz_platform_devices,
434                    ARRAY_SIZE(jz_platform_devices));
435}
436
437struct jz4740_clock_board_data jz4740_clock_bdata = {
438    .ext_rate = 12000000,
439    .rtc_rate = 32768,
440};
441
442static struct rda5807_platform_data a320_rda5807_pdata = {
443    .input_flags = RDA5807_INPUT_LNA_WC_25 | RDA5807_LNA_PORT_P,
444    .output_flags = RDA5807_OUTPUT_AUDIO_ANALOG,
445};
446
447static struct i2c_board_info a320_i2c_info[] __initdata = {
448    {
449        .type = "radio-rda5807",
450        .addr = RDA5807_I2C_ADDR,
451        .platform_data = &a320_rda5807_pdata,
452    }
453};
454
455static int __init a320_board_setup(void)
456{
457    printk(KERN_INFO "JZ4740 A320 board setup\n");
458
459    panic_blink = a320_panic_blink_callback;
460
461    board_gpio_setup();
462
463    if (a320_init_platform_devices())
464        panic("Failed to initalize platform devices\n");
465
466    i2c_register_board_info(0, a320_i2c_info, ARRAY_SIZE(a320_i2c_info));
467
468    return 0;
469}
470
471arch_initcall(a320_board_setup);
472

Archive Download this file



interactive