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