Path: blob/master/arch/arm/mach-msm/board-trout-gpio.c
10817 views
/*1* linux/arch/arm/mach-msm/gpio.c2*3* Copyright (C) 2005 HP Labs4* Copyright (C) 2008 Google, Inc.5* Copyright (C) 2009 Pavel Machek <[email protected]>6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License, or10* (at your option) any later version.11*/1213#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/io.h>16#include <linux/irq.h>17#include <linux/interrupt.h>18#include <linux/gpio.h>1920#include "board-trout.h"2122static uint8_t trout_int_mask[2] = {23[0] = 0xff, /* mask all interrupts */24[1] = 0xff,25};26static uint8_t trout_sleep_int_mask[] = {27[0] = 0xff,28[1] = 0xff,29};3031struct msm_gpio_chip {32struct gpio_chip chip;33void __iomem *reg; /* Base of register bank */34u8 shadow;35};3637#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)3839static int msm_gpiolib_get(struct gpio_chip *chip, unsigned offset)40{41struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);42unsigned mask = 1 << offset;4344return !!(readb(msm_gpio->reg) & mask);45}4647static void msm_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)48{49struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);50unsigned mask = 1 << offset;5152if (val)53msm_gpio->shadow |= mask;54else55msm_gpio->shadow &= ~mask;5657writeb(msm_gpio->shadow, msm_gpio->reg);58}5960static int msm_gpiolib_direction_input(struct gpio_chip *chip,61unsigned offset)62{63msm_gpiolib_set(chip, offset, 0);64return 0;65}6667static int msm_gpiolib_direction_output(struct gpio_chip *chip,68unsigned offset, int val)69{70msm_gpiolib_set(chip, offset, val);71return 0;72}7374static int trout_gpio_to_irq(struct gpio_chip *chip, unsigned offset)75{76return TROUT_GPIO_TO_INT(offset + chip->base);77}7879#define TROUT_GPIO_BANK(name, reg_num, base_gpio, shadow_val) \80{ \81.chip = { \82.label = name, \83.direction_input = msm_gpiolib_direction_input,\84.direction_output = msm_gpiolib_direction_output, \85.get = msm_gpiolib_get, \86.set = msm_gpiolib_set, \87.to_irq = trout_gpio_to_irq, \88.base = base_gpio, \89.ngpio = 8, \90}, \91.reg = (void *) reg_num + TROUT_CPLD_BASE, \92.shadow = shadow_val, \93}9495static struct msm_gpio_chip msm_gpio_banks[] = {96#if defined(CONFIG_MSM_DEBUG_UART1)97/* H2W pins <-> UART1 */98TROUT_GPIO_BANK("MISC2", 0x00, TROUT_GPIO_MISC2_BASE, 0x40),99#else100/* H2W pins <-> UART3, Bluetooth <-> UART1 */101TROUT_GPIO_BANK("MISC2", 0x00, TROUT_GPIO_MISC2_BASE, 0x80),102#endif103/* I2C pull */104TROUT_GPIO_BANK("MISC3", 0x02, TROUT_GPIO_MISC3_BASE, 0x04),105TROUT_GPIO_BANK("MISC4", 0x04, TROUT_GPIO_MISC4_BASE, 0),106/* mmdi 32k en */107TROUT_GPIO_BANK("MISC5", 0x06, TROUT_GPIO_MISC5_BASE, 0x04),108TROUT_GPIO_BANK("INT2", 0x08, TROUT_GPIO_INT2_BASE, 0),109TROUT_GPIO_BANK("MISC1", 0x0a, TROUT_GPIO_MISC1_BASE, 0),110TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),111};112113static void trout_gpio_irq_ack(struct irq_data *d)114{115int bank = TROUT_INT_TO_BANK(d->irq);116uint8_t mask = TROUT_INT_TO_MASK(d->irq);117int reg = TROUT_BANK_TO_STAT_REG(bank);118/*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", d->irq);*/119writeb(mask, TROUT_CPLD_BASE + reg);120}121122static void trout_gpio_irq_mask(struct irq_data *d)123{124unsigned long flags;125uint8_t reg_val;126int bank = TROUT_INT_TO_BANK(d->irq);127uint8_t mask = TROUT_INT_TO_MASK(d->irq);128int reg = TROUT_BANK_TO_MASK_REG(bank);129130local_irq_save(flags);131reg_val = trout_int_mask[bank] |= mask;132/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",133d->irq, bank, reg_val);*/134writeb(reg_val, TROUT_CPLD_BASE + reg);135local_irq_restore(flags);136}137138static void trout_gpio_irq_unmask(struct irq_data *d)139{140unsigned long flags;141uint8_t reg_val;142int bank = TROUT_INT_TO_BANK(d->irq);143uint8_t mask = TROUT_INT_TO_MASK(d->irq);144int reg = TROUT_BANK_TO_MASK_REG(bank);145146local_irq_save(flags);147reg_val = trout_int_mask[bank] &= ~mask;148/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",149d->irq, bank, reg_val);*/150writeb(reg_val, TROUT_CPLD_BASE + reg);151local_irq_restore(flags);152}153154int trout_gpio_irq_set_wake(struct irq_data *d, unsigned int on)155{156unsigned long flags;157int bank = TROUT_INT_TO_BANK(d->irq);158uint8_t mask = TROUT_INT_TO_MASK(d->irq);159160local_irq_save(flags);161if(on)162trout_sleep_int_mask[bank] &= ~mask;163else164trout_sleep_int_mask[bank] |= mask;165local_irq_restore(flags);166return 0;167}168169static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)170{171int j, m;172unsigned v;173int bank;174int stat_reg;175int int_base = TROUT_INT_START;176uint8_t int_mask;177178for (bank = 0; bank < 2; bank++) {179stat_reg = TROUT_BANK_TO_STAT_REG(bank);180v = readb(TROUT_CPLD_BASE + stat_reg);181int_mask = trout_int_mask[bank];182if (v & int_mask) {183writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);184printk(KERN_ERR "trout_gpio_irq_handler: got masked "185"interrupt: %d:%02x\n", bank, v & int_mask);186}187v &= ~int_mask;188while (v) {189m = v & -v;190j = fls(m) - 1;191/*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"192"it %d irq %d\n", bank, v, m, j, int_base + j);*/193v &= ~m;194generic_handle_irq(int_base + j);195}196int_base += TROUT_INT_BANK0_COUNT;197}198desc->irq_data.chip->irq_ack(&desc->irq_data);199}200201static struct irq_chip trout_gpio_irq_chip = {202.name = "troutgpio",203.irq_ack = trout_gpio_irq_ack,204.irq_mask = trout_gpio_irq_mask,205.irq_unmask = trout_gpio_irq_unmask,206.irq_set_wake = trout_gpio_irq_set_wake,207};208209/*210* Called from the processor-specific init to enable GPIO pin support.211*/212int __init trout_init_gpio(void)213{214int i;215for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {216irq_set_chip_and_handler(i, &trout_gpio_irq_chip,217handle_edge_irq);218set_irq_flags(i, IRQF_VALID);219}220221for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)222gpiochip_add(&msm_gpio_banks[i].chip);223224irq_set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);225irq_set_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);226irq_set_irq_wake(MSM_GPIO_TO_INT(17), 1);227228return 0;229}230231postcore_initcall(trout_init_gpio);232233234235