Commit 7e1092b5 authored by Simon Horman's avatar Simon Horman

gpio-rcar: Add support for IRQ_TYPE_EDGE_BOTH

As hardware support for this feature is not universal for all SoCs a flag,
has_both_edge_trigger, has been added to the platform data of the driver to
allow this feature to be enabled.

The motivation for this is to allow use of the gpio-keys driver on the
lager board which is based on the r8a7790 SoC. The V2 of this patch has been
fully exercised using that driver on that board.
Signed-off-by: default avatarMagnus Damm <damm@opensource.se>
Signed-off-by: default avatarSimon Horman <horms+renesas@verge.net.au>
parent 36cb0066
...@@ -49,6 +49,7 @@ struct gpio_rcar_priv { ...@@ -49,6 +49,7 @@ struct gpio_rcar_priv {
#define POSNEG 0x20 #define POSNEG 0x20
#define EDGLEVEL 0x24 #define EDGLEVEL 0x24
#define FILONOFF 0x28 #define FILONOFF 0x28
#define BOTHEDGE 0x4c
static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
{ {
...@@ -91,7 +92,8 @@ static void gpio_rcar_irq_enable(struct irq_data *d) ...@@ -91,7 +92,8 @@ static void gpio_rcar_irq_enable(struct irq_data *d)
static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
unsigned int hwirq, unsigned int hwirq,
bool active_high_rising_edge, bool active_high_rising_edge,
bool level_trigger) bool level_trigger,
bool both)
{ {
unsigned long flags; unsigned long flags;
...@@ -108,6 +110,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, ...@@ -108,6 +110,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
/* Configure edge or level trigger in EDGLEVEL */ /* Configure edge or level trigger in EDGLEVEL */
gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
/* Select one edge or both edges in BOTHEDGE */
if (p->config.has_both_edge_trigger)
gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
/* Select "Interrupt Input Mode" in IOINTSEL */ /* Select "Interrupt Input Mode" in IOINTSEL */
gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
...@@ -127,16 +133,26 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -127,16 +133,26 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
switch (type & IRQ_TYPE_SENSE_MASK) { switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_LEVEL_HIGH: case IRQ_TYPE_LEVEL_HIGH:
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true); gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true,
false);
break; break;
case IRQ_TYPE_LEVEL_LOW: case IRQ_TYPE_LEVEL_LOW:
gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true); gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true,
false);
break; break;
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false); gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
false);
break; break;
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false); gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false,
false);
break;
case IRQ_TYPE_EDGE_BOTH:
if (!p->config.has_both_edge_trigger)
return -EINVAL;
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
true);
break; break;
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -21,6 +21,7 @@ struct gpio_rcar_config { ...@@ -21,6 +21,7 @@ struct gpio_rcar_config {
unsigned int irq_base; unsigned int irq_base;
unsigned int number_of_pins; unsigned int number_of_pins;
const char *pctl_name; const char *pctl_name;
unsigned has_both_edge_trigger:1;
}; };
#endif /* __GPIO_RCAR_H__ */ #endif /* __GPIO_RCAR_H__ */
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