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 56static struct map_desc n30_iodesc[] __initdata = { 57 /* nothing here yet */ 58}; 59 60static 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 89static 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 95static 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 146static struct gpio_keys_platform_data n30_button_data = { 147 .buttons = n30_buttons, 148 .nbuttons = ARRAY_SIZE(n30_buttons), 149}; 150 151static struct platform_device n30_button_device = { 152 .name = "gpio-keys", 153 .id = -1, 154 .dev = { 155 .platform_data = &n30_button_data, 156 } 157}; 158 159static 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 236static struct gpio_keys_platform_data n35_button_data = { 237 .buttons = n35_buttons, 238 .nbuttons = ARRAY_SIZE(n35_buttons), 239}; 240 241static 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. */ 251static 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. */ 259static 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. */ 269static 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 276static 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 283static 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 291static 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 299static 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 307static 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 315static 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 334static 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 341static 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 355static 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 362static 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 376static 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 389static 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. */ 397static 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 bluetooh. 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 533static 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 541static 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 549static 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 593MACHINE_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, 602MACHINE_END 603 604MACHINE_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, 612MACHINE_END 613