Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 28091
b: refs/heads/master
c: 814138f
h: refs/heads/master
i:
  28089: 1f07033
  28087: 26a4b43
v: v3
  • Loading branch information
Andrew Victor authored and Russell King committed Jun 19, 2006
1 parent 5c33174 commit 83e0186
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 683c66bf75ce277b90d658da0c1a0bf1a55cce4c
refs/heads/master: 814138ffa488824393d2f49f2720dcd197a7d4cf
87 changes: 84 additions & 3 deletions trunk/arch/arm/mach-at91rm9200/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,84 @@ EXPORT_SYMBOL(at91_get_gpio_value);

/*--------------------------------------------------------------------------*/

#ifdef CONFIG_PM

static u32 wakeups[BGA_GPIO_BANKS];
static u32 backups[BGA_GPIO_BANKS];

static int gpio_irq_set_wake(unsigned pin, unsigned state)
{
unsigned mask = pin_to_mask(pin);

pin -= PIN_BASE;
pin /= 32;

if (unlikely(pin >= BGA_GPIO_BANKS))
return -EINVAL;

if (state)
wakeups[pin] |= mask;
else
wakeups[pin] &= ~mask;

return 0;
}

void at91_gpio_suspend(void)
{
int i;

for (i = 0; i < BGA_GPIO_BANKS; i++) {
u32 pio = pio_controller_offset[i];

/*
* 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);
at91_sys_write(pio_controller_offset[i] + PIO_IDR, backups[i]);
at91_sys_write(pio_controller_offset[i] + PIO_IER, wakeups[i]);

if (!wakeups[i]) {
disable_irq_wake(AT91_ID_PIOA + i);
at91_sys_write(AT91_PMC_PCDR, 1 << (AT91_ID_PIOA + i));
} else {
enable_irq_wake(AT91_ID_PIOA + i);
#ifdef CONFIG_PM_DEBUG
printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]);
#endif
}
}
}

void at91_gpio_resume(void)
{
int i;

for (i = 0; i < BGA_GPIO_BANKS; i++) {
at91_sys_write(pio_controller_offset[i] + PIO_IDR, wakeups[i]);
at91_sys_write(pio_controller_offset[i] + PIO_IER, backups[i]);
}

at91_sys_write(AT91_PMC_PCER,
(1 << AT91_ID_PIOA)
| (1 << AT91_ID_PIOB)
| (1 << AT91_ID_PIOC)
| (1 << AT91_ID_PIOD));
}

#else
#define gpio_irq_set_wake NULL
#endif


/* Several AIC controller irqs are dispatched through this GPIO handler.
* To use any AT91_PIN_* as an externally triggered IRQ, first call
Expand Down Expand Up @@ -252,6 +330,7 @@ static struct irqchip gpio_irqchip = {
.mask = gpio_irq_mask,
.unmask = gpio_irq_unmask,
.set_type = gpio_irq_type,
.set_wake = gpio_irq_set_wake,
};

static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)
Expand All @@ -266,6 +345,7 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs
/* temporarily mask (level sensitive) parent IRQ */
desc->chip->ack(irq);
for (;;) {
/* reading ISR acks the pending (edge triggered) GPIO interrupt */
isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
if (!isr)
break;
Expand Down Expand Up @@ -315,15 +395,16 @@ void __init at91_gpio_irq_setup(unsigned banks)
set_irq_chipdata(id, controller);

for (i = 0; i < 32; i++, pin++) {
/*
* Can use the "simple" and not "edge" handler since it's
* shorter, and the AIC handles interupts sanely.
*/
set_irq_chip(pin, &gpio_irqchip);
set_irq_handler(pin, do_simple_IRQ);
set_irq_flags(pin, IRQF_VALID);
}

set_irq_chained_handler(id, gpio_irq_handler);

/* enable the PIO peripheral clock */
at91_sys_write(AT91_PMC_PCER, 1 << id);
}
pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks);
}

0 comments on commit 83e0186

Please sign in to comment.