diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/intc.c')
| -rw-r--r-- | arch/avr32/mach-at32ap/intc.c | 82 |
1 files changed, 69 insertions, 13 deletions
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 0b286cd5302..aaff83cc50f 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Atmel Corporation + * Copyright (C) 2006, 2008 Atmel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,15 +12,20 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/syscore_ops.h> +#include <linux/export.h> -#include <asm/intc.h> #include <asm/io.h> #include "intc.h" struct intc { - void __iomem *regs; - struct irq_chip chip; + void __iomem *regs; + struct irq_chip chip; +#ifdef CONFIG_PM + unsigned long suspend_ipr; + unsigned long saved_ipr[64]; +#endif }; extern struct platform_device at32_intc0_device; @@ -29,12 +34,12 @@ extern struct platform_device at32_intc0_device; * TODO: We may be able to implement mask/unmask by setting IxM flags * in the status register. */ -static void intc_mask_irq(unsigned int irq) +static void intc_mask_irq(struct irq_data *d) { } -static void intc_unmask_irq(unsigned int irq) +static void intc_unmask_irq(struct irq_data *d) { } @@ -42,8 +47,8 @@ static void intc_unmask_irq(unsigned int irq) static struct intc intc0 = { .chip = { .name = "intc", - .mask = intc_mask_irq, - .unmask = intc_unmask_irq, + .irq_mask = intc_mask_irq, + .irq_unmask = intc_unmask_irq, }, }; @@ -52,7 +57,6 @@ static struct intc intc0 = { */ asmlinkage void do_IRQ(int level, struct pt_regs *regs) { - struct irq_desc *desc; struct pt_regs *old_regs; unsigned int irq; unsigned long status_reg; @@ -64,8 +68,7 @@ asmlinkage void do_IRQ(int level, struct pt_regs *regs) irq_enter(); irq = intc_readl(&intc0, INTCAUSE0 - 4 * level); - desc = irq_desc + irq; - desc->handle_irq(irq, desc); + generic_handle_irq(irq); /* * Clear all interrupt level masks so that we may handle @@ -105,7 +108,7 @@ void __init init_IRQ(void) clk_enable(pclk); - intc0.regs = ioremap(regs->start, regs->end - regs->start + 1); + intc0.regs = ioremap(regs->start, resource_size(regs)); if (!intc0.regs) { printk(KERN_EMERG "intc: failed to map registers (0x%08lx)\n", (unsigned long)regs->start); @@ -123,7 +126,7 @@ void __init init_IRQ(void) intc_writel(&intc0, INTPR0 + 4 * i, offset); readback = intc_readl(&intc0, INTPR0 + 4 * i); if (readback == offset) - set_irq_chip_and_handler(i, &intc0.chip, + irq_set_chip_and_handler(i, &intc0.chip, handle_simple_irq); } @@ -137,6 +140,59 @@ fail: panic("Interrupt controller initialization failed!\n"); } +#ifdef CONFIG_PM +void intc_set_suspend_handler(unsigned long offset) +{ + intc0.suspend_ipr = offset; +} + +static int intc_suspend(void) +{ + int i; + + if (unlikely(!irqs_disabled())) { + pr_err("intc_suspend: called with interrupts enabled\n"); + return -EINVAL; + } + + if (unlikely(!intc0.suspend_ipr)) { + pr_err("intc_suspend: suspend_ipr not initialized\n"); + return -EINVAL; + } + + for (i = 0; i < 64; i++) { + intc0.saved_ipr[i] = intc_readl(&intc0, INTPR0 + 4 * i); + intc_writel(&intc0, INTPR0 + 4 * i, intc0.suspend_ipr); + } + + return 0; +} + +static void intc_resume(void) +{ + int i; + + for (i = 0; i < 64; i++) + intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]); +} +#else +#define intc_suspend NULL +#define intc_resume NULL +#endif + +static struct syscore_ops intc_syscore_ops = { + .suspend = intc_suspend, + .resume = intc_resume, +}; + +static int __init intc_init_syscore(void) +{ + register_syscore_ops(&intc_syscore_ops); + + return 0; +} +device_initcall(intc_init_syscore); + unsigned long intc_get_pending(unsigned int group) { return intc_readl(&intc0, INTREQ0 + 4 * group); |
