From c334aa8da6e17555823ebf05bdb429ff224e99b3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 9 Jan 2014 16:05:20 +0000 Subject: [PATCH 154/174] gpio: support low and high level interrupts --- arch/arm/mach-bcm2708/bcm2708_gpio.c | 52 +++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) --- a/arch/arm/mach-bcm2708/bcm2708_gpio.c +++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c @@ -58,6 +58,8 @@ struct bcm2708_gpio { struct gpio_chip gc; unsigned long rising; unsigned long falling; + unsigned long high; + unsigned long low; }; static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset, @@ -145,20 +147,22 @@ static int bcm2708_gpio_irq_set_type(str unsigned irq = d->irq; struct bcm2708_gpio *gpio = irq_get_chip_data(irq); - if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + gpio->rising &= ~(1 << __bcm2708_irq_to_gpio(irq)); + gpio->falling &= ~(1 << __bcm2708_irq_to_gpio(irq)); + gpio->high &= ~(1 << __bcm2708_irq_to_gpio(irq)); + gpio->low &= ~(1 << __bcm2708_irq_to_gpio(irq)); + + if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) return -EINVAL; - if (type & IRQ_TYPE_EDGE_RISING) { + if (type & IRQ_TYPE_EDGE_RISING) gpio->rising |= (1 << __bcm2708_irq_to_gpio(irq)); - } else { - gpio->rising &= ~(1 << __bcm2708_irq_to_gpio(irq)); - } - - if (type & IRQ_TYPE_EDGE_FALLING) { + if (type & IRQ_TYPE_EDGE_FALLING) gpio->falling |= (1 << __bcm2708_irq_to_gpio(irq)); - } else { - gpio->falling &= ~(1 << __bcm2708_irq_to_gpio(irq)); - } + if (type & IRQ_TYPE_LEVEL_HIGH) + gpio->high |= (1 << __bcm2708_irq_to_gpio(irq)); + if (type & IRQ_TYPE_LEVEL_LOW) + gpio->low |= (1 << __bcm2708_irq_to_gpio(irq)); return 0; } @@ -168,13 +172,17 @@ static void bcm2708_gpio_irq_mask(struct struct bcm2708_gpio *gpio = irq_get_chip_data(irq); unsigned gn = __bcm2708_irq_to_gpio(irq); unsigned gb = gn / 32; - unsigned long rising = readl(gpio->base + GPIOREN(gb)); + unsigned long rising = readl(gpio->base + GPIOREN(gb)); unsigned long falling = readl(gpio->base + GPIOFEN(gb)); + unsigned long high = readl(gpio->base + GPIOHEN(gb)); + unsigned long low = readl(gpio->base + GPIOLEN(gb)); gn = gn % 32; - writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); + writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); + writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); + writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); } static void bcm2708_gpio_irq_unmask(struct irq_data *d) @@ -183,24 +191,38 @@ static void bcm2708_gpio_irq_unmask(stru struct bcm2708_gpio *gpio = irq_get_chip_data(irq); unsigned gn = __bcm2708_irq_to_gpio(irq); unsigned gb = gn / 32; - unsigned long rising = readl(gpio->base + GPIOREN(gb)); + unsigned long rising = readl(gpio->base + GPIOREN(gb)); unsigned long falling = readl(gpio->base + GPIOFEN(gb)); + unsigned long high = readl(gpio->base + GPIOHEN(gb)); + unsigned long low = readl(gpio->base + GPIOLEN(gb)); gn = gn % 32; writel(1 << gn, gpio->base + GPIOEDS(gb)); if (gpio->rising & (1 << gn)) { - writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); + writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); } else { writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); } if (gpio->falling & (1 << gn)) { - writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); + writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); } else { writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); } + + if (gpio->high & (1 << gn)) { + writel(high | (1 << gn), gpio->base + GPIOHEN(gb)); + } else { + writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); + } + + if (gpio->low & (1 << gn)) { + writel(low | (1 << gn), gpio->base + GPIOLEN(gb)); + } else { + writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); + } } static struct irq_chip bcm2708_irqchip = {