linux/arch/arm/mach-s3c24xx/mach-n30.c
<<
>>
Prefs
   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 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
 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