aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorAndrew Victor <andrew@sanpeople.com>2007-01-09 07:47:29 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-01-24 06:59:56 -0500
commit3ea163e44c041b9e1d7314998dfbfd4fbc6eea20 (patch)
treed2b1b4868ad3528411925878585590fb74ef0450 /arch/arm
parent9b938166907558e664d8fa413e6233a36669e0c0 (diff)
[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: Andrew Victor <andrew@sanpeople.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-at91rm9200/gpio.c39
1 files changed, 13 insertions, 26 deletions
diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c
index 3f188508c391..af22659c8a28 100644
--- a/arch/arm/mach-at91rm9200/gpio.c
+++ b/arch/arm/mach-at91rm9200/gpio.c
@@ -20,7 +20,6 @@
20#include <asm/io.h> 20#include <asm/io.h>
21#include <asm/hardware.h> 21#include <asm/hardware.h>
22#include <asm/arch/at91_pio.h> 22#include <asm/arch/at91_pio.h>
23#include <asm/arch/at91_pmc.h>
24#include <asm/arch/gpio.h> 23#include <asm/arch/gpio.h>
25 24
26#include "generic.h" 25#include "generic.h"
@@ -224,17 +223,17 @@ static u32 backups[MAX_GPIO_BANKS];
224static int gpio_irq_set_wake(unsigned pin, unsigned state) 223static int gpio_irq_set_wake(unsigned pin, unsigned state)
225{ 224{
226 unsigned mask = pin_to_mask(pin); 225 unsigned mask = pin_to_mask(pin);
226 unsigned bank = (pin - PIN_BASE) / 32;
227 227
228 pin -= PIN_BASE; 228 if (unlikely(bank >= MAX_GPIO_BANKS))
229 pin /= 32;
230
231 if (unlikely(pin >= MAX_GPIO_BANKS))
232 return -EINVAL; 229 return -EINVAL;
233 230
234 if (state) 231 if (state)
235 wakeups[pin] |= mask; 232 wakeups[bank] |= mask;
236 else 233 else
237 wakeups[pin] &= ~mask; 234 wakeups[bank] &= ~mask;
235
236 set_irq_wake(gpio[bank].id, state);
238 237
239 return 0; 238 return 0;
240} 239}
@@ -246,29 +245,15 @@ void at91_gpio_suspend(void)
246 for (i = 0; i < gpio_banks; i++) { 245 for (i = 0; i < gpio_banks; i++) {
247 u32 pio = gpio[i].offset; 246 u32 pio = gpio[i].offset;
248 247
249 /*
250 * Note: drivers should have disabled GPIO interrupts that
251 * aren't supposed to be wakeup sources.
252 * But that is not much good on ARM..... disable_irq() does
253 * not update the hardware immediately, so the hardware mask
254 * (IMR) has the wrong value (not current, too much is
255 * permitted).
256 *
257 * Our workaround is to disable all non-wakeup IRQs ...
258 * which is exactly what correct drivers asked for in the
259 * first place!
260 */
261 backups[i] = at91_sys_read(pio + PIO_IMR); 248 backups[i] = at91_sys_read(pio + PIO_IMR);
262 at91_sys_write(pio + PIO_IDR, backups[i]); 249 at91_sys_write(pio + PIO_IDR, backups[i]);
263 at91_sys_write(pio + PIO_IER, wakeups[i]); 250 at91_sys_write(pio + PIO_IER, wakeups[i]);
264 251
265 if (!wakeups[i]) { 252 if (!wakeups[i])
266 disable_irq_wake(gpio[i].id); 253 clk_disable(gpio[i].clock);
267 at91_sys_write(AT91_PMC_PCDR, 1 << gpio[i].id); 254 else {
268 } else {
269 enable_irq_wake(gpio[i].id);
270#ifdef CONFIG_PM_DEBUG 255#ifdef CONFIG_PM_DEBUG
271 printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]); 256 printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
272#endif 257#endif
273 } 258 }
274 } 259 }
@@ -281,9 +266,11 @@ void at91_gpio_resume(void)
281 for (i = 0; i < gpio_banks; i++) { 266 for (i = 0; i < gpio_banks; i++) {
282 u32 pio = gpio[i].offset; 267 u32 pio = gpio[i].offset;
283 268
269 if (!wakeups[i])
270 clk_enable(gpio[i].clock);
271
284 at91_sys_write(pio + PIO_IDR, wakeups[i]); 272 at91_sys_write(pio + PIO_IDR, wakeups[i]);
285 at91_sys_write(pio + PIO_IER, backups[i]); 273 at91_sys_write(pio + PIO_IER, backups[i]);
286 at91_sys_write(AT91_PMC_PCER, 1 << gpio[i].id);
287 } 274 }
288} 275}
289 276