diff mbox

[1/3] gpio-rcar: Add support for IRQ_TYPE_EDGE_BOTH

Message ID 1368435233-8587-2-git-send-email-horms+renesas@verge.net.au (mailing list archive)
State Superseded
Commit 69749ba762ef195c04c37513b7e9a84a4c96c66a
Headers show

Commit Message

Simon Horman May 13, 2013, 8:53 a.m. UTC
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. This patch has been lightly
exercised using that driver on that board.

Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
 drivers/gpio/gpio-rcar.c                | 27 ++++++++++++++++++++++-----
 include/linux/platform_data/gpio-rcar.h |  1 +
 2 files changed, 23 insertions(+), 5 deletions(-)

Comments

Magnus Damm May 13, 2013, 10:14 a.m. UTC | #1
On Mon, May 13, 2013 at 5:53 PM, Simon Horman
<horms+renesas@verge.net.au> wrote:
> 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. This patch has been lightly
> exercised using that driver on that board.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> ---
>  drivers/gpio/gpio-rcar.c                | 27 ++++++++++++++++++++++-----
>  include/linux/platform_data/gpio-rcar.h |  1 +
>  2 files changed, 23 insertions(+), 5 deletions(-)

Thanks for the patch, Simon!

> diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
> index 0f3d647..33d8f6a 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)
>  {
> @@ -111,6 +113,11 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
>         /* Select "Interrupt Input Mode" in IOINTSEL */
>         gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
>
> +       if (p->config.has_both_edge_trigger && !level_trigger) {
> +               /* Select one edge or both edges in BOTHEDGE */
> +               gpio_rcar_modify_bit(p, IOINTSEL, hwirq, both);
> +       }
> +
>         /* Write INTCLR in case of edge trigger */
>         if (!level_trigger)
>                 gpio_rcar_write(p, INTCLR, BIT(hwirq));

In your hunk above I suspect you want to setup the BOTHEDGE register
instead of IOINTSEL.

Also, I wonder how BOTHEDGE should be set in the case of level
trigger. Say that the user first selects edge trigger and then
reconfigures to level, then you probably want to make sure the
BOTHEDGE register is cleared.

So may want to do something like this (untested):

       if (p->config.has_both_edge_trigger) {
               /* Select one edge or both edges in BOTHEDGE */
               gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
       }

Also, please double check that the register access sequences in the
documentation are still kept, please see "6.7.1 Setting Edge-Sensitive
Interrupt Input Mode" in the H2 data sheet. It looks like you want to
move this setting so it happens before IOINTSEL.

Thanks!

/ magnus
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Horman May 14, 2013, 2:44 a.m. UTC | #2
On Mon, May 13, 2013 at 07:14:41PM +0900, Magnus Damm wrote:
> On Mon, May 13, 2013 at 5:53 PM, Simon Horman
> <horms+renesas@verge.net.au> wrote:
> > 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. This patch has been lightly
> > exercised using that driver on that board.
> >
> > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > ---
> >  drivers/gpio/gpio-rcar.c                | 27 ++++++++++++++++++++++-----
> >  include/linux/platform_data/gpio-rcar.h |  1 +
> >  2 files changed, 23 insertions(+), 5 deletions(-)
> 
> Thanks for the patch, Simon!
> 
> > diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
> > index 0f3d647..33d8f6a 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)
> >  {
> > @@ -111,6 +113,11 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
> >         /* Select "Interrupt Input Mode" in IOINTSEL */
> >         gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
> >
> > +       if (p->config.has_both_edge_trigger && !level_trigger) {
> > +               /* Select one edge or both edges in BOTHEDGE */
> > +               gpio_rcar_modify_bit(p, IOINTSEL, hwirq, both);
> > +       }
> > +
> >         /* Write INTCLR in case of edge trigger */
> >         if (!level_trigger)
> >                 gpio_rcar_write(p, INTCLR, BIT(hwirq));
> 
> In your hunk above I suspect you want to setup the BOTHEDGE register
> instead of IOINTSEL.

Thanks, I will fix that.

> Also, I wonder how BOTHEDGE should be set in the case of level
> trigger. Say that the user first selects edge trigger and then
> reconfigures to level, then you probably want to make sure the
> BOTHEDGE register is cleared.
> 
> So may want to do something like this (untested):
> 
>        if (p->config.has_both_edge_trigger) {
>                /* Select one edge or both edges in BOTHEDGE */
>                gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
>        }

Sure, if you think so.

> Also, please double check that the register access sequences in the
> documentation are still kept, please see "6.7.1 Setting Edge-Sensitive
> Interrupt Input Mode" in the H2 data sheet. It looks like you want to
> move this setting so it happens before IOINTSEL.

Thanks, I will fix that.
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 0f3d647..33d8f6a 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;
 
@@ -111,6 +113,11 @@  static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
 	/* Select "Interrupt Input Mode" in IOINTSEL */
 	gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
 
+	if (p->config.has_both_edge_trigger && !level_trigger) {
+		/* Select one edge or both edges in BOTHEDGE */
+		gpio_rcar_modify_bit(p, IOINTSEL, hwirq, both);
+	}
+
 	/* Write INTCLR in case of edge trigger */
 	if (!level_trigger)
 		gpio_rcar_write(p, INTCLR, BIT(hwirq));
@@ -127,16 +134,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 cc472f6..dfea5c6 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;
 };
 
 #define RCAR_GP_PIN(bank, pin)		(((bank) * 32) + (pin))