1 /* 2 * linux/arch/arm/mach-pxa/irq.c 3 * 4 * Generic PXA IRQ handling 5 * 6 * Author: Nicolas Pitre 7 * Created: Jun 15, 2001 8 * Copyright: MontaVista Software Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/init.h> 16 #include <linux/module.h> 17 #include <linux/interrupt.h> 18 #include <linux/sysdev.h> 19 20 #include <asm/hardware.h> 21 #include <asm/irq.h> 22 #include <asm/mach/irq.h> 23 #include <asm/arch/pxa-regs.h> 24 25 #include "generic.h" 26 27 #define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f) 28 #define _ICMR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR)) 29 #define _ICLR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR)) 30 31 /* 32 * This is for peripheral IRQs internal to the PXA chip. 33 */ 34 35 static int pxa_internal_irq_nr; 36 37 static void pxa_mask_irq(unsigned int irq) 38 { 39 _ICMR(irq) &= ~(1 << IRQ_BIT(irq)); 40 } 41 42 static void pxa_unmask_irq(unsigned int irq) 43 { 44 _ICMR(irq) |= 1 << IRQ_BIT(irq); 45 } 46 47 static struct irq_chip pxa_internal_irq_chip = { 48 .name = "SC", 49 .ack = pxa_mask_irq, 50 .mask = pxa_mask_irq, 51 .unmask = pxa_unmask_irq, 52 }; 53 54 void __init pxa_init_irq(int irq_nr) 55 { 56 int irq; 57 58 pxa_internal_irq_nr = irq_nr; 59 60 for (irq = 0; irq < irq_nr; irq += 32) { 61 _ICMR(irq) = 0; /* disable all IRQs */ 62 _ICLR(irq) = 0; /* all IRQs are IRQ, not FIQ */ 63 } 64 65 /* only unmasked interrupts kick us out of idle */ 66 ICCR = 1; 67 68 for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) { 69 set_irq_chip(irq, &pxa_internal_irq_chip); 70 set_irq_handler(irq, handle_level_irq); 71 set_irq_flags(irq, IRQF_VALID); 72 } 73 } 74 75 void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) 76 { 77 pxa_internal_irq_chip.set_wake = set_wake; 78 pxa_init_gpio_set_wake(set_wake); 79 } 80 81 #ifdef CONFIG_PM 82 static unsigned long saved_icmr[2]; 83 84 static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) 85 { 86 int i, irq = PXA_IRQ(0); 87 88 for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 89 saved_icmr[i] = _ICMR(irq); 90 _ICMR(irq) = 0; 91 } 92 93 return 0; 94 } 95 96 static int pxa_irq_resume(struct sys_device *dev) 97 { 98 int i, irq = PXA_IRQ(0); 99 100 for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 101 _ICMR(irq) = saved_icmr[i]; 102 _ICLR(irq) = 0; 103 } 104 105 ICCR = 1; 106 return 0; 107 } 108 #else 109 #define pxa_irq_suspend NULL 110 #define pxa_irq_resume NULL 111 #endif 112 113 struct sysdev_class pxa_irq_sysclass = { 114 .name = "irq", 115 .suspend = pxa_irq_suspend, 116 .resume = pxa_irq_resume, 117 }; 118 119 static int __init pxa_irq_init(void) 120 { 121 return sysdev_class_register(&pxa_irq_sysclass); 122 } 123 124 core_initcall(pxa_irq_init); 125