Make use of the suspend/resume functionality as well. Signed-off-by: Thomas Gleixner --- arch/arm/mach-pxa/irq.c | 192 +++++++++++++++++++----------------------------- 1 file changed, 76 insertions(+), 116 deletions(-) Index: linux-2.6/arch/arm/mach-pxa/irq.c =================================================================== --- linux-2.6.orig/arch/arm/mach-pxa/irq.c +++ linux-2.6/arch/arm/mach-pxa/irq.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -40,14 +40,9 @@ #define IPR_VALID (1 << 31) #define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f) -#define MAX_INTERNAL_IRQS 128 - /* * This is for peripheral IRQs internal to the PXA chip. */ - -static int pxa_internal_irq_nr; - static inline int cpu_has_ipr(void) { return !cpu_is_pxa25x(); @@ -64,31 +59,6 @@ static inline void __iomem *irq_base(int return (void __iomem *)io_p2v(phys_base[i]); } -static void pxa_mask_irq(struct irq_data *d) -{ - void __iomem *base = irq_data_get_irq_chip_data(d); - uint32_t icmr = __raw_readl(base + ICMR); - - icmr &= ~(1 << IRQ_BIT(d->irq)); - __raw_writel(icmr, base + ICMR); -} - -static void pxa_unmask_irq(struct irq_data *d) -{ - void __iomem *base = irq_data_get_irq_chip_data(d); - uint32_t icmr = __raw_readl(base + ICMR); - - icmr |= 1 << IRQ_BIT(d->irq); - __raw_writel(icmr, base + ICMR); -} - -static struct irq_chip pxa_internal_irq_chip = { - .name = "SC", - .irq_ack = pxa_mask_irq, - .irq_mask = pxa_mask_irq, - .irq_unmask = pxa_unmask_irq, -}; - /* * GPIO IRQs for GPIO 0 and 1 */ @@ -119,121 +89,111 @@ static void pxa_ack_low_gpio(struct irq_ GEDR0 = (1 << (d->irq - IRQ_GPIO0)); } -static struct irq_chip pxa_low_gpio_chip = { - .name = "GPIO-l", - .irq_ack = pxa_ack_low_gpio, - .irq_mask = pxa_mask_irq, - .irq_unmask = pxa_unmask_irq, - .irq_set_type = pxa_set_low_gpio_type, -}; - -static void __init pxa_init_low_gpio_irq(set_wake_t fn) +#ifdef CONFIG_PM +static void __init pxa_init_low_gpio_irq(struct irq_chip_generic *gc) { - int irq; + struct irq_chip_type *ct = gc->chip_types + 1; + unsigned int irq = gc->irq_base; + + if (irq > IRQ_GPIO0 || irq + 32 < IRQ_GPIO0) + return; /* clear edge detection on GPIO 0 and 1 */ GFER0 &= ~0x3; GRER0 &= ~0x3; GEDR0 = 0x3; - for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { - irq_set_chip_and_handler(irq, &pxa_low_gpio_chip, - handle_edge_irq); - irq_set_chip_data(irq, irq_base(0)); - set_irq_flags(irq, IRQF_VALID); - } + /* Copy the base chip */ + *ct = *gc->chip_types; + ct->chip.name = "GPIO-l"; + ct->chip.irq_ack = pxa_ack_low_gpio; + ct->chip.irq_set_type = pxa_set_low_gpio_type; - pxa_low_gpio_chip.irq_set_wake = fn; + for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) + irq_set_chip_and_handler(irq, &ct->chip, handle_edge_irq); } -void __init pxa_init_irq(int irq_nr, set_wake_t fn) +static void pxa_irq_suspend(struct irq_data *d) { - int irq, i, n; - - BUG_ON(irq_nr > MAX_INTERNAL_IRQS); - - pxa_internal_irq_nr = irq_nr; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 *ipr = gc->private; - for (n = 0; n < irq_nr; n += 32) { - void __iomem *base = irq_base(n >> 5); + writel(0, gc->reg_base + ICMR); - __raw_writel(0, base + ICMR); /* disable all IRQs */ - __raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */ - for (i = n; (i < (n + 32)) && (i < irq_nr); i++) { - /* initialize interrupt priority */ - if (cpu_has_ipr()) - __raw_writel(i | IPR_VALID, IRQ_BASE + IPR(i)); + if (cpu_has_ipr()) { + unsigned int i, cnt = gc->irq_cnt; - irq = PXA_IRQ(i); - irq_set_chip_and_handler(irq, &pxa_internal_irq_chip, - handle_level_irq); - irq_set_chip_data(irq, base); - set_irq_flags(irq, IRQF_VALID); - } + for (i = gc->irq_base; cnt; i++, cnt--) + *ipr++ = __raw_readl(IRQ_BASE + IPR(i)); } - - /* only unmasked interrupts kick us out of idle */ - __raw_writel(1, irq_base(0) + ICCR); - - pxa_internal_irq_chip.irq_set_wake = fn; - pxa_init_low_gpio_irq(fn); } -#ifdef CONFIG_PM -static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32]; -static unsigned long saved_ipr[MAX_INTERNAL_IRQS]; - -static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) +static void pxa_irq_resume(struct irq_data *d) { - int i; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 *ipr = gc->private; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { - void __iomem *base = irq_base(i); - - saved_icmr[i] = __raw_readl(base + ICMR); - __raw_writel(0, base + ICMR); - } + writel(gc->mask_cache, gc->reg_base + ICMR); + writel(0, gc->reg_base + ICLR); if (cpu_has_ipr()) { - for (i = 0; i < pxa_internal_irq_nr; i++) - saved_ipr[i] = __raw_readl(IRQ_BASE + IPR(i)); + unsigned int i, cnt = gc->irq_cnt; + + for (i = gc->irq_base; cnt; i++, cnt--) + __raw_writel(*ipr++, IRQ_BASE + IPR(i)); } - return 0; + __raw_writel(1, IRQ_BASE + ICCR); } -static int pxa_irq_resume(struct sys_device *dev) +static void __init +pxa_pm_init(int num, struct irq_chip_generic *gc, struct irq_chip_type *ct) { - int i; - - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { - void __iomem *base = irq_base(i); + ct->chip.irq_suspend = pxa_irq_suspend; + ct->chip.irq_resume = pxa_irq_resume; - __raw_writel(saved_icmr[i], base + ICMR); - __raw_writel(0, base + ICLR); - } - - if (cpu_has_ipr()) - for (i = 0; i < pxa_internal_irq_nr; i++) - __raw_writel(saved_ipr[i], IRQ_BASE + IPR(i)); - - __raw_writel(1, IRQ_BASE + ICCR); - return 0; + if (!cpu_has_ipr()) + return; + gc->private = kzalloc(num * sizeof(u32), GFP_KERNEL); } #else -#define pxa_irq_suspend NULL -#define pxa_irq_resume NULL +static inline void +pxa_pm_init(int num, struct irq_chip_generic *gc, struct irq_chip_type *ct) { } #endif -struct sysdev_class pxa_irq_sysclass = { - .name = "irq", - .suspend = pxa_irq_suspend, - .resume = pxa_irq_resume, -}; - -static int __init pxa_irq_init(void) +void __init pxa_init_irq(int irq_nr, set_wake_t fn) { - return sysdev_class_register(&pxa_irq_sysclass); -} + int i, n; + + for (n = 0; n < irq_nr; n += 32) { + void __iomem *base = irq_base(n >> 5); + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + int cnt = n + 32 <= irq_nr ? 32 : irq_nr % 32; -core_initcall(pxa_irq_init); + __raw_writel(0, base + ICMR); /* disable all IRQs */ + __raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */ + + /* initialize interrupt priority ? */ + if (cpu_has_ipr()) { + for (i = n; i < n + cnt; i++) + __raw_writel(i | IPR_VALID, IRQ_BASE + IPR(i)); + } + + gc = irq_alloc_generic_chip("SC", 2, PXA_IRQ(n), base, + handle_level_irq); + ct = gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_wake = fn; + ct->regs.mask = ICMR; + + irq_setup_generic_chip(gc, IRQ_MSK(cnt), + IRQ_NOREQUEST | IRQ_NOPROBE, 0); + pxa_pm_init(cnt, gc, ct); + pxa_init_low_gpio_irq(gc); + } + + /* only unmasked interrupts kick us out of idle */ + __raw_writel(1, irq_base(0) + ICCR); +}