diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-da9052.c | 21 | ||||
-rw-r--r-- | drivers/gpio/gpio-ml-ioh.c | 32 | ||||
-rw-r--r-- | drivers/gpio/gpio-mpc8xxx.c | 18 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 136 |
5 files changed, 95 insertions, 113 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4e04157a3683..8a77b0a937a5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -138,6 +138,7 @@ config GPIO_MXS config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA + select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 58ac3777f0c4..56dd047d5844 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -22,7 +22,6 @@ #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> #include <linux/mfd/da9052/pdata.h> -#include <linux/mfd/da9052/gpio.h> #define DA9052_INPUT 1 #define DA9052_OUTPUT_OPENDRAIN 2 @@ -43,6 +42,9 @@ #define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0 #define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F #define DA9052_GPIO_NIBBLE_SHIFT 4 +#define DA9052_IRQ_GPI0 16 +#define DA9052_GPIO_ODD_SHIFT 7 +#define DA9052_GPIO_EVEN_SHIFT 3 struct da9052_gpio { struct da9052 *da9052; @@ -104,33 +106,26 @@ static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset) static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { struct da9052_gpio *gpio = to_da9052_gpio(gc); - unsigned char register_value = 0; int ret; if (da9052_gpio_port_odd(offset)) { - if (value) { - register_value = DA9052_GPIO_ODD_PORT_MODE; ret = da9052_reg_update(gpio->da9052, (offset >> 1) + DA9052_GPIO_0_1_REG, DA9052_GPIO_ODD_PORT_MODE, - register_value); + value << DA9052_GPIO_ODD_SHIFT); if (ret != 0) dev_err(gpio->da9052->dev, "Failed to updated gpio odd reg,%d", ret); - } } else { - if (value) { - register_value = DA9052_GPIO_EVEN_PORT_MODE; ret = da9052_reg_update(gpio->da9052, (offset >> 1) + DA9052_GPIO_0_1_REG, DA9052_GPIO_EVEN_PORT_MODE, - register_value); + value << DA9052_GPIO_EVEN_SHIFT); if (ret != 0) dev_err(gpio->da9052->dev, "Failed to updated gpio even reg,%d", ret); - } } } @@ -201,9 +196,9 @@ static struct gpio_chip reference_gp __devinitdata = { .direction_input = da9052_gpio_direction_input, .direction_output = da9052_gpio_direction_output, .to_irq = da9052_gpio_to_irq, - .can_sleep = 1; - .ngpio = 16; - .base = -1; + .can_sleep = 1, + .ngpio = 16, + .base = -1, }; static int __devinit da9052_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index ea8e73869250..461958fc2264 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -332,6 +332,34 @@ static void ioh_irq_mask(struct irq_data *d) &chip->reg->regs[chip->ch].imask); } +static void ioh_irq_disable(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + unsigned long flags; + u32 ien; + + spin_lock_irqsave(&chip->spinlock, flags); + ien = ioread32(&chip->reg->regs[chip->ch].ien); + ien &= ~(1 << (d->irq - chip->irq_base)); + iowrite32(ien, &chip->reg->regs[chip->ch].ien); + spin_unlock_irqrestore(&chip->spinlock, flags); +} + +static void ioh_irq_enable(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + unsigned long flags; + u32 ien; + + spin_lock_irqsave(&chip->spinlock, flags); + ien = ioread32(&chip->reg->regs[chip->ch].ien); + ien |= 1 << (d->irq - chip->irq_base); + iowrite32(ien, &chip->reg->regs[chip->ch].ien); + spin_unlock_irqrestore(&chip->spinlock, flags); +} + static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) { struct ioh_gpio *chip = dev_id; @@ -339,7 +367,7 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) int i, j; int ret = IRQ_NONE; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++, chip++) { reg_val = ioread32(&chip->reg->regs[i].istatus); for (j = 0; j < num_ports[i]; j++) { if (reg_val & BIT(j)) { @@ -370,6 +398,8 @@ static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, ct->chip.irq_mask = ioh_irq_mask; ct->chip.irq_unmask = ioh_irq_unmask; ct->chip.irq_set_type = ioh_irq_type; + ct->chip.irq_disable = ioh_irq_disable; + ct->chip.irq_enable = ioh_irq_enable; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index ec3fcf0a7e12..5cd04b65c556 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -132,6 +132,15 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return 0; } +static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + /* GPIO 28..31 are input only on MPC5121 */ + if (gpio >= 28) + return -EINVAL; + + return mpc8xxx_gpio_dir_out(gc, gpio, val); +} + static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -340,11 +349,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np) mm_gc->save_regs = mpc8xxx_gpio_save_regs; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = mpc8xxx_gpio_dir_out; - if (of_device_is_compatible(np, "fsl,mpc8572-gpio")) - gc->get = mpc8572_gpio_get; - else - gc->get = mpc8xxx_gpio_get; + gc->direction_output = of_device_is_compatible(np, "fsl,mpc5121-gpio") ? + mpc5121_gpio_dir_out : mpc8xxx_gpio_dir_out; + gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ? + mpc8572_gpio_get : mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; gc->to_irq = mpc8xxx_gpio_to_irq; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 42a5d5672694..2f399ec7bd66 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -12,7 +12,6 @@ #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/module.h> -#include <linux/list.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> @@ -24,6 +23,7 @@ #include <linux/amba/pl061.h> #include <linux/slab.h> #include <linux/pm.h> +#include <asm/mach/irq.h> #define GPIODIR 0x400 #define GPIOIS 0x404 @@ -48,23 +48,16 @@ struct pl061_context_save_regs { #endif struct pl061_gpio { - /* We use a list of pl061_gpio structs for each trigger IRQ in the main - * interrupts controller of the system. We need this to support systems - * in which more that one PL061s are connected to the same IRQ. The ISR - * interates through this list to find the source of the interrupt. - */ - struct list_head list; - /* Each of the two spinlocks protects a different set of hardware * regiters and data structurs. This decouples the code of the IRQ from * the GPIO code. This also makes the case of a GPIO routine call from * the IRQ code simpler. */ spinlock_t lock; /* GPIO registers */ - spinlock_t irq_lock; /* IRQ registers */ void __iomem *base; - unsigned irq_base; + int irq_base; + struct irq_chip_generic *irq_gc; struct gpio_chip gc; #ifdef CONFIG_PM @@ -134,46 +127,16 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return -EINVAL; return chip->irq_base + offset; } -/* - * PL061 GPIO IRQ - */ -static void pl061_irq_disable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie &= ~(1 << offset); - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - -static void pl061_irq_enable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie |= 1 << offset; - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = gc->private; int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -181,7 +144,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; - spin_lock_irqsave(&chip->irq_lock, flags); + raw_spin_lock_irqsave(&gc->lock, flags); gpioiev = readb(chip->base + GPIOIEV); @@ -210,53 +173,54 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) writeb(gpioiev, chip->base + GPIOIEV); - spin_unlock_irqrestore(&chip->irq_lock, flags); + raw_spin_unlock_irqrestore(&gc->lock, flags); return 0; } -static struct irq_chip pl061_irqchip = { - .name = "GPIO", - .irq_enable = pl061_irq_enable, - .irq_disable = pl061_irq_disable, - .irq_set_type = pl061_irq_type, -}; - static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { - struct list_head *chip_list = irq_get_handler_data(irq); - struct list_head *ptr; - struct pl061_gpio *chip; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - list_for_each(ptr, chip_list) { - unsigned long pending; - int offset; - - chip = list_entry(ptr, struct pl061_gpio, list); - pending = readb(chip->base + GPIOMIS); - writeb(pending, chip->base + GPIOIC); + unsigned long pending; + int offset; + struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); - if (pending == 0) - continue; + chained_irq_enter(irqchip, desc); + pending = readb(chip->base + GPIOMIS); + writeb(pending, chip->base + GPIOIC); + if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + + chained_irq_exit(irqchip, desc); +} + +static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) +{ + struct irq_chip_type *ct; + + chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base, + chip->base, handle_simple_irq); + chip->irq_gc->private = chip; + + ct = chip->irq_gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_type = pl061_irq_type; + ct->chip.irq_set_wake = irq_gc_set_wake; + ct->regs.mask = GPIOIE; + + irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR), + IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } static int pl061_probe(struct amba_device *dev, const struct amba_id *id) { struct pl061_platform_data *pdata; struct pl061_gpio *chip; - struct list_head *chip_list; int ret, irq, i; - static DECLARE_BITMAP(init_irq, NR_IRQS); - - pdata = dev->dev.platform_data; - if (pdata == NULL) - return -ENODEV; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -268,7 +232,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->irq_base = pdata->irq_base; } else if (dev->dev.of_node) { chip->gc.base = -1; - chip->irq_base = NO_IRQ; + chip->irq_base = 0; } else { ret = -ENODEV; goto free_mem; @@ -287,8 +251,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } spin_lock_init(&chip->lock); - spin_lock_init(&chip->irq_lock); - INIT_LIST_HEAD(&chip->list); chip->gc.direction_input = pl061_direction_input; chip->gc.direction_output = pl061_direction_output; @@ -308,9 +270,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) * irq_chip support */ - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return 0; + pl061_init_gc(chip, chip->irq_base); + writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = dev->irq[0]; if (irq < 0) { @@ -318,18 +282,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) goto iounmap; } irq_set_chained_handler(irq, pl061_irq_handler); - if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ - chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); - if (chip_list == NULL) { - clear_bit(irq, init_irq); - ret = -ENOMEM; - goto iounmap; - } - INIT_LIST_HEAD(chip_list); - irq_set_handler_data(irq, chip_list); - } else - chip_list = irq_get_handler_data(irq); - list_add(&chip->list, chip_list); + irq_set_handler_data(irq, chip); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { @@ -339,11 +292,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) else pl061_direction_input(&chip->gc, i); } - - irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, - handle_simple_irq); - set_irq_flags(i+chip->irq_base, IRQF_VALID); - irq_set_chip_data(i + chip->irq_base, chip); } amba_set_drvdata(dev, chip); |