linux/arch/arm/mach-msm/board-trout-gpio.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-msm/gpio.c
   3 *
   4 * Copyright (C) 2005 HP Labs
   5 * Copyright (C) 2008 Google, Inc.
   6 * Copyright (C) 2009 Pavel Machek <pavel@ucw.cz>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/io.h>
  17#include <linux/irq.h>
  18#include <linux/interrupt.h>
  19#include <linux/gpio.h>
  20
  21#include "board-trout.h"
  22
  23static uint8_t trout_int_mask[2] = {
  24        [0] = 0xff, /* mask all interrupts */
  25        [1] = 0xff,
  26};
  27static uint8_t trout_sleep_int_mask[] = {
  28        [0] = 0xff,
  29        [1] = 0xff,
  30};
  31
  32struct msm_gpio_chip {
  33        struct gpio_chip        chip;
  34        void __iomem            *reg;   /* Base of register bank */
  35        u8                      shadow;
  36};
  37
  38#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
  39
  40static int msm_gpiolib_get(struct gpio_chip *chip, unsigned offset)
  41{
  42        struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
  43        unsigned mask = 1 << offset;
  44
  45        return !!(readb(msm_gpio->reg) & mask);
  46}
  47
  48static void msm_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
  49{
  50        struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
  51        unsigned mask = 1 << offset;
  52
  53        if (val)
  54                msm_gpio->shadow |= mask;
  55        else
  56                msm_gpio->shadow &= ~mask;
  57
  58        writeb(msm_gpio->shadow, msm_gpio->reg);
  59}
  60
  61static int msm_gpiolib_direction_input(struct gpio_chip *chip,
  62                                        unsigned offset)
  63{
  64        msm_gpiolib_set(chip, offset, 0);
  65        return 0;
  66}
  67
  68static int msm_gpiolib_direction_output(struct gpio_chip *chip,
  69                                         unsigned offset, int val)
  70{
  71        msm_gpiolib_set(chip, offset, val);
  72        return 0;
  73}
  74
  75static int trout_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  76{
  77        return TROUT_GPIO_TO_INT(offset + chip->base);
  78}
  79
  80#define TROUT_GPIO_BANK(name, reg_num, base_gpio, shadow_val)           \
  81        {                                                               \
  82                .chip = {                                               \
  83                        .label            = name,                       \
  84                        .direction_input  = msm_gpiolib_direction_input,\
  85                        .direction_output = msm_gpiolib_direction_output, \
  86                        .get              = msm_gpiolib_get,            \
  87                        .set              = msm_gpiolib_set,            \
  88                        .to_irq           = trout_gpio_to_irq,          \
  89                        .base             = base_gpio,                  \
  90                        .ngpio            = 8,                          \
  91                },                                                      \
  92                .reg = (void *) reg_num + TROUT_CPLD_BASE,              \
  93                .shadow = shadow_val,                                   \
  94        }
  95
  96static struct msm_gpio_chip msm_gpio_banks[] = {
  97#if defined(CONFIG_MSM_DEBUG_UART1)
  98        /* H2W pins <-> UART1 */
  99        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x40),
 100#else
 101        /* H2W pins <-> UART3, Bluetooth <-> UART1 */
 102        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x80),
 103#endif
 104        /* I2C pull */
 105        TROUT_GPIO_BANK("MISC3", 0x02,   TROUT_GPIO_MISC3_BASE, 0x04),
 106        TROUT_GPIO_BANK("MISC4", 0x04,   TROUT_GPIO_MISC4_BASE, 0),
 107        /* mmdi 32k en */
 108        TROUT_GPIO_BANK("MISC5", 0x06,   TROUT_GPIO_MISC5_BASE, 0x04),
 109        TROUT_GPIO_BANK("INT2", 0x08,    TROUT_GPIO_INT2_BASE,  0),
 110        TROUT_GPIO_BANK("MISC1", 0x0a,   TROUT_GPIO_MISC1_BASE, 0),
 111        TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
 112};
 113
 114static void trout_gpio_irq_ack(struct irq_data *d)
 115{
 116        int bank = TROUT_INT_TO_BANK(d->irq);
 117        uint8_t mask = TROUT_INT_TO_MASK(d->irq);
 118        int reg = TROUT_BANK_TO_STAT_REG(bank);
 119        /*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", d->irq);*/
 120        writeb(mask, TROUT_CPLD_BASE + reg);
 121}
 122
 123static void trout_gpio_irq_mask(struct irq_data *d)
 124{
 125        unsigned long flags;
 126        uint8_t reg_val;
 127        int bank = TROUT_INT_TO_BANK(d->irq);
 128        uint8_t mask = TROUT_INT_TO_MASK(d->irq);
 129        int reg = TROUT_BANK_TO_MASK_REG(bank);
 130
 131        local_irq_save(flags);
 132        reg_val = trout_int_mask[bank] |= mask;
 133        /*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
 134               d->irq, bank, reg_val);*/
 135        writeb(reg_val, TROUT_CPLD_BASE + reg);
 136        local_irq_restore(flags);
 137}
 138
 139static void trout_gpio_irq_unmask(struct irq_data *d)
 140{
 141        unsigned long flags;
 142        uint8_t reg_val;
 143        int bank = TROUT_INT_TO_BANK(d->irq);
 144        uint8_t mask = TROUT_INT_TO_MASK(d->irq);
 145        int reg = TROUT_BANK_TO_MASK_REG(bank);
 146
 147        local_irq_save(flags);
 148        reg_val = trout_int_mask[bank] &= ~mask;
 149        /*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
 150               d->irq, bank, reg_val);*/
 151        writeb(reg_val, TROUT_CPLD_BASE + reg);
 152        local_irq_restore(flags);
 153}
 154
 155int trout_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 156{
 157        unsigned long flags;
 158        int bank = TROUT_INT_TO_BANK(d->irq);
 159        uint8_t mask = TROUT_INT_TO_MASK(d->irq);
 160
 161        local_irq_save(flags);
 162        if(on)
 163                trout_sleep_int_mask[bank] &= ~mask;
 164        else
 165                trout_sleep_int_mask[bank] |= mask;
 166        local_irq_restore(flags);
 167        return 0;
 168}
 169
 170static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 171{
 172        int j, m;
 173        unsigned v;
 174        int bank;
 175        int stat_reg;
 176        int int_base = TROUT_INT_START;
 177        uint8_t int_mask;
 178
 179        for (bank = 0; bank < 2; bank++) {
 180                stat_reg = TROUT_BANK_TO_STAT_REG(bank);
 181                v = readb(TROUT_CPLD_BASE + stat_reg);
 182                int_mask = trout_int_mask[bank];
 183                if (v & int_mask) {
 184                        writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
 185                        printk(KERN_ERR "trout_gpio_irq_handler: got masked "
 186                               "interrupt: %d:%02x\n", bank, v & int_mask);
 187                }
 188                v &= ~int_mask;
 189                while (v) {
 190                        m = v & -v;
 191                        j = fls(m) - 1;
 192                        /*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
 193                               "it %d irq %d\n", bank, v, m, j, int_base + j);*/
 194                        v &= ~m;
 195                        generic_handle_irq(int_base + j);
 196                }
 197                int_base += TROUT_INT_BANK0_COUNT;
 198        }
 199        desc->irq_data.chip->irq_ack(&desc->irq_data);
 200}
 201
 202static struct irq_chip trout_gpio_irq_chip = {
 203        .name          = "troutgpio",
 204        .irq_ack       = trout_gpio_irq_ack,
 205        .irq_mask      = trout_gpio_irq_mask,
 206        .irq_unmask    = trout_gpio_irq_unmask,
 207        .irq_set_wake  = trout_gpio_irq_set_wake,
 208};
 209
 210/*
 211 * Called from the processor-specific init to enable GPIO pin support.
 212 */
 213int __init trout_init_gpio(void)
 214{
 215        int i;
 216        for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
 217                irq_set_chip_and_handler(i, &trout_gpio_irq_chip,
 218                                         handle_edge_irq);
 219                set_irq_flags(i, IRQF_VALID);
 220        }
 221
 222        for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
 223                gpiochip_add(&msm_gpio_banks[i].chip);
 224
 225        irq_set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
 226        irq_set_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
 227        irq_set_irq_wake(MSM_GPIO_TO_INT(17), 1);
 228
 229        return 0;
 230}
 231
 232postcore_initcall(trout_init_gpio);
 233
 234