linux/arch/arm/mach-sa1100/h3xxx.c
<<
>>
Prefs
   1/*
   2 * Support for Compaq iPAQ H3100 and H3600 handheld computers (common code)
   3 *
   4 * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
   5 * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/gpio.h>
  15#include <linux/gpio_keys.h>
  16#include <linux/input.h>
  17#include <linux/mfd/htc-egpio.h>
  18#include <linux/mtd/mtd.h>
  19#include <linux/mtd/partitions.h>
  20#include <linux/platform_data/sa11x0-serial.h>
  21#include <linux/platform_device.h>
  22#include <linux/serial_core.h>
  23
  24#include <asm/mach/flash.h>
  25#include <asm/mach/map.h>
  26
  27#include <mach/h3xxx.h>
  28#include <mach/irqs.h>
  29
  30#include "generic.h"
  31
  32/*
  33 * H3xxx flash support
  34 */
  35static struct mtd_partition h3xxx_partitions[] = {
  36        {
  37                .name           = "H3XXX boot firmware",
  38                .size           = 0x00040000,
  39                .offset         = 0,
  40                .mask_flags     = MTD_WRITEABLE,  /* force read-only */
  41        }, {
  42                .name           = "H3XXX rootfs",
  43                .size           = MTDPART_SIZ_FULL,
  44                .offset         = 0x00040000,
  45        }
  46};
  47
  48static void h3xxx_set_vpp(int vpp)
  49{
  50        gpio_set_value(H3XXX_EGPIO_VPP_ON, vpp);
  51}
  52
  53static int h3xxx_flash_init(void)
  54{
  55        int err = gpio_request(H3XXX_EGPIO_VPP_ON, "Flash Vpp");
  56        if (err) {
  57                pr_err("%s: can't request H3XXX_EGPIO_VPP_ON\n", __func__);
  58                return err;
  59        }
  60
  61        err = gpio_direction_output(H3XXX_EGPIO_VPP_ON, 0);
  62        if (err)
  63                gpio_free(H3XXX_EGPIO_VPP_ON);
  64
  65        return err;
  66}
  67
  68static void h3xxx_flash_exit(void)
  69{
  70        gpio_free(H3XXX_EGPIO_VPP_ON);
  71}
  72
  73static struct flash_platform_data h3xxx_flash_data = {
  74        .map_name       = "cfi_probe",
  75        .set_vpp        = h3xxx_set_vpp,
  76        .init           = h3xxx_flash_init,
  77        .exit           = h3xxx_flash_exit,
  78        .parts          = h3xxx_partitions,
  79        .nr_parts       = ARRAY_SIZE(h3xxx_partitions),
  80};
  81
  82static struct resource h3xxx_flash_resource =
  83        DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
  84
  85
  86/*
  87 * H3xxx uart support
  88 */
  89static struct gpio h3xxx_uart_gpio[] = {
  90        { H3XXX_GPIO_COM_DCD,   GPIOF_IN,               "COM DCD" },
  91        { H3XXX_GPIO_COM_CTS,   GPIOF_IN,               "COM CTS" },
  92        { H3XXX_GPIO_COM_RTS,   GPIOF_OUT_INIT_LOW,     "COM RTS" },
  93};
  94
  95static bool h3xxx_uart_request_gpios(void)
  96{
  97        static bool h3xxx_uart_gpio_ok;
  98        int rc;
  99
 100        if (h3xxx_uart_gpio_ok)
 101                return true;
 102
 103        rc = gpio_request_array(h3xxx_uart_gpio, ARRAY_SIZE(h3xxx_uart_gpio));
 104        if (rc)
 105                pr_err("h3xxx_uart_request_gpios: error %d\n", rc);
 106        else
 107                h3xxx_uart_gpio_ok = true;
 108
 109        return h3xxx_uart_gpio_ok;
 110}
 111
 112static void h3xxx_uart_set_mctrl(struct uart_port *port, u_int mctrl)
 113{
 114        if (port->mapbase == _Ser3UTCR0) {
 115                if (!h3xxx_uart_request_gpios())
 116                        return;
 117                gpio_set_value(H3XXX_GPIO_COM_RTS, !(mctrl & TIOCM_RTS));
 118        }
 119}
 120
 121static u_int h3xxx_uart_get_mctrl(struct uart_port *port)
 122{
 123        u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
 124
 125        if (port->mapbase == _Ser3UTCR0) {
 126                if (!h3xxx_uart_request_gpios())
 127                        return ret;
 128                /*
 129                 * DCD and CTS bits are inverted in GPLR by RS232 transceiver
 130                 */
 131                if (gpio_get_value(H3XXX_GPIO_COM_DCD))
 132                        ret &= ~TIOCM_CD;
 133                if (gpio_get_value(H3XXX_GPIO_COM_CTS))
 134                        ret &= ~TIOCM_CTS;
 135        }
 136
 137        return ret;
 138}
 139
 140static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 141{
 142        if (port->mapbase == _Ser3UTCR0) {
 143                if (!gpio_request(H3XXX_EGPIO_RS232_ON, "RS232 transceiver")) {
 144                        gpio_direction_output(H3XXX_EGPIO_RS232_ON, !state);
 145                        gpio_free(H3XXX_EGPIO_RS232_ON);
 146                } else {
 147                        pr_err("%s: can't request H3XXX_EGPIO_RS232_ON\n",
 148                                __func__);
 149                }
 150        }
 151}
 152
 153/*
 154 * Enable/Disable wake up events for this serial port.
 155 * Obviously, we only support this on the normal COM port.
 156 */
 157static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable)
 158{
 159        int err = -EINVAL;
 160
 161        if (port->mapbase == _Ser3UTCR0) {
 162                if (enable)
 163                        PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
 164                else
 165                        PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
 166                err = 0;
 167        }
 168        return err;
 169}
 170
 171static struct sa1100_port_fns h3xxx_port_fns __initdata = {
 172        .set_mctrl      = h3xxx_uart_set_mctrl,
 173        .get_mctrl      = h3xxx_uart_get_mctrl,
 174        .pm             = h3xxx_uart_pm,
 175        .set_wake       = h3xxx_uart_set_wake,
 176};
 177
 178/*
 179 * EGPIO
 180 */
 181
 182static struct resource egpio_resources[] = {
 183        [0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
 184};
 185
 186static struct htc_egpio_chip egpio_chips[] = {
 187        [0] = {
 188                .reg_start      = 0,
 189                .gpio_base      = H3XXX_EGPIO_BASE,
 190                .num_gpios      = 16,
 191                .direction      = HTC_EGPIO_OUTPUT,
 192                .initial_values = 0x0080, /* H3XXX_EGPIO_RS232_ON */
 193        },
 194};
 195
 196static struct htc_egpio_platform_data egpio_info = {
 197        .reg_width      = 16,
 198        .bus_width      = 16,
 199        .chip           = egpio_chips,
 200        .num_chips      = ARRAY_SIZE(egpio_chips),
 201};
 202
 203static struct platform_device h3xxx_egpio = {
 204        .name           = "htc-egpio",
 205        .id             = -1,
 206        .resource       = egpio_resources,
 207        .num_resources  = ARRAY_SIZE(egpio_resources),
 208        .dev            = {
 209                .platform_data = &egpio_info,
 210        },
 211};
 212
 213/*
 214 * GPIO keys
 215 */
 216
 217static struct gpio_keys_button h3xxx_button_table[] = {
 218        {
 219                .code           = KEY_POWER,
 220                .gpio           = H3XXX_GPIO_PWR_BUTTON,
 221                .desc           = "Power Button",
 222                .active_low     = 1,
 223                .type           = EV_KEY,
 224                .wakeup         = 1,
 225        }, {
 226                .code           = KEY_ENTER,
 227                .gpio           = H3XXX_GPIO_ACTION_BUTTON,
 228                .active_low     = 1,
 229                .desc           = "Action button",
 230                .type           = EV_KEY,
 231                .wakeup         = 0,
 232        },
 233};
 234
 235static struct gpio_keys_platform_data h3xxx_keys_data = {
 236        .buttons  = h3xxx_button_table,
 237        .nbuttons = ARRAY_SIZE(h3xxx_button_table),
 238};
 239
 240static struct platform_device h3xxx_keys = {
 241        .name   = "gpio-keys",
 242        .id     = -1,
 243        .dev    = {
 244                .platform_data = &h3xxx_keys_data,
 245        },
 246};
 247
 248static struct resource h3xxx_micro_resources[] = {
 249        DEFINE_RES_MEM(0x80010000, SZ_4K),
 250        DEFINE_RES_MEM(0x80020000, SZ_4K),
 251        DEFINE_RES_IRQ(IRQ_Ser1UART),
 252};
 253
 254struct platform_device h3xxx_micro_asic = {
 255        .name = "ipaq-h3xxx-micro",
 256        .id = -1,
 257        .resource = h3xxx_micro_resources,
 258        .num_resources = ARRAY_SIZE(h3xxx_micro_resources),
 259};
 260
 261static struct platform_device *h3xxx_devices[] = {
 262        &h3xxx_egpio,
 263        &h3xxx_keys,
 264        &h3xxx_micro_asic,
 265};
 266
 267void __init h3xxx_mach_init(void)
 268{
 269        sa1100_register_uart_fns(&h3xxx_port_fns);
 270        sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
 271        platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices));
 272}
 273
 274static struct map_desc h3600_io_desc[] __initdata = {
 275        {       /* static memory bank 2  CS#2 */
 276                .virtual        =  H3600_BANK_2_VIRT,
 277                .pfn            = __phys_to_pfn(SA1100_CS2_PHYS),
 278                .length         = 0x02800000,
 279                .type           = MT_DEVICE
 280        }, {    /* static memory bank 4  CS#4 */
 281                .virtual        =  H3600_BANK_4_VIRT,
 282                .pfn            = __phys_to_pfn(SA1100_CS4_PHYS),
 283                .length         = 0x00800000,
 284                .type           = MT_DEVICE
 285        }, {    /* EGPIO 0              CS#5 */
 286                .virtual        =  H3600_EGPIO_VIRT,
 287                .pfn            = __phys_to_pfn(H3600_EGPIO_PHYS),
 288                .length         = 0x01000000,
 289                .type           = MT_DEVICE
 290        }
 291};
 292
 293/*
 294 * Common map_io initialization
 295 */
 296
 297void __init h3xxx_map_io(void)
 298{
 299        sa1100_map_io();
 300        iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
 301
 302        sa1100_register_uart(0, 3); /* Common serial port */
 303//      sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
 304
 305        /* Ensure those pins are outputs and driving low  */
 306        PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
 307        PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
 308
 309        /* Configure suspend conditions */
 310        PGSR = 0;
 311        PCFR = PCFR_OPDE;
 312        PSDR = 0;
 313
 314        GPCR = 0x0fffffff;      /* All outputs are set low by default */
 315        GPDR = 0;               /* Configure all GPIOs as input */
 316}
 317
 318