From b8fdbbc2073968f993b9512f1ef11d8c033de8fd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Mar 2009 12:46:41 +0100 Subject: [PATCH] --- yaml --- r: 148982 b: refs/heads/master c: 910862ec092c156023b8a6e726e8c793da0a03f7 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/arch/arm/plat-mxc/gpio.c | 49 ++++++++++++++++++++- trunk/arch/arm/plat-mxc/include/mach/gpio.h | 1 + 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 02d0c01527c7..e9f25166f88d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: fde364742a1afec9e71e705e863d029295282fe5 +refs/heads/master: 910862ec092c156023b8a6e726e8c793da0a03f7 diff --git a/trunk/arch/arm/plat-mxc/gpio.c b/trunk/arch/arm/plat-mxc/gpio.c index 89e95798cc3b..7506d963be4b 100644 --- a/trunk/arch/arm/plat-mxc/gpio.c +++ b/trunk/arch/arm/plat-mxc/gpio.c @@ -64,6 +64,8 @@ static void gpio_unmask_irq(u32 irq) _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1); } +static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset); + static int gpio_set_irq_type(u32 irq, u32 type) { u32 gpio = irq_to_gpio(irq); @@ -72,6 +74,7 @@ static int gpio_set_irq_type(u32 irq, u32 type) int edge; void __iomem *reg = port->base; + port->both_edges &= ~(1 << (gpio & 31)); switch (type) { case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; @@ -79,13 +82,24 @@ static int gpio_set_irq_type(u32 irq, u32 type) case IRQ_TYPE_EDGE_FALLING: edge = GPIO_INT_FALL_EDGE; break; + case IRQ_TYPE_EDGE_BOTH: + val = mxc_gpio_get(&port->chip, gpio & 31); + if (val) { + edge = GPIO_INT_LOW_LEV; + pr_debug("mxc: set GPIO %d to low trigger\n", gpio); + } else { + edge = GPIO_INT_HIGH_LEV; + pr_debug("mxc: set GPIO %d to high trigger\n", gpio); + } + port->both_edges |= 1 << (gpio & 31); + break; case IRQ_TYPE_LEVEL_LOW: edge = GPIO_INT_LOW_LEV; break; case IRQ_TYPE_LEVEL_HIGH: edge = GPIO_INT_HIGH_LEV; break; - default: /* this includes IRQ_TYPE_EDGE_BOTH */ + default: return -EINVAL; } @@ -98,6 +112,34 @@ static int gpio_set_irq_type(u32 irq, u32 type) return 0; } +static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) +{ + void __iomem *reg = port->base; + u32 bit, val; + int edge; + + reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ + bit = gpio & 0xf; + val = __raw_readl(reg); + edge = (val >> (bit << 1)) & 3; + val &= ~(0x3 << (bit << 1)); + switch (edge) { + case GPIO_INT_HIGH_LEV: + edge = GPIO_INT_LOW_LEV; + pr_debug("mxc: switch GPIO %d to low trigger\n", gpio); + break; + case GPIO_INT_LOW_LEV: + edge = GPIO_INT_HIGH_LEV; + pr_debug("mxc: switch GPIO %d to high trigger\n", gpio); + break; + default: + pr_err("mxc: invalid configuration for GPIO %d: %x\n", + gpio, edge); + return; + } + __raw_writel(val | (edge << (bit << 1)), reg); +} + /* handle n interrupts in one status register */ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) { @@ -105,11 +147,16 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) gpio_irq_no = port->virtual_irq_start; for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) { + u32 gpio = irq_to_gpio(gpio_irq_no); if ((irq_stat & 1) == 0) continue; BUG_ON(!(irq_desc[gpio_irq_no].handle_irq)); + + if (port->both_edges & (1 << (gpio & 31))) + mxc_flip_edge(port, gpio); + irq_desc[gpio_irq_no].handle_irq(gpio_irq_no, &irq_desc[gpio_irq_no]); } diff --git a/trunk/arch/arm/plat-mxc/include/mach/gpio.h b/trunk/arch/arm/plat-mxc/include/mach/gpio.h index ea509f1090fb..894d2f87c856 100644 --- a/trunk/arch/arm/plat-mxc/include/mach/gpio.h +++ b/trunk/arch/arm/plat-mxc/include/mach/gpio.h @@ -35,6 +35,7 @@ struct mxc_gpio_port { int irq; int virtual_irq_start; struct gpio_chip chip; + u32 both_edges; }; int mxc_gpio_init(struct mxc_gpio_port*, int);