| From d8d574975de57110e0f08077056d8741fb3c204a Mon Sep 17 00:00:00 2001 |
| From: Simon Horman <horms+renesas@verge.net.au> |
| Date: Fri, 24 May 2013 18:47:24 +0900 |
| Subject: 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: Magnus Damm <damm@opensource.se> |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| (cherry picked from commit 7e1092b5a264c484001b0cdd1f49bea7884e3366) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpio/gpio-rcar.c | 26 +++++++++++++++++++++----- |
| include/linux/platform_data/gpio-rcar.h | 1 + |
| 2 files changed, 22 insertions(+), 5 deletions(-) |
| |
| diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c |
| index 0f3d6473..d173d56d 100644 |
| --- a/drivers/gpio/gpio-rcar.c |
| +++ b/drivers/gpio/gpio-rcar.c |
| @@ -49,6 +49,7 @@ struct gpio_rcar_priv { |
| #define POSNEG 0x20 |
| #define EDGLEVEL 0x24 |
| #define FILONOFF 0x28 |
| +#define BOTHEDGE 0x4c |
| |
| 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) |
| static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, |
| unsigned int hwirq, |
| bool active_high_rising_edge, |
| - bool level_trigger) |
| + bool level_trigger, |
| + bool both) |
| { |
| unsigned long flags; |
| |
| @@ -108,6 +110,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, |
| /* Configure edge or level trigger in EDGLEVEL */ |
| 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 */ |
| 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) |
| |
| switch (type & IRQ_TYPE_SENSE_MASK) { |
| 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; |
| 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; |
| 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; |
| 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; |
| default: |
| return -EINVAL; |
| diff --git a/include/linux/platform_data/gpio-rcar.h b/include/linux/platform_data/gpio-rcar.h |
| index aba7079c..6c0027a3 100644 |
| --- a/include/linux/platform_data/gpio-rcar.h |
| +++ b/include/linux/platform_data/gpio-rcar.h |
| @@ -21,6 +21,7 @@ struct gpio_rcar_config { |
| unsigned int irq_base; |
| unsigned int number_of_pins; |
| const char *pctl_name; |
| + unsigned has_both_edge_trigger:1; |
| }; |
| |
| #endif /* __GPIO_RCAR_H__ */ |
| -- |
| 1.8.4.3.gca3854a |
| |