| /* | 
 |  *  linux/arch/arm/mach-pxa/irq.c | 
 |  * | 
 |  *  Generic PXA IRQ handling | 
 |  * | 
 |  *  Author:	Nicolas Pitre | 
 |  *  Created:	Jun 15, 2001 | 
 |  *  Copyright:	MontaVista Software Inc. | 
 |  * | 
 |  *  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 | 
 |  *  published by the Free Software Foundation. | 
 |  */ | 
 |  | 
 | #include <linux/init.h> | 
 | #include <linux/module.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/sysdev.h> | 
 |  | 
 | #include <asm/hardware.h> | 
 | #include <asm/irq.h> | 
 | #include <asm/mach/irq.h> | 
 | #include <asm/arch/pxa-regs.h> | 
 | #include <asm/arch/pxa2xx-gpio.h> | 
 |  | 
 | #include "generic.h" | 
 |  | 
 | #define IRQ_BIT(n)	(((n) - PXA_IRQ(0)) & 0x1f) | 
 | #define _ICMR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR)) | 
 | #define _ICLR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR)) | 
 |  | 
 | /* | 
 |  * This is for peripheral IRQs internal to the PXA chip. | 
 |  */ | 
 |  | 
 | static int pxa_internal_irq_nr; | 
 |  | 
 | static void pxa_mask_irq(unsigned int irq) | 
 | { | 
 | 	_ICMR(irq) &= ~(1 << IRQ_BIT(irq)); | 
 | } | 
 |  | 
 | static void pxa_unmask_irq(unsigned int irq) | 
 | { | 
 | 	_ICMR(irq) |= 1 << IRQ_BIT(irq); | 
 | } | 
 |  | 
 | static struct irq_chip pxa_internal_irq_chip = { | 
 | 	.name		= "SC", | 
 | 	.ack		= pxa_mask_irq, | 
 | 	.mask		= pxa_mask_irq, | 
 | 	.unmask		= pxa_unmask_irq, | 
 | }; | 
 |  | 
 | void __init pxa_init_irq(int irq_nr, set_wake_t fn) | 
 | { | 
 | 	int irq; | 
 |  | 
 | 	pxa_internal_irq_nr = irq_nr; | 
 |  | 
 | 	for (irq = 0; irq < irq_nr; irq += 32) { | 
 | 		_ICMR(irq) = 0;	/* disable all IRQs */ | 
 | 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */ | 
 | 	} | 
 |  | 
 | 	/* only unmasked interrupts kick us out of idle */ | 
 | 	ICCR = 1; | 
 |  | 
 | 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) { | 
 | 		set_irq_chip(irq, &pxa_internal_irq_chip); | 
 | 		set_irq_handler(irq, handle_level_irq); | 
 | 		set_irq_flags(irq, IRQF_VALID); | 
 | 	} | 
 |  | 
 | 	pxa_internal_irq_chip.set_wake = fn; | 
 | } | 
 |  | 
 | #ifdef CONFIG_PM | 
 | static unsigned long saved_icmr[2]; | 
 |  | 
 | static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) | 
 | { | 
 | 	int i, irq = PXA_IRQ(0); | 
 |  | 
 | 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { | 
 | 		saved_icmr[i] = _ICMR(irq); | 
 | 		_ICMR(irq) = 0; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int pxa_irq_resume(struct sys_device *dev) | 
 | { | 
 | 	int i, irq = PXA_IRQ(0); | 
 |  | 
 | 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { | 
 | 		_ICMR(irq) = saved_icmr[i]; | 
 | 		_ICLR(irq) = 0; | 
 | 	} | 
 |  | 
 | 	ICCR = 1; | 
 | 	return 0; | 
 | } | 
 | #else | 
 | #define pxa_irq_suspend		NULL | 
 | #define pxa_irq_resume		NULL | 
 | #endif | 
 |  | 
 | struct sysdev_class pxa_irq_sysclass = { | 
 | 	.name		= "irq", | 
 | 	.suspend	= pxa_irq_suspend, | 
 | 	.resume		= pxa_irq_resume, | 
 | }; | 
 |  | 
 | static int __init pxa_irq_init(void) | 
 | { | 
 | 	return sysdev_class_register(&pxa_irq_sysclass); | 
 | } | 
 |  | 
 | core_initcall(pxa_irq_init); |