blob: 621b343adbedf27119701c0ade2f42ad0e165752 [file] [log] [blame]
Christer Weinigel95790872008-07-07 18:12:45 +01001/* Machine specific code for the Acer n30, Acer N35, Navman PiN 570,
2 * Yakumo AlphaX and Airis NC05 PDAs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (c) 2003-2005 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 *
Christer Weinigel196a0472008-07-07 18:12:41 +01007 * Copyright (c) 2005-2008 Christer Weinigel <christer@weinigel.se>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * There is a wiki with more information about the n30 port at
10 * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
Christer Weinigel95790872008-07-07 18:12:45 +010015 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include <linux/kernel.h>
18#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Christer Weinigel196a0472008-07-07 18:12:41 +010020#include <linux/delay.h>
Christer Weinigel62065752008-07-07 18:12:43 +010021#include <linux/gpio_keys.h>
Christer Weinigel196a0472008-07-07 18:12:41 +010022#include <linux/init.h>
Christer Weinigel62065752008-07-07 18:12:43 +010023#include <linux/input.h>
Christer Weinigel196a0472008-07-07 18:12:41 +010024#include <linux/interrupt.h>
25#include <linux/platform_device.h>
26#include <linux/serial_core.h>
27#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <asm/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/mach-types.h>
33
Christer Weinigel865cc632008-07-07 18:12:44 +010034#include <asm/arch/leds-gpio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/arch/regs-gpio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Christer Weinigel196a0472008-07-07 18:12:41 +010037#include <asm/mach/arch.h>
38#include <asm/mach/irq.h>
39#include <asm/mach/map.h>
40
41#include <asm/plat-s3c/iic.h>
42#include <asm/plat-s3c/regs-serial.h>
43
Ben Dooksa21765a2007-02-11 18:31:01 +010044#include <asm/plat-s3c24xx/clock.h>
Ben Dooksa21765a2007-02-11 18:31:01 +010045#include <asm/plat-s3c24xx/cpu.h>
Christer Weinigel196a0472008-07-07 18:12:41 +010046#include <asm/plat-s3c24xx/devs.h>
47#include <asm/plat-s3c24xx/s3c2410.h>
Christer Weinigeld088e5f2008-07-07 18:12:42 +010048#include <asm/plat-s3c24xx/udc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50static struct map_desc n30_iodesc[] __initdata = {
51 /* nothing here yet */
52};
53
54static struct s3c2410_uartcfg n30_uartcfgs[] = {
55 /* Normal serial port */
56 [0] = {
57 .hwport = 0,
58 .flags = 0,
59 .ucon = 0x2c5,
60 .ulcon = 0x03,
61 .ufcon = 0x51,
62 },
63 /* IR port */
64 [1] = {
65 .hwport = 1,
66 .flags = 0,
67 .uart_flags = UPF_CONS_FLOW,
68 .ucon = 0x2c5,
69 .ulcon = 0x43,
70 .ufcon = 0x51,
71 },
Christer Weinigel95790872008-07-07 18:12:45 +010072 /* On the N30 the bluetooth controller is connected here.
73 * On the N35 and variants the GPS receiver is connected here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 [2] = {
75 .hwport = 2,
76 .flags = 0,
77 .ucon = 0x2c5,
78 .ulcon = 0x03,
79 .ufcon = 0x51,
80 },
81};
82
Christer Weinigeld088e5f2008-07-07 18:12:42 +010083static void n30_udc_pullup(enum s3c2410_udc_cmd_e cmd)
84{
85 switch (cmd)
86 {
87 case S3C2410_UDC_P_ENABLE :
88 s3c2410_gpio_setpin(S3C2410_GPB3, 1);
89 break;
90 case S3C2410_UDC_P_DISABLE :
91 s3c2410_gpio_setpin(S3C2410_GPB3, 0);
92 break;
93 case S3C2410_UDC_P_RESET :
94 break;
95 default:
96 break;
97 }
98}
99
100static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
101 .udc_command = n30_udc_pullup,
102 .vbus_pin = S3C2410_GPG1,
103 .vbus_pin_inverted = 0,
104};
105
Christer Weinigel62065752008-07-07 18:12:43 +0100106static struct gpio_keys_button n30_buttons[] = {
107 {
108 .gpio = S3C2410_GPF0,
109 .code = KEY_POWER,
110 .desc = "Power",
111 .active_low = 0,
112 },
113 {
114 .gpio = S3C2410_GPG9,
115 .code = KEY_UP,
116 .desc = "Thumbwheel Up",
117 .active_low = 0,
118 },
119 {
120 .gpio = S3C2410_GPG8,
121 .code = KEY_DOWN,
122 .desc = "Thumbwheel Down",
123 .active_low = 0,
124 },
125 {
126 .gpio = S3C2410_GPG7,
127 .code = KEY_ENTER,
128 .desc = "Thumbwheel Press",
129 .active_low = 0,
130 },
131 {
132 .gpio = S3C2410_GPF7,
133 .code = KEY_HOMEPAGE,
134 .desc = "Home",
135 .active_low = 0,
136 },
137 {
138 .gpio = S3C2410_GPF6,
139 .code = KEY_CALENDAR,
140 .desc = "Calendar",
141 .active_low = 0,
142 },
143 {
144 .gpio = S3C2410_GPF5,
145 .code = KEY_ADDRESSBOOK,
146 .desc = "Contacts",
147 .active_low = 0,
148 },
149 {
150 .gpio = S3C2410_GPF4,
151 .code = KEY_MAIL,
152 .desc = "Mail",
153 .active_low = 0,
154 },
155};
156
157static struct gpio_keys_platform_data n30_button_data = {
158 .buttons = n30_buttons,
159 .nbuttons = ARRAY_SIZE(n30_buttons),
160};
161
162static struct platform_device n30_button_device = {
163 .name = "gpio-keys",
164 .id = -1,
165 .dev = {
166 .platform_data = &n30_button_data,
167 }
168};
169
Christer Weinigel95790872008-07-07 18:12:45 +0100170static struct gpio_keys_button n35_buttons[] = {
171 {
172 .gpio = S3C2410_GPF0,
173 .code = KEY_POWER,
174 .desc = "Power",
175 .active_low = 0,
176 },
177 {
178 .gpio = S3C2410_GPG9,
179 .code = KEY_UP,
180 .desc = "Joystick Up",
181 .active_low = 0,
182 },
183 {
184 .gpio = S3C2410_GPG8,
185 .code = KEY_DOWN,
186 .desc = "Joystick Down",
187 .active_low = 0,
188 },
189 {
190 .gpio = S3C2410_GPG6,
191 .code = KEY_DOWN,
192 .desc = "Joystick Left",
193 .active_low = 0,
194 },
195 {
196 .gpio = S3C2410_GPG5,
197 .code = KEY_DOWN,
198 .desc = "Joystick Right",
199 .active_low = 0,
200 },
201 {
202 .gpio = S3C2410_GPG7,
203 .code = KEY_ENTER,
204 .desc = "Joystick Press",
205 .active_low = 0,
206 },
207 {
208 .gpio = S3C2410_GPF7,
209 .code = KEY_HOMEPAGE,
210 .desc = "Home",
211 .active_low = 0,
212 },
213 {
214 .gpio = S3C2410_GPF6,
215 .code = KEY_CALENDAR,
216 .desc = "Calendar",
217 .active_low = 0,
218 },
219 {
220 .gpio = S3C2410_GPF5,
221 .code = KEY_ADDRESSBOOK,
222 .desc = "Contacts",
223 .active_low = 0,
224 },
225 {
226 .gpio = S3C2410_GPF4,
227 .code = KEY_MAIL,
228 .desc = "Mail",
229 .active_low = 0,
230 },
231 {
232 .gpio = S3C2410_GPF3,
233 .code = SW_RADIO,
234 .desc = "GPS Antenna",
235 .active_low = 0,
236 },
237 {
238 .gpio = S3C2410_GPG2,
239 .code = SW_HEADPHONE_INSERT,
240 .desc = "Headphone",
241 .active_low = 0,
242 },
243};
244
245static struct gpio_keys_platform_data n35_button_data = {
246 .buttons = n35_buttons,
247 .nbuttons = ARRAY_SIZE(n35_buttons),
248};
249
250static struct platform_device n35_button_device = {
251 .name = "gpio-keys",
252 .id = -1,
253 .num_resources = 0,
254 .dev = {
255 .platform_data = &n35_button_data,
256 }
257};
258
Christer Weinigel865cc632008-07-07 18:12:44 +0100259/* This is the bluetooth LED on the device. */
260static struct s3c24xx_led_platdata n30_blue_led_pdata = {
261 .name = "blue_led",
262 .gpio = S3C2410_GPG6,
263 .def_trigger = "",
264};
265
266/* This LED is driven by the battery microcontroller, and is blinking
267 * red, blinking green or solid green when the battery is low,
268 * charging or full respectively. By driving GPD9 low, it's possible
269 * to force the LED to blink red, so call that warning LED. */
270static struct s3c24xx_led_platdata n30_warning_led_pdata = {
271 .name = "warning_led",
272 .flags = S3C24XX_LEDF_ACTLOW,
273 .gpio = S3C2410_GPD9,
274 .def_trigger = "",
275};
276
277static struct platform_device n30_blue_led = {
278 .name = "s3c24xx_led",
279 .id = 1,
280 .dev = {
281 .platform_data = &n30_blue_led_pdata,
282 },
283};
284
285static struct platform_device n30_warning_led = {
286 .name = "s3c24xx_led",
287 .id = 2,
288 .dev = {
289 .platform_data = &n30_warning_led_pdata,
290 },
291};
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static struct platform_device *n30_devices[] __initdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 &s3c_device_lcd,
295 &s3c_device_wdt,
296 &s3c_device_i2c,
297 &s3c_device_iis,
Christer Weinigel196a0472008-07-07 18:12:41 +0100298 &s3c_device_usb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 &s3c_device_usbgadget,
Christer Weinigel62065752008-07-07 18:12:43 +0100300 &n30_button_device,
Christer Weinigel865cc632008-07-07 18:12:44 +0100301 &n30_blue_led,
302 &n30_warning_led,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303};
304
Christer Weinigel95790872008-07-07 18:12:45 +0100305static struct platform_device *n35_devices[] __initdata = {
306 &s3c_device_lcd,
307 &s3c_device_wdt,
308 &s3c_device_i2c,
309 &s3c_device_iis,
310 &s3c_device_usbgadget,
311 &n35_button_device,
312};
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314static struct s3c2410_platform_i2c n30_i2ccfg = {
315 .flags = 0,
316 .slave_addr = 0x10,
317 .bus_freq = 10*1000,
318 .max_freq = 10*1000,
319};
320
Ben Dooks5fe10ab2005-09-20 17:24:33 +0100321static void __init n30_map_io(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
324 s3c24xx_init_clocks(0);
325 s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Ben Dooks5fe10ab2005-09-20 17:24:33 +0100328static void __init n30_init_irq(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 s3c24xx_init_irq();
331}
332
Ben Dooks027da012005-09-05 20:47:53 +0100333/* GPB3 is the line that controls the pull-up for the USB D+ line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Ben Dooks5fe10ab2005-09-20 17:24:33 +0100335static void __init n30_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
337 s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
Christer Weinigeld088e5f2008-07-07 18:12:42 +0100338 s3c24xx_udc_set_platdata(&n30_udc_cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Ben Dooks027da012005-09-05 20:47:53 +0100340 /* Turn off suspend on both USB ports, and switch the
341 * selectable USB port to USB device mode. */
342
343 s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
344 S3C2410_MISCCR_USBSUSPND0 |
345 S3C2410_MISCCR_USBSUSPND1, 0x0);
Ben Dooks57e51712007-04-20 11:19:16 +0100346
Christer Weinigel95790872008-07-07 18:12:45 +0100347 if (machine_is_n30()) {
348 /* Turn off suspend on both USB ports, and switch the
349 * selectable USB port to USB device mode. */
350 s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
351 S3C2410_MISCCR_USBSUSPND0 |
352 S3C2410_MISCCR_USBSUSPND1, 0x0);
353
354 platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
355 }
356
357 if (machine_is_n35()) {
358 /* Turn off suspend and switch the selectable USB port
359 * to USB device mode. Turn on suspend for the host
360 * port since it is not connected on the N35.
361 *
362 * Actually, the host port is available at some pads
363 * on the back of the device, so it would actually be
364 * possible to add a USB device inside the N35 if you
365 * are willing to do some hardware modifications. */
366 s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
367 S3C2410_MISCCR_USBSUSPND0 |
368 S3C2410_MISCCR_USBSUSPND1,
369 S3C2410_MISCCR_USBSUSPND1);
370
371 platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices));
372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375MACHINE_START(N30, "Acer-N30")
Ben Dooks027da012005-09-05 20:47:53 +0100376 /* Maintainer: Christer Weinigel <christer@weinigel.se>,
377 Ben Dooks <ben-linux@fluff.org>
378 */
Russell Kinge9dea0c2005-07-03 17:38:58 +0100379 .phys_io = S3C2410_PA_UART,
380 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
381 .boot_params = S3C2410_SDRAM_PA + 0x100,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .timer = &s3c24xx_timer,
383 .init_machine = n30_init,
384 .init_irq = n30_init_irq,
385 .map_io = n30_map_io,
386MACHINE_END
Christer Weinigel95790872008-07-07 18:12:45 +0100387
388MACHINE_START(N35, "Acer-N35")
389 /* Maintainer: Christer Weinigel <christer@weinigel.se>
390 */
391 .phys_io = S3C2410_PA_UART,
392 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
393 .boot_params = S3C2410_SDRAM_PA + 0x100,
394 .timer = &s3c24xx_timer,
395 .init_machine = n30_init,
396 .init_irq = n30_init_irq,
397 .map_io = n30_map_io,
398MACHINE_END