• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Machine specific code for the Acer n30, Acer N35, Navman PiN 570,
2  * Yakumo AlphaX and Airis NC05 PDAs.
3  *
4  * Copyright (c) 2003-2005 Simtec Electronics
5  *	Ben Dooks <ben@simtec.co.uk>
6  *
7  * Copyright (c) 2005-2008 Christer Weinigel <christer@weinigel.se>
8  *
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.
15  */
16 
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 
20 #include <linux/gpio_keys.h>
21 #include <linux/init.h>
22 #include <linux/gpio.h>
23 #include <linux/input.h>
24 #include <linux/interrupt.h>
25 #include <linux/platform_device.h>
26 #include <linux/serial_core.h>
27 #include <linux/serial_s3c.h>
28 #include <linux/timer.h>
29 #include <linux/io.h>
30 #include <linux/mmc/host.h>
31 
32 #include <mach/hardware.h>
33 #include <asm/irq.h>
34 #include <asm/mach-types.h>
35 
36 #include <mach/fb.h>
37 #include <linux/platform_data/leds-s3c24xx.h>
38 #include <mach/regs-gpio.h>
39 #include <mach/regs-lcd.h>
40 #include <mach/gpio-samsung.h>
41 
42 #include <asm/mach/arch.h>
43 #include <asm/mach/irq.h>
44 #include <asm/mach/map.h>
45 
46 #include <linux/platform_data/i2c-s3c2410.h>
47 
48 #include <plat/cpu.h>
49 #include <plat/devs.h>
50 #include <linux/platform_data/mmc-s3cmci.h>
51 #include <linux/platform_data/usb-s3c2410_udc.h>
52 #include <plat/samsung-time.h>
53 
54 #include "common.h"
55 
56 static struct map_desc n30_iodesc[] __initdata = {
57 	/* nothing here yet */
58 };
59 
60 static struct s3c2410_uartcfg n30_uartcfgs[] = {
61 	/* Normal serial port */
62 	[0] = {
63 		.hwport	     = 0,
64 		.flags	     = 0,
65 		.ucon	     = 0x2c5,
66 		.ulcon	     = 0x03,
67 		.ufcon	     = 0x51,
68 	},
69 	/* IR port */
70 	[1] = {
71 		.hwport	     = 1,
72 		.flags	     = 0,
73 		.uart_flags  = UPF_CONS_FLOW,
74 		.ucon	     = 0x2c5,
75 		.ulcon	     = 0x43,
76 		.ufcon	     = 0x51,
77 	},
78 	/* On the N30 the bluetooth controller is connected here.
79 	 * On the N35 and variants the GPS receiver is connected here. */
80 	[2] = {
81 		.hwport	     = 2,
82 		.flags	     = 0,
83 		.ucon	     = 0x2c5,
84 		.ulcon	     = 0x03,
85 		.ufcon	     = 0x51,
86 	},
87 };
88 
89 static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
90 	.vbus_pin		= S3C2410_GPG(1),
91 	.vbus_pin_inverted	= 0,
92 	.pullup_pin		= S3C2410_GPB(3),
93 };
94 
95 static struct gpio_keys_button n30_buttons[] = {
96 	{
97 		.gpio		= S3C2410_GPF(0),
98 		.code		= KEY_POWER,
99 		.desc		= "Power",
100 		.active_low	= 0,
101 	},
102 	{
103 		.gpio		= S3C2410_GPG(9),
104 		.code		= KEY_UP,
105 		.desc		= "Thumbwheel Up",
106 		.active_low	= 0,
107 	},
108 	{
109 		.gpio		= S3C2410_GPG(8),
110 		.code		= KEY_DOWN,
111 		.desc		= "Thumbwheel Down",
112 		.active_low	= 0,
113 	},
114 	{
115 		.gpio		= S3C2410_GPG(7),
116 		.code		= KEY_ENTER,
117 		.desc		= "Thumbwheel Press",
118 		.active_low	= 0,
119 	},
120 	{
121 		.gpio		= S3C2410_GPF(7),
122 		.code		= KEY_HOMEPAGE,
123 		.desc		= "Home",
124 		.active_low	= 0,
125 	},
126 	{
127 		.gpio		= S3C2410_GPF(6),
128 		.code		= KEY_CALENDAR,
129 		.desc		= "Calendar",
130 		.active_low	= 0,
131 	},
132 	{
133 		.gpio		= S3C2410_GPF(5),
134 		.code		= KEY_ADDRESSBOOK,
135 		.desc		= "Contacts",
136 		.active_low	= 0,
137 	},
138 	{
139 		.gpio		= S3C2410_GPF(4),
140 		.code		= KEY_MAIL,
141 		.desc		= "Mail",
142 		.active_low	= 0,
143 	},
144 };
145 
146 static struct gpio_keys_platform_data n30_button_data = {
147 	.buttons	= n30_buttons,
148 	.nbuttons	= ARRAY_SIZE(n30_buttons),
149 };
150 
151 static struct platform_device n30_button_device = {
152 	.name		= "gpio-keys",
153 	.id		= -1,
154 	.dev		= {
155 		.platform_data	= &n30_button_data,
156 	}
157 };
158 
159 static struct gpio_keys_button n35_buttons[] = {
160 	{
161 		.gpio		= S3C2410_GPF(0),
162 		.code		= KEY_POWER,
163 		.type		= EV_PWR,
164 		.desc		= "Power",
165 		.active_low	= 0,
166 		.wakeup		= 1,
167 	},
168 	{
169 		.gpio		= S3C2410_GPG(9),
170 		.code		= KEY_UP,
171 		.desc		= "Joystick Up",
172 		.active_low	= 0,
173 	},
174 	{
175 		.gpio		= S3C2410_GPG(8),
176 		.code		= KEY_DOWN,
177 		.desc		= "Joystick Down",
178 		.active_low	= 0,
179 	},
180 	{
181 		.gpio		= S3C2410_GPG(6),
182 		.code		= KEY_DOWN,
183 		.desc		= "Joystick Left",
184 		.active_low	= 0,
185 	},
186 	{
187 		.gpio		= S3C2410_GPG(5),
188 		.code		= KEY_DOWN,
189 		.desc		= "Joystick Right",
190 		.active_low	= 0,
191 	},
192 	{
193 		.gpio		= S3C2410_GPG(7),
194 		.code		= KEY_ENTER,
195 		.desc		= "Joystick Press",
196 		.active_low	= 0,
197 	},
198 	{
199 		.gpio		= S3C2410_GPF(7),
200 		.code		= KEY_HOMEPAGE,
201 		.desc		= "Home",
202 		.active_low	= 0,
203 	},
204 	{
205 		.gpio		= S3C2410_GPF(6),
206 		.code		= KEY_CALENDAR,
207 		.desc		= "Calendar",
208 		.active_low	= 0,
209 	},
210 	{
211 		.gpio		= S3C2410_GPF(5),
212 		.code		= KEY_ADDRESSBOOK,
213 		.desc		= "Contacts",
214 		.active_low	= 0,
215 	},
216 	{
217 		.gpio		= S3C2410_GPF(4),
218 		.code		= KEY_MAIL,
219 		.desc		= "Mail",
220 		.active_low	= 0,
221 	},
222 	{
223 		.gpio		= S3C2410_GPF(3),
224 		.code		= SW_RADIO,
225 		.desc		= "GPS Antenna",
226 		.active_low	= 0,
227 	},
228 	{
229 		.gpio		= S3C2410_GPG(2),
230 		.code		= SW_HEADPHONE_INSERT,
231 		.desc		= "Headphone",
232 		.active_low	= 0,
233 	},
234 };
235 
236 static struct gpio_keys_platform_data n35_button_data = {
237 	.buttons	= n35_buttons,
238 	.nbuttons	= ARRAY_SIZE(n35_buttons),
239 };
240 
241 static struct platform_device n35_button_device = {
242 	.name		= "gpio-keys",
243 	.id		= -1,
244 	.num_resources	= 0,
245 	.dev		= {
246 		.platform_data	= &n35_button_data,
247 	}
248 };
249 
250 /* This is the bluetooth LED on the device. */
251 static struct s3c24xx_led_platdata n30_blue_led_pdata = {
252 	.name		= "blue_led",
253 	.gpio		= S3C2410_GPG(6),
254 	.def_trigger	= "",
255 };
256 
257 /* This is the blue LED on the device. Originally used to indicate GPS activity
258  * by flashing. */
259 static struct s3c24xx_led_platdata n35_blue_led_pdata = {
260 	.name		= "blue_led",
261 	.gpio		= S3C2410_GPD(8),
262 	.def_trigger	= "",
263 };
264 
265 /* This LED is driven by the battery microcontroller, and is blinking
266  * red, blinking green or solid green when the battery is low,
267  * charging or full respectively.  By driving GPD9 low, it's possible
268  * to force the LED to blink red, so call that warning LED.  */
269 static struct s3c24xx_led_platdata n30_warning_led_pdata = {
270 	.name		= "warning_led",
271 	.flags          = S3C24XX_LEDF_ACTLOW,
272 	.gpio		= S3C2410_GPD(9),
273 	.def_trigger	= "",
274 };
275 
276 static struct s3c24xx_led_platdata n35_warning_led_pdata = {
277 	.name		= "warning_led",
278 	.flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
279 	.gpio		= S3C2410_GPD(9),
280 	.def_trigger	= "",
281 };
282 
283 static struct platform_device n30_blue_led = {
284 	.name		= "s3c24xx_led",
285 	.id		= 1,
286 	.dev		= {
287 		.platform_data	= &n30_blue_led_pdata,
288 	},
289 };
290 
291 static struct platform_device n35_blue_led = {
292 	.name		= "s3c24xx_led",
293 	.id		= 1,
294 	.dev		= {
295 		.platform_data	= &n35_blue_led_pdata,
296 	},
297 };
298 
299 static struct platform_device n30_warning_led = {
300 	.name		= "s3c24xx_led",
301 	.id		= 2,
302 	.dev		= {
303 		.platform_data	= &n30_warning_led_pdata,
304 	},
305 };
306 
307 static struct platform_device n35_warning_led = {
308 	.name		= "s3c24xx_led",
309 	.id		= 2,
310 	.dev		= {
311 		.platform_data	= &n35_warning_led_pdata,
312 	},
313 };
314 
315 static struct s3c2410fb_display n30_display __initdata = {
316 	.type		= S3C2410_LCDCON1_TFT,
317 	.width		= 240,
318 	.height		= 320,
319 	.pixclock	= 170000,
320 
321 	.xres		= 240,
322 	.yres		= 320,
323 	.bpp		= 16,
324 	.left_margin	= 3,
325 	.right_margin	= 40,
326 	.hsync_len	= 40,
327 	.upper_margin	= 2,
328 	.lower_margin	= 3,
329 	.vsync_len	= 2,
330 
331 	.lcdcon5 = S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME,
332 };
333 
334 static struct s3c2410fb_mach_info n30_fb_info __initdata = {
335 	.displays	= &n30_display,
336 	.num_displays	= 1,
337 	.default_display = 0,
338 	.lpcsel		= 0x06,
339 };
340 
n30_sdi_set_power(unsigned char power_mode,unsigned short vdd)341 static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd)
342 {
343 	switch (power_mode) {
344 	case MMC_POWER_ON:
345 	case MMC_POWER_UP:
346 		gpio_set_value(S3C2410_GPG(4), 1);
347 		break;
348 	case MMC_POWER_OFF:
349 	default:
350 		gpio_set_value(S3C2410_GPG(4), 0);
351 		break;
352 	}
353 }
354 
355 static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = {
356 	.gpio_detect	= S3C2410_GPF(1),
357 	.gpio_wprotect  = S3C2410_GPG(10),
358 	.ocr_avail	= MMC_VDD_32_33,
359 	.set_power	= n30_sdi_set_power,
360 };
361 
362 static struct platform_device *n30_devices[] __initdata = {
363 	&s3c_device_lcd,
364 	&s3c_device_wdt,
365 	&s3c_device_i2c0,
366 	&s3c_device_iis,
367 	&s3c_device_ohci,
368 	&s3c_device_rtc,
369 	&s3c_device_usbgadget,
370 	&s3c_device_sdi,
371 	&n30_button_device,
372 	&n30_blue_led,
373 	&n30_warning_led,
374 };
375 
376 static struct platform_device *n35_devices[] __initdata = {
377 	&s3c_device_lcd,
378 	&s3c_device_wdt,
379 	&s3c_device_i2c0,
380 	&s3c_device_iis,
381 	&s3c_device_rtc,
382 	&s3c_device_usbgadget,
383 	&s3c_device_sdi,
384 	&n35_button_device,
385 	&n35_blue_led,
386 	&n35_warning_led,
387 };
388 
389 static struct s3c2410_platform_i2c __initdata n30_i2ccfg = {
390 	.flags		= 0,
391 	.slave_addr	= 0x10,
392 	.frequency	= 10*1000,
393 };
394 
395 /* Lots of hardcoded stuff, but it sets up the hardware in a useful
396  * state so that we can boot Linux directly from flash. */
n30_hwinit(void)397 static void __init n30_hwinit(void)
398 {
399 	/* GPA0-11 special functions -- unknown what they do
400 	 * GPA12 N30 special function -- unknown what it does
401 	 *       N35/PiN output -- unknown what it does
402 	 *
403 	 * A12 is nGCS1 on the N30 and an output on the N35/PiN.  I
404 	 * don't think it does anything useful on the N30, so I ought
405 	 * to make it an output there too since it always driven to 0
406 	 * as far as I can tell. */
407 	if (machine_is_n30())
408 		__raw_writel(0x007fffff, S3C2410_GPACON);
409 	if (machine_is_n35())
410 		__raw_writel(0x007fefff, S3C2410_GPACON);
411 	__raw_writel(0x00000000, S3C2410_GPADAT);
412 
413 	/* GPB0 TOUT0 backlight level
414 	 * GPB1 output 1=backlight on
415 	 * GPB2 output IrDA enable 0=transceiver enabled, 1=disabled
416 	 * GPB3 output USB D+ pull up 0=disabled, 1=enabled
417 	 * GPB4 N30 output -- unknown function
418 	 *      N30/PiN GPS control 0=GPS enabled, 1=GPS disabled
419 	 * GPB5 output -- unknown function
420 	 * GPB6 input -- unknown function
421 	 * GPB7 output -- unknown function
422 	 * GPB8 output -- probably LCD driver enable
423 	 * GPB9 output -- probably LCD VSYNC driver enable
424 	 * GPB10 output -- probably LCD HSYNC driver enable
425 	 */
426 	__raw_writel(0x00154556, S3C2410_GPBCON);
427 	__raw_writel(0x00000750, S3C2410_GPBDAT);
428 	__raw_writel(0x00000073, S3C2410_GPBUP);
429 
430 	/* GPC0 input RS232 DCD/DSR/RI
431 	 * GPC1 LCD
432 	 * GPC2 output RS232 DTR?
433 	 * GPC3 input RS232 DCD/DSR/RI
434 	 * GPC4 LCD
435 	 * GPC5 output 0=NAND write enabled, 1=NAND write protect
436 	 * GPC6 input -- unknown function
437 	 * GPC7 input charger status 0=charger connected
438 	 *      this input can be triggered by power on the USB device
439 	 *      port too, but will go back to disconnected soon after.
440 	 * GPC8 N30/N35 output -- unknown function, always driven to 1
441 	 *      PiN input -- unknown function, always read as 1
442 	 *      Make it an input with a pull up for all models.
443 	 * GPC9-15 LCD
444 	 */
445 	__raw_writel(0xaaa80618, S3C2410_GPCCON);
446 	__raw_writel(0x0000014c, S3C2410_GPCDAT);
447 	__raw_writel(0x0000fef2, S3C2410_GPCUP);
448 
449 	/* GPD0 input -- unknown function
450 	 * GPD1-D7 LCD
451 	 * GPD8 N30 output -- unknown function
452 	 *      N35/PiN output 1=GPS LED on
453 	 * GPD9 output 0=power led blinks red, 1=normal power led function
454 	 * GPD10 output -- unknown function
455 	 * GPD11-15 LCD drivers
456 	 */
457 	__raw_writel(0xaa95aaa4, S3C2410_GPDCON);
458 	__raw_writel(0x00000601, S3C2410_GPDDAT);
459 	__raw_writel(0x0000fbfe, S3C2410_GPDUP);
460 
461 	/* GPE0-4 I2S audio bus
462 	 * GPE5-10 SD/MMC bus
463 	 * E11-13 outputs -- unknown function, probably power management
464 	 * E14-15 I2C bus connected to the battery controller
465 	 */
466 	__raw_writel(0xa56aaaaa, S3C2410_GPECON);
467 	__raw_writel(0x0000efc5, S3C2410_GPEDAT);
468 	__raw_writel(0x0000f81f, S3C2410_GPEUP);
469 
470 	/* GPF0  input 0=power button pressed
471 	 * GPF1  input SD/MMC switch 0=card present
472 	 * GPF2  N30 1=reset button pressed (inverted compared to the rest)
473 	 *	 N35/PiN 0=reset button pressed
474 	 * GPF3  N30/PiN input -- unknown function
475 	 *       N35 input GPS antenna position, 0=antenna closed, 1=open
476 	 * GPF4  input 0=button 4 pressed
477 	 * GPF5  input 0=button 3 pressed
478 	 * GPF6  input 0=button 2 pressed
479 	 * GPF7  input 0=button 1 pressed
480 	 */
481 	__raw_writel(0x0000aaaa, S3C2410_GPFCON);
482 	__raw_writel(0x00000000, S3C2410_GPFDAT);
483 	__raw_writel(0x000000ff, S3C2410_GPFUP);
484 
485 	/* GPG0  input RS232 DCD/DSR/RI
486 	 * GPG1  input 1=USB gadget port has power from a host
487 	 * GPG2  N30 input -- unknown function
488 	 *       N35/PiN input 0=headphones plugged in, 1=not plugged in
489 	 * GPG3  N30 output -- unknown function
490 	 *       N35/PiN input with unknown function
491 	 * GPG4  N30 output 0=MMC enabled, 1=MMC disabled
492 	 * GPG5  N30 output 0=BlueTooth chip disabled, 1=enabled
493 	 *       N35/PiN input joystick right
494 	 * GPG6  N30 output 0=blue led on, 1=off
495 	 *       N35/PiN input joystick left
496 	 * GPG7  input 0=thumbwheel pressed
497 	 * GPG8  input 0=thumbwheel down
498 	 * GPG9  input 0=thumbwheel up
499 	 * GPG10 input SD/MMC write protect switch
500 	 * GPG11 N30 input -- unknown function
501 	 *       N35 output 0=GPS antenna powered, 1=not powered
502 	 *       PiN output -- unknown function
503 	 * GPG12-15 touch screen functions
504 	 *
505 	 * The pullups differ between the models, so enable all
506 	 * pullups that are enabled on any of the models.
507 	 */
508 	if (machine_is_n30())
509 		__raw_writel(0xff0a956a, S3C2410_GPGCON);
510 	if (machine_is_n35())
511 		__raw_writel(0xff4aa92a, S3C2410_GPGCON);
512 	__raw_writel(0x0000e800, S3C2410_GPGDAT);
513 	__raw_writel(0x0000f86f, S3C2410_GPGUP);
514 
515 	/* GPH0/1/2/3 RS232 serial port
516 	 * GPH4/5 IrDA serial port
517 	 * GPH6/7  N30 BlueTooth serial port
518 	 *         N35/PiN GPS receiver
519 	 * GPH8 input -- unknown function
520 	 * GPH9 CLKOUT0 HCLK -- unknown use
521 	 * GPH10 CLKOUT1 FCLK -- unknown use
522 	 *
523 	 * The pull ups for H6/H7 are enabled on N30 but not on the
524 	 * N35/PiN.  I suppose is useful for a budget model of the N30
525 	 * with no bluetooth.  It doesn't hurt to have the pull ups
526 	 * enabled on the N35, so leave them enabled for all models.
527 	 */
528 	__raw_writel(0x0028aaaa, S3C2410_GPHCON);
529 	__raw_writel(0x000005ef, S3C2410_GPHDAT);
530 	__raw_writel(0x0000063f, S3C2410_GPHUP);
531 }
532 
n30_map_io(void)533 static void __init n30_map_io(void)
534 {
535 	s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
536 	n30_hwinit();
537 	s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
538 	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
539 }
540 
n30_init_time(void)541 static void __init n30_init_time(void)
542 {
543 	s3c2410_init_clocks(12000000);
544 	samsung_timer_init();
545 }
546 
547 /* GPB3 is the line that controls the pull-up for the USB D+ line */
548 
n30_init(void)549 static void __init n30_init(void)
550 {
551 	WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power"));
552 
553 	s3c24xx_fb_set_platdata(&n30_fb_info);
554 	s3c24xx_udc_set_platdata(&n30_udc_cfg);
555 	s3c24xx_mci_set_platdata(&n30_mci_cfg);
556 	s3c_i2c0_set_platdata(&n30_i2ccfg);
557 
558 	/* Turn off suspend on both USB ports, and switch the
559 	 * selectable USB port to USB device mode. */
560 
561 	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
562 			      S3C2410_MISCCR_USBSUSPND0 |
563 			      S3C2410_MISCCR_USBSUSPND1, 0x0);
564 
565 	if (machine_is_n30()) {
566 		/* Turn off suspend on both USB ports, and switch the
567 		 * selectable USB port to USB device mode. */
568 		s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
569 				      S3C2410_MISCCR_USBSUSPND0 |
570 				      S3C2410_MISCCR_USBSUSPND1, 0x0);
571 
572 		platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
573 	}
574 
575 	if (machine_is_n35()) {
576 		/* Turn off suspend and switch the selectable USB port
577 		 * to USB device mode.  Turn on suspend for the host
578 		 * port since it is not connected on the N35.
579 		 *
580 		 * Actually, the host port is available at some pads
581 		 * on the back of the device, so it would actually be
582 		 * possible to add a USB device inside the N35 if you
583 		 * are willing to do some hardware modifications. */
584 		s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
585 				      S3C2410_MISCCR_USBSUSPND0 |
586 				      S3C2410_MISCCR_USBSUSPND1,
587 				      S3C2410_MISCCR_USBSUSPND0);
588 
589 		platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices));
590 	}
591 }
592 
593 MACHINE_START(N30, "Acer-N30")
594 	/* Maintainer: Christer Weinigel <christer@weinigel.se>,
595 				Ben Dooks <ben-linux@fluff.org>
596 	*/
597 	.atag_offset	= 0x100,
598 	.init_time	= n30_init_time,
599 	.init_machine	= n30_init,
600 	.init_irq	= s3c2410_init_irq,
601 	.map_io		= n30_map_io,
602 MACHINE_END
603 
604 MACHINE_START(N35, "Acer-N35")
605 	/* Maintainer: Christer Weinigel <christer@weinigel.se>
606 	*/
607 	.atag_offset	= 0x100,
608 	.init_time	= n30_init_time,
609 	.init_machine	= n30_init,
610 	.init_irq	= s3c2410_init_irq,
611 	.map_io		= n30_map_io,
612 MACHINE_END
613