diff mbox

ARM: at91: add gpio suspend/resume support when using pinctrl

Message ID 1362755901-20279-1-git-send-email-ludovic.desroches@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ludovic Desroches March 8, 2013, 3:18 p.m. UTC
From: Ludovic Desroches <ludovic.desroches@atmel.com>

gpio suspend/resume and wakeup sources where not managed when using pinctrl so
it was impossible to wake up the system with a gpio.

Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 arch/arm/mach-at91/include/mach/gpio.h |  8 +++++
 arch/arm/mach-at91/pm.c                | 10 ++++--
 drivers/pinctrl/pinctrl-at91.c         | 61 +++++++++++++++++++++++++++++++++-
 3 files changed, 76 insertions(+), 3 deletions(-)

Comments

Nicolas Ferre March 13, 2013, 9:22 a.m. UTC | #1
On 03/08/2013 04:18 PM, ludovic.desroches@atmel.com :
> From: Ludovic Desroches <ludovic.desroches@atmel.com>
> 
> gpio suspend/resume and wakeup sources where not managed when using pinctrl so
> it was impossible to wake up the system with a gpio.
> 
> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

Nice, I queue it for "fixes" in at91-3.9-fixes.

Thanks, best regards,

> ---
>  arch/arm/mach-at91/include/mach/gpio.h |  8 +++++
>  arch/arm/mach-at91/pm.c                | 10 ++++--
>  drivers/pinctrl/pinctrl-at91.c         | 61 +++++++++++++++++++++++++++++++++-
>  3 files changed, 76 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
> index eed465a..5fc2377 100644
> --- a/arch/arm/mach-at91/include/mach/gpio.h
> +++ b/arch/arm/mach-at91/include/mach/gpio.h
> @@ -209,6 +209,14 @@ extern int at91_get_gpio_value(unsigned pin);
>  extern void at91_gpio_suspend(void);
>  extern void at91_gpio_resume(void);
>  
> +#ifdef CONFIG_PINCTRL_AT91
> +extern void at91_pinctrl_gpio_suspend(void);
> +extern void at91_pinctrl_gpio_resume(void);
> +#else
> +static inline void at91_pinctrl_gpio_suspend(void) {}
> +static inline void at91_pinctrl_gpio_resume(void) {}
> +#endif
> +
>  #endif	/* __ASSEMBLY__ */
>  
>  #endif
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
> index adb6db8..73f1f25 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -201,7 +201,10 @@ extern u32 at91_slow_clock_sz;
>  
>  static int at91_pm_enter(suspend_state_t state)
>  {
> -	at91_gpio_suspend();
> +	if (of_have_populated_dt())
> +		at91_pinctrl_gpio_suspend();
> +	else
> +		at91_gpio_suspend();
>  	at91_irq_suspend();
>  
>  	pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
> @@ -286,7 +289,10 @@ static int at91_pm_enter(suspend_state_t state)
>  error:
>  	target_state = PM_SUSPEND_ON;
>  	at91_irq_resume();
> -	at91_gpio_resume();
> +	if (of_have_populated_dt())
> +		at91_pinctrl_gpio_resume();
> +	else
> +		at91_gpio_resume();
>  	return 0;
>  }
>  
> diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
> index 75933a6..efb7f10 100644
> --- a/drivers/pinctrl/pinctrl-at91.c
> +++ b/drivers/pinctrl/pinctrl-at91.c
> @@ -1277,21 +1277,80 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
>  }
>  
>  #ifdef CONFIG_PM
> +
> +static u32 wakeups[MAX_GPIO_BANKS];
> +static u32 backups[MAX_GPIO_BANKS];
> +
>  static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
>  {
>  	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
>  	unsigned	bank = at91_gpio->pioc_idx;
> +	unsigned mask = 1 << d->hwirq;
>  
>  	if (unlikely(bank >= MAX_GPIO_BANKS))
>  		return -EINVAL;
>  
> +	if (state)
> +		wakeups[bank] |= mask;
> +	else
> +		wakeups[bank] &= ~mask;
> +
>  	irq_set_irq_wake(at91_gpio->pioc_virq, state);
>  
>  	return 0;
>  }
> +
> +void at91_pinctrl_gpio_suspend(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < gpio_banks; i++) {
> +		void __iomem  *pio;
> +
> +		if (!gpio_chips[i])
> +			continue;
> +
> +		pio = gpio_chips[i]->regbase;
> +
> +		backups[i] = __raw_readl(pio + PIO_IMR);
> +		__raw_writel(backups[i], pio + PIO_IDR);
> +		__raw_writel(wakeups[i], pio + PIO_IER);
> +
> +		if (!wakeups[i]) {
> +			clk_unprepare(gpio_chips[i]->clock);
> +			clk_disable(gpio_chips[i]->clock);
> +		} else {
> +			printk(KERN_DEBUG "GPIO-%c may wake for %08x\n",
> +			       'A'+i, wakeups[i]);
> +		}
> +	}
> +}
> +
> +void at91_pinctrl_gpio_resume(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < gpio_banks; i++) {
> +		void __iomem  *pio;
> +
> +		if (!gpio_chips[i])
> +			continue;
> +
> +		pio = gpio_chips[i]->regbase;
> +
> +		if (!wakeups[i]) {
> +			if (clk_prepare(gpio_chips[i]->clock) == 0)
> +				clk_enable(gpio_chips[i]->clock);
> +		}
> +
> +		__raw_writel(wakeups[i], pio + PIO_IDR);
> +		__raw_writel(backups[i], pio + PIO_IER);
> +	}
> +}
> +
>  #else
>  #define gpio_irq_set_wake	NULL
> -#endif
> +#endif /* CONFIG_PM */
>  
>  static struct irq_chip gpio_irqchip = {
>  	.name		= "GPIO",
>
Linus Walleij March 13, 2013, 7:05 p.m. UTC | #2
On Fri, Mar 8, 2013 at 4:18 PM,  <ludovic.desroches@atmel.com> wrote:

> From: Ludovic Desroches <ludovic.desroches@atmel.com>
>
> gpio suspend/resume and wakeup sources where not managed when using pinctrl so
> it was impossible to wake up the system with a gpio.
>
> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

I saw that Nicolas is taking care of it...

Yours,
Linus Walleij
diff mbox

Patch

diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
index eed465a..5fc2377 100644
--- a/arch/arm/mach-at91/include/mach/gpio.h
+++ b/arch/arm/mach-at91/include/mach/gpio.h
@@ -209,6 +209,14 @@  extern int at91_get_gpio_value(unsigned pin);
 extern void at91_gpio_suspend(void);
 extern void at91_gpio_resume(void);
 
+#ifdef CONFIG_PINCTRL_AT91
+extern void at91_pinctrl_gpio_suspend(void);
+extern void at91_pinctrl_gpio_resume(void);
+#else
+static inline void at91_pinctrl_gpio_suspend(void) {}
+static inline void at91_pinctrl_gpio_resume(void) {}
+#endif
+
 #endif	/* __ASSEMBLY__ */
 
 #endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index adb6db8..73f1f25 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -201,7 +201,10 @@  extern u32 at91_slow_clock_sz;
 
 static int at91_pm_enter(suspend_state_t state)
 {
-	at91_gpio_suspend();
+	if (of_have_populated_dt())
+		at91_pinctrl_gpio_suspend();
+	else
+		at91_gpio_suspend();
 	at91_irq_suspend();
 
 	pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
@@ -286,7 +289,10 @@  static int at91_pm_enter(suspend_state_t state)
 error:
 	target_state = PM_SUSPEND_ON;
 	at91_irq_resume();
-	at91_gpio_resume();
+	if (of_have_populated_dt())
+		at91_pinctrl_gpio_resume();
+	else
+		at91_gpio_resume();
 	return 0;
 }
 
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 75933a6..efb7f10 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1277,21 +1277,80 @@  static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
 }
 
 #ifdef CONFIG_PM
+
+static u32 wakeups[MAX_GPIO_BANKS];
+static u32 backups[MAX_GPIO_BANKS];
+
 static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
 {
 	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
 	unsigned	bank = at91_gpio->pioc_idx;
+	unsigned mask = 1 << d->hwirq;
 
 	if (unlikely(bank >= MAX_GPIO_BANKS))
 		return -EINVAL;
 
+	if (state)
+		wakeups[bank] |= mask;
+	else
+		wakeups[bank] &= ~mask;
+
 	irq_set_irq_wake(at91_gpio->pioc_virq, state);
 
 	return 0;
 }
+
+void at91_pinctrl_gpio_suspend(void)
+{
+	int i;
+
+	for (i = 0; i < gpio_banks; i++) {
+		void __iomem  *pio;
+
+		if (!gpio_chips[i])
+			continue;
+
+		pio = gpio_chips[i]->regbase;
+
+		backups[i] = __raw_readl(pio + PIO_IMR);
+		__raw_writel(backups[i], pio + PIO_IDR);
+		__raw_writel(wakeups[i], pio + PIO_IER);
+
+		if (!wakeups[i]) {
+			clk_unprepare(gpio_chips[i]->clock);
+			clk_disable(gpio_chips[i]->clock);
+		} else {
+			printk(KERN_DEBUG "GPIO-%c may wake for %08x\n",
+			       'A'+i, wakeups[i]);
+		}
+	}
+}
+
+void at91_pinctrl_gpio_resume(void)
+{
+	int i;
+
+	for (i = 0; i < gpio_banks; i++) {
+		void __iomem  *pio;
+
+		if (!gpio_chips[i])
+			continue;
+
+		pio = gpio_chips[i]->regbase;
+
+		if (!wakeups[i]) {
+			if (clk_prepare(gpio_chips[i]->clock) == 0)
+				clk_enable(gpio_chips[i]->clock);
+		}
+
+		__raw_writel(wakeups[i], pio + PIO_IDR);
+		__raw_writel(backups[i], pio + PIO_IER);
+	}
+}
+
 #else
 #define gpio_irq_set_wake	NULL
-#endif
+#endif /* CONFIG_PM */
 
 static struct irq_chip gpio_irqchip = {
 	.name		= "GPIO",