diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-06-17 12:52:15 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-17 12:56:49 +0200 |
commit | eadb8a091b27a840de7450f84ecff5ef13476424 (patch) | |
tree | 58c3782d40def63baa8167f3d31e3048cb4c7660 /arch/arm/plat-mxc/gpio.c | |
parent | 73874005cd8800440be4299bd095387fff4b90ac (diff) | |
parent | 65795efbd380a832ae508b04dba8f8e53f0b84d9 (diff) |
Merge branch 'linus' into tracing/hw-breakpoints
Conflicts:
arch/x86/Kconfig
arch/x86/kernel/traps.c
arch/x86/power/cpu.c
arch/x86/power/cpu_32.c
kernel/Makefile
Semantic conflict:
arch/x86/kernel/hw_breakpoint.c
Merge reason: Resolve the conflicts, move from put_cpu_no_sched() to
put_cpu() in arch/x86/kernel/hw_breakpoint.c.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/arm/plat-mxc/gpio.c')
-rw-r--r-- | arch/arm/plat-mxc/gpio.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 89e95798cc3..7506d963be4 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/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]); } |