Commit 3ea163e4 authored by Andrew Victor's avatar Andrew Victor Committed by Russell King

[ARM] 4089/1: AT91: GPIO wake IRQ cleanup

Cleanup of at91 platform level gpio wake and suspend/resume logic.

The GPIO core now delegates wakeups to the parent AIC by refcounting,
and delegates clock management to the clock API.  This makes these
system modules more independent of each other, which is cleaner and will
also help with the AT91SAM9263 (where some GPIO controllers share the
same irq and clock).

Original patch by David Brownell.
Signed-off-by: default avatarAndrew Victor <andrew@sanpeople.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9b938166
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/arch/at91_pio.h> #include <asm/arch/at91_pio.h>
#include <asm/arch/at91_pmc.h>
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#include "generic.h" #include "generic.h"
...@@ -224,17 +223,17 @@ static u32 backups[MAX_GPIO_BANKS]; ...@@ -224,17 +223,17 @@ static u32 backups[MAX_GPIO_BANKS];
static int gpio_irq_set_wake(unsigned pin, unsigned state) static int gpio_irq_set_wake(unsigned pin, unsigned state)
{ {
unsigned mask = pin_to_mask(pin); unsigned mask = pin_to_mask(pin);
unsigned bank = (pin - PIN_BASE) / 32;
pin -= PIN_BASE; if (unlikely(bank >= MAX_GPIO_BANKS))
pin /= 32;
if (unlikely(pin >= MAX_GPIO_BANKS))
return -EINVAL; return -EINVAL;
if (state) if (state)
wakeups[pin] |= mask; wakeups[bank] |= mask;
else else
wakeups[pin] &= ~mask; wakeups[bank] &= ~mask;
set_irq_wake(gpio[bank].id, state);
return 0; return 0;
} }
...@@ -246,29 +245,15 @@ void at91_gpio_suspend(void) ...@@ -246,29 +245,15 @@ void at91_gpio_suspend(void)
for (i = 0; i < gpio_banks; i++) { for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset; u32 pio = gpio[i].offset;
/*
* Note: drivers should have disabled GPIO interrupts that
* aren't supposed to be wakeup sources.
* But that is not much good on ARM..... disable_irq() does
* not update the hardware immediately, so the hardware mask
* (IMR) has the wrong value (not current, too much is
* permitted).
*
* Our workaround is to disable all non-wakeup IRQs ...
* which is exactly what correct drivers asked for in the
* first place!
*/
backups[i] = at91_sys_read(pio + PIO_IMR); backups[i] = at91_sys_read(pio + PIO_IMR);
at91_sys_write(pio + PIO_IDR, backups[i]); at91_sys_write(pio + PIO_IDR, backups[i]);
at91_sys_write(pio + PIO_IER, wakeups[i]); at91_sys_write(pio + PIO_IER, wakeups[i]);
if (!wakeups[i]) { if (!wakeups[i])
disable_irq_wake(gpio[i].id); clk_disable(gpio[i].clock);
at91_sys_write(AT91_PMC_PCDR, 1 << gpio[i].id); else {
} else {
enable_irq_wake(gpio[i].id);
#ifdef CONFIG_PM_DEBUG #ifdef CONFIG_PM_DEBUG
printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]); printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
#endif #endif
} }
} }
...@@ -281,9 +266,11 @@ void at91_gpio_resume(void) ...@@ -281,9 +266,11 @@ void at91_gpio_resume(void)
for (i = 0; i < gpio_banks; i++) { for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset; u32 pio = gpio[i].offset;
if (!wakeups[i])
clk_enable(gpio[i].clock);
at91_sys_write(pio + PIO_IDR, wakeups[i]); at91_sys_write(pio + PIO_IDR, wakeups[i]);
at91_sys_write(pio + PIO_IER, backups[i]); at91_sys_write(pio + PIO_IER, backups[i]);
at91_sys_write(AT91_PMC_PCER, 1 << gpio[i].id);
} }
} }
......
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