Root/
Source at commit 1c406daf9520ee85932009a7d9367b39a2336ad4 created 12 years 7 months ago. By Xiangfu Liu, ben nanonote: forward patches to linux-3.0 | |
---|---|
1 | From dcc0d9f15146c100a843dfa62ba259e208330f07 Mon Sep 17 00:00:00 2001 |
2 | From: Lars-Peter Clausen <lars@metafoo.de> |
3 | Date: Sat, 24 Apr 2010 17:25:23 +0200 |
4 | Subject: [PATCH 03/29] Add n526 board support |
5 | |
6 | --- |
7 | arch/mips/jz4740/Kconfig | 4 + |
8 | arch/mips/jz4740/Makefile | 1 + |
9 | arch/mips/jz4740/board-n526.c | 320 +++++++++++++++++++++++++++++++++++++++++ |
10 | 3 files changed, 325 insertions(+), 0 deletions(-) |
11 | create mode 100644 arch/mips/jz4740/board-n526.c |
12 | |
13 | diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig |
14 | index 85bfbf3..2f366d7 100644 |
15 | --- a/arch/mips/jz4740/Kconfig |
16 | +++ b/arch/mips/jz4740/Kconfig |
17 | @@ -10,6 +10,10 @@ config JZ4740_N516 |
18 | bool "Hanvon n516 eBook reader" |
19 | select SOC_JZ4740 |
20 | |
21 | +config JZ4740_N526 |
22 | + bool "Hanvon n526 eBook reader" |
23 | + select SOC_JZ4740 |
24 | + |
25 | endchoice |
26 | |
27 | config HAVE_PWM |
28 | diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile |
29 | index 727270a..e8f2904 100644 |
30 | --- a/arch/mips/jz4740/Makefile |
31 | +++ b/arch/mips/jz4740/Makefile |
32 | @@ -13,6 +13,7 @@ obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o |
33 | |
34 | obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o |
35 | obj-$(CONFIG_JZ4740_N516) += board-n516.o board-n516-display.o |
36 | +obj-$(CONFIG_JZ4740_N526) += board-n526.o |
37 | |
38 | # PM support |
39 | |
40 | diff --git a/arch/mips/jz4740/board-n526.c b/arch/mips/jz4740/board-n526.c |
41 | new file mode 100644 |
42 | index 0000000..494c4cb |
43 | --- /dev/null |
44 | +++ b/arch/mips/jz4740/board-n526.c |
45 | @@ -0,0 +1,320 @@ |
46 | +/* |
47 | + * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de> |
48 | + * N526 eBook reader support |
49 | + * |
50 | + * This program is free software; you can redistribute it and/or modify it |
51 | + * under the terms of the GNU General Public License as published by the |
52 | + * Free Software Foundation; either version 2 of the License, or (at your |
53 | + * option) any later version. |
54 | + * |
55 | + * You should have received a copy of the GNU General Public License along |
56 | + * with this program; if not, write to the Free Software Foundation, Inc., |
57 | + * 675 Mass Ave, Cambridge, MA 02139, USA. |
58 | + * |
59 | + */ |
60 | + |
61 | +#include <linux/kernel.h> |
62 | +#include <linux/init.h> |
63 | +#include <linux/gpio.h> |
64 | + |
65 | +#include <linux/mutex.h> |
66 | +#include <linux/wait.h> |
67 | +#include <video/broadsheetfb.h> |
68 | +#include <linux/delay.h> |
69 | +#include <linux/interrupt.h> |
70 | + |
71 | +#include <linux/input.h> |
72 | +#include <linux/gpio_keys.h> |
73 | + |
74 | +#include <linux/leds.h> |
75 | + |
76 | +#include <linux/i2c.h> |
77 | + |
78 | +#include "clock.h" |
79 | + |
80 | +#include <asm/mach-jz4740/jz4740_mmc.h> |
81 | +#include <asm/mach-jz4740/jz4740_nand.h> |
82 | +#include <asm/mach-jz4740/jz4740_fb.h> |
83 | + |
84 | +#include <asm/mach-jz4740/platform.h> |
85 | + |
86 | +/* NAND */ |
87 | +static struct nand_ecclayout n526_ecclayout = { |
88 | + .eccbytes = 36, |
89 | + .eccpos = { |
90 | + 6, 7, 8, 9, 10, 11, 12, 13, |
91 | + 14, 15, 16, 17, 18, 19, 20, 21, |
92 | + 22, 23, 24, 25, 26, 27, 28, 29, |
93 | + 30, 31, 32, 33, 34, 35, 36, 37, |
94 | + 38, 39, 40, 41}, |
95 | + .oobfree = { |
96 | + { |
97 | + .offset = 2, |
98 | + .length = 4, |
99 | + }, |
100 | + { |
101 | + .offset = 42, |
102 | + .length = 22, |
103 | + }, |
104 | + } |
105 | +}; |
106 | + |
107 | +static struct mtd_partition n526_partitions[] = { |
108 | + { .name = "NAND BOOT partition", |
109 | + .offset = 0 * 0x100000, |
110 | + .size = 4 * 0x100000, |
111 | + }, |
112 | + { .name = "NAND KERNEL partition", |
113 | + .offset = 4 * 0x100000, |
114 | + .size = 4 * 0x100000, |
115 | + }, |
116 | + { .name = "NAND ROOTFS partition", |
117 | + .offset = 16 * 0x100000, |
118 | + .size = 498 * 0x100000, |
119 | + }, |
120 | +}; |
121 | + |
122 | +static struct jz_nand_platform_data n526_nand_pdata = { |
123 | + .ecc_layout = &n526_ecclayout, |
124 | + .partitions = n526_partitions, |
125 | + .num_partitions = ARRAY_SIZE(n526_partitions), |
126 | + .busy_gpio = JZ_GPIO_PORTC(30), |
127 | +}; |
128 | + |
129 | +static struct jz4740_mmc_platform_data n526_mmc_pdata = { |
130 | + .gpio_card_detect = JZ_GPIO_PORTD(7), |
131 | + .card_detect_active_low = 1, |
132 | + .gpio_read_only = -1, |
133 | + .gpio_power = JZ_GPIO_PORTD(17), |
134 | + .power_active_low = 1, |
135 | +}; |
136 | + |
137 | +static struct gpio_led n526_leds[] = { |
138 | + { |
139 | + .name = "n526:blue:power", |
140 | + .gpio = JZ_GPIO_PORTD(28), |
141 | + .default_state = LEDS_GPIO_DEFSTATE_ON, |
142 | + } |
143 | +}; |
144 | + |
145 | +static struct gpio_led_platform_data n526_leds_pdata = { |
146 | + .leds = n526_leds, |
147 | + .num_leds = ARRAY_SIZE(n526_leds), |
148 | +}; |
149 | + |
150 | +static struct platform_device n526_leds_device = { |
151 | + .name = "leds-gpio", |
152 | + .id = -1, |
153 | + .dev = { |
154 | + .platform_data = &n526_leds_pdata, |
155 | + }, |
156 | +}; |
157 | + |
158 | +static void __init board_gpio_setup(void) |
159 | +{ |
160 | + /* We only need to enable/disable pullup here for pins used in generic |
161 | + * drivers. Everything else is done by the drivers themselfs. */ |
162 | + jz_gpio_disable_pullup(JZ_GPIO_PORTD(17)); |
163 | + jz_gpio_enable_pullup(JZ_GPIO_PORTD(7)); |
164 | + jz_gpio_disable_pullup(JZ_GPIO_PORTC(19)); |
165 | + jz_gpio_disable_pullup(JZ_GPIO_PORTC(20)); |
166 | + jz_gpio_disable_pullup(JZ_GPIO_PORTC(21)); |
167 | + jz_gpio_disable_pullup(JZ_GPIO_PORTC(23)); |
168 | +} |
169 | + |
170 | + |
171 | +static const int n526_eink_ctrl_gpios[] = { |
172 | + 0, |
173 | + JZ_GPIO_PORTC(23), |
174 | + JZ_GPIO_PORTC(19), |
175 | + JZ_GPIO_PORTC(20), |
176 | +}; |
177 | + |
178 | +static void n526_eink_set_ctl(struct broadsheetfb_par * par, unsigned char ctrl, u8 |
179 | +value) |
180 | +{ |
181 | + gpio_set_value(n526_eink_ctrl_gpios[ctrl], value); |
182 | +} |
183 | + |
184 | + |
185 | +static int n526_eink_wait(struct broadsheetfb_par *par) |
186 | +{ |
187 | + wait_event(par->waitq, gpio_get_value(JZ_GPIO_PORTB(17))); |
188 | + |
189 | + return 0; |
190 | +} |
191 | + |
192 | +static u16 n526_eink_get_hdb(struct broadsheetfb_par *par) |
193 | +{ |
194 | + u16 value = 0; |
195 | + jz_gpio_port_direction_input(JZ_GPIO_PORTC(0), 0xffff); |
196 | + gpio_set_value(JZ_GPIO_PORTC(21), 0); |
197 | + mdelay(100); |
198 | + |
199 | + value = jz_gpio_port_get_value(JZ_GPIO_PORTC(0), 0xffff); |
200 | + |
201 | + gpio_set_value(JZ_GPIO_PORTC(21), 1); |
202 | + jz_gpio_port_direction_output(JZ_GPIO_PORTC(0), 0xffff); |
203 | + return value; |
204 | +} |
205 | + |
206 | +static void n526_eink_set_hdb(struct broadsheetfb_par *par, u16 value) |
207 | +{ |
208 | + jz_gpio_port_set_value(JZ_GPIO_PORTC(0), value, 0xffff); |
209 | +} |
210 | + |
211 | +static int n526_eink_init(struct broadsheetfb_par *par) |
212 | +{ |
213 | + int i; |
214 | + |
215 | + gpio_request(JZ_GPIO_PORTD(1), "display reset"); |
216 | + gpio_direction_output(JZ_GPIO_PORTD(1), 1); |
217 | + mdelay(10); |
218 | + gpio_set_value(JZ_GPIO_PORTD(1), 0); |
219 | + |
220 | + gpio_request(JZ_GPIO_PORTB(18), "eink enable"); |
221 | + gpio_direction_output(JZ_GPIO_PORTB(18), 0); |
222 | + |
223 | + gpio_request(JZ_GPIO_PORTB(29), "foobar"); |
224 | + gpio_direction_output(JZ_GPIO_PORTB(29), 1); |
225 | + |
226 | + for(i = 1; i < ARRAY_SIZE(n526_eink_ctrl_gpios); ++i) { |
227 | + gpio_request(n526_eink_ctrl_gpios[i], "eink display ctrl"); |
228 | + gpio_direction_output(n526_eink_ctrl_gpios[i], 0); |
229 | + } |
230 | + |
231 | + gpio_request(JZ_GPIO_PORTC(22), "foobar"); |
232 | + gpio_direction_input(JZ_GPIO_PORTC(22)); |
233 | + gpio_request(JZ_GPIO_PORTC(21), "eink nRD"); |
234 | + gpio_direction_output(JZ_GPIO_PORTC(21), 1); |
235 | + |
236 | + for(i = 0; i < 16; ++i) { |
237 | + gpio_request(JZ_GPIO_PORTC(i), "eink display data"); |
238 | + } |
239 | + jz_gpio_port_direction_output(JZ_GPIO_PORTC(0), 0xffff); |
240 | + |
241 | + gpio_set_value(JZ_GPIO_PORTB(18), 1); |
242 | + |
243 | + return 0; |
244 | +} |
245 | + |
246 | +static irqreturn_t n526_eink_busy_irq(int irq, void *devid) |
247 | +{ |
248 | + struct broadsheetfb_par *par = devid; |
249 | + wake_up(&par->waitq); |
250 | + |
251 | + return IRQ_HANDLED; |
252 | +} |
253 | + |
254 | +static int n526_eink_setup_irq(struct fb_info *info) |
255 | +{ |
256 | + int ret; |
257 | + struct broadsheetfb_par *par = info->par; |
258 | + |
259 | + gpio_request(JZ_GPIO_PORTB(17), "eink busy"); |
260 | + gpio_direction_input(JZ_GPIO_PORTB(17)); |
261 | + |
262 | + ret = request_irq(gpio_to_irq(JZ_GPIO_PORTB(17)), n526_eink_busy_irq, |
263 | + IRQF_DISABLED | IRQF_TRIGGER_RISING, |
264 | + "eink busyline", par); |
265 | + if (ret) |
266 | + printk("n526 display: Failed to request busyline irq: %d\n", ret); |
267 | + return 0; |
268 | +} |
269 | + |
270 | +static void n526_eink_cleanup(struct broadsheetfb_par *par) |
271 | +{ |
272 | +} |
273 | + |
274 | +static struct broadsheet_board broadsheet_pdata = { |
275 | + .owner = THIS_MODULE, |
276 | + .init = n526_eink_init, |
277 | + .wait_for_rdy = n526_eink_wait, |
278 | + .set_ctl = n526_eink_set_ctl, |
279 | + .set_hdb = n526_eink_set_hdb, |
280 | + .get_hdb = n526_eink_get_hdb, |
281 | + .cleanup = n526_eink_cleanup, |
282 | + .setup_irq = n526_eink_setup_irq, |
283 | +}; |
284 | + |
285 | +static struct platform_device n526_broadsheet_device = { |
286 | + .name = "broadsheetfb", |
287 | + .id = -1, |
288 | + .dev = { |
289 | + .platform_data = &broadsheet_pdata, |
290 | + }, |
291 | +}; |
292 | + |
293 | +/* Buttons */ |
294 | +static struct gpio_keys_button n526_gpio_keys_buttons[] = { |
295 | + [0] = { |
296 | + .code = KEY_ENTER, |
297 | + .gpio = 0, |
298 | + .active_low = 1, |
299 | + .desc = "Power", |
300 | + }, |
301 | +}; |
302 | + |
303 | +static struct gpio_keys_platform_data n526_gpio_keys_data = { |
304 | + .nbuttons = ARRAY_SIZE(n526_gpio_keys_buttons), |
305 | + .buttons = n526_gpio_keys_buttons, |
306 | +}; |
307 | + |
308 | +static struct platform_device n526_gpio_keys_device = { |
309 | + .name = "gpio-keys", |
310 | + .id = -1, |
311 | + .dev = { |
312 | + .platform_data = &n526_gpio_keys_data, |
313 | + } |
314 | +}; |
315 | + |
316 | +static struct i2c_board_info n526_i2c_board_info = { |
317 | + .type = "n526-lpc", |
318 | + .addr = 0x54, |
319 | +}; |
320 | + |
321 | +static struct platform_device *n526_platform_devices[] __initdata = { |
322 | + &jz4740_usb_ohci_device, |
323 | + &jz4740_udc_device, |
324 | + &jz4740_mmc_device, |
325 | + &jz4740_nand_device, |
326 | + &jz4740_i2s_device, |
327 | + &jz4740_codec_device, |
328 | + &jz4740_pcm_device, |
329 | + &jz4740_rtc_device, |
330 | + &jz4740_i2c_device, |
331 | + &n526_leds_device, |
332 | + &n526_broadsheet_device, |
333 | + &n526_gpio_keys_device, |
334 | +}; |
335 | + |
336 | +static int __init n526_init_platform_devices(void) |
337 | +{ |
338 | + jz4740_nand_device.dev.platform_data = &n526_nand_pdata; |
339 | + jz4740_mmc_device.dev.platform_data = &n526_mmc_pdata; |
340 | + |
341 | + jz4740_serial_device_register(); |
342 | + |
343 | + n526_i2c_board_info.irq = gpio_to_irq(JZ_GPIO_PORTD(14)), |
344 | + i2c_register_board_info(0, &n526_i2c_board_info, 1); |
345 | + |
346 | + return platform_add_devices(n526_platform_devices, |
347 | + ARRAY_SIZE(n526_platform_devices)); |
348 | + |
349 | +} |
350 | + |
351 | +struct jz4740_clock_board_data jz4740_clock_bdata = { |
352 | + .ext_rate = 12000000, |
353 | + .rtc_rate = 32768, |
354 | +}; |
355 | + |
356 | +static int __init n526_board_setup(void) |
357 | +{ |
358 | + board_gpio_setup(); |
359 | + |
360 | + if (n526_init_platform_devices()) |
361 | + panic("Failed to initalize platform devices\n"); |
362 | + |
363 | + return 0; |
364 | +} |
365 | +arch_initcall(n526_board_setup); |
366 | -- |
367 | 1.7.4.1 |
368 | |
369 |