Commit 3c9a071d authored by Herbert Valerio Riedel's avatar Herbert Valerio Riedel Committed by Russell King

[ARM] 4670/1: ep93xx: implement IRQT_BOTHEDGE gpio irq sense type

Having a both-edge sensitive irq trigger type is required for the
generic gpio-keys input driver; alas the ep93xx does not support
both-edge gpio triggers in hardware, so this patch implements them by
switching edge polarity on each triggered interrupt.  This is the same
approach as taken by the Orion SoC both-edge gpio irq support
implementation.
Signed-off-by: default avatarHerbert Valerio Riedel <hvr@gnu.org>
Acked-by: default avatarLennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 7ca72253
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Core routines for Cirrus EP93xx chips. * Core routines for Cirrus EP93xx chips.
* *
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
* Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
* *
* Thanks go to Michael Burian and Ray Lehtiniemi for their key * Thanks go to Michael Burian and Ray Lehtiniemi for their key
* role in the ep93xx linux community. * role in the ep93xx linux community.
...@@ -315,12 +316,29 @@ static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -315,12 +316,29 @@ static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
desc_handle_irq(gpio_irq, irq_desc + gpio_irq); desc_handle_irq(gpio_irq, irq_desc + gpio_irq);
} }
static void ep93xx_gpio_irq_ack(unsigned int irq)
{
int line = irq_to_gpio(irq);
int port = line >> 3;
int port_mask = 1 << (line & 7);
if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
update_gpio_int_params(port);
}
__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
static void ep93xx_gpio_irq_mask_ack(unsigned int irq) static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
{ {
int line = irq_to_gpio(irq); int line = irq_to_gpio(irq);
int port = line >> 3; int port = line >> 3;
int port_mask = 1 << (line & 7); int port_mask = 1 << (line & 7);
if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE)
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
gpio_int_unmasked[port] &= ~port_mask; gpio_int_unmasked[port] &= ~port_mask;
update_gpio_int_params(port); update_gpio_int_params(port);
...@@ -353,31 +371,54 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq) ...@@ -353,31 +371,54 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq)
*/ */
static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
{ {
struct irq_desc *desc = irq_desc + irq;
const int gpio = irq_to_gpio(irq); const int gpio = irq_to_gpio(irq);
const int port = gpio >> 3; const int port = gpio >> 3;
const int port_mask = 1 << (gpio & 7); const int port_mask = 1 << (gpio & 7);
ep93xx_gpio_set_direction(gpio, GPIO_IN); ep93xx_gpio_set_direction(gpio, GPIO_IN);
if (type & IRQT_RISING) { switch (type) {
gpio_int_enabled[port] |= port_mask; case IRQT_RISING:
gpio_int_type1[port] |= port_mask; gpio_int_type1[port] |= port_mask;
gpio_int_type2[port] |= port_mask; gpio_int_type2[port] |= port_mask;
} else if (type & IRQT_FALLING) { desc->handle_irq = handle_edge_irq;
gpio_int_enabled[port] |= port_mask; break;
case IRQT_FALLING:
gpio_int_type1[port] |= port_mask; gpio_int_type1[port] |= port_mask;
gpio_int_type2[port] &= ~port_mask; gpio_int_type2[port] &= ~port_mask;
} else if (type & IRQT_HIGH) { desc->handle_irq = handle_edge_irq;
gpio_int_enabled[port] |= port_mask; break;
case IRQT_HIGH:
gpio_int_type1[port] &= ~port_mask; gpio_int_type1[port] &= ~port_mask;
gpio_int_type2[port] |= port_mask; gpio_int_type2[port] |= port_mask;
} else if (type & IRQT_LOW) { desc->handle_irq = handle_level_irq;
gpio_int_enabled[port] |= port_mask; break;
case IRQT_LOW:
gpio_int_type1[port] &= ~port_mask; gpio_int_type1[port] &= ~port_mask;
gpio_int_type2[port] &= ~port_mask; gpio_int_type2[port] &= ~port_mask;
} else { desc->handle_irq = handle_level_irq;
gpio_int_enabled[port] &= ~port_mask; break;
case IRQT_BOTHEDGE:
gpio_int_type1[port] |= port_mask;
/* set initial polarity based on current input level */
if (gpio_get_value(gpio))
gpio_int_type2[port] &= ~port_mask; /* falling */
else
gpio_int_type2[port] |= port_mask; /* rising */
desc->handle_irq = handle_edge_irq;
break;
default:
pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
type, gpio);
return -EINVAL;
} }
gpio_int_enabled[port] |= port_mask;
desc->status &= ~IRQ_TYPE_SENSE_MASK;
desc->status |= type & IRQ_TYPE_SENSE_MASK;
update_gpio_int_params(port); update_gpio_int_params(port);
return 0; return 0;
...@@ -385,7 +426,8 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) ...@@ -385,7 +426,8 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
static struct irq_chip ep93xx_gpio_irq_chip = { static struct irq_chip ep93xx_gpio_irq_chip = {
.name = "GPIO", .name = "GPIO",
.ack = ep93xx_gpio_irq_mask_ack, .ack = ep93xx_gpio_irq_ack,
.mask_ack = ep93xx_gpio_irq_mask_ack,
.mask = ep93xx_gpio_irq_mask, .mask = ep93xx_gpio_irq_mask,
.unmask = ep93xx_gpio_irq_unmask, .unmask = ep93xx_gpio_irq_unmask,
.set_type = ep93xx_gpio_irq_type, .set_type = ep93xx_gpio_irq_type,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment