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