xref: /openbmc/linux/arch/arm/mach-pxa/irq.c (revision f6fb7af4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/arm/mach-pxa/irq.c
31da177e4SLinus Torvalds  *
4e3630db1Seric miao  *  Generic PXA IRQ handling
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  Author:	Nicolas Pitre
71da177e4SLinus Torvalds  *  Created:	Jun 15, 2001
81da177e4SLinus Torvalds  *  Copyright:	MontaVista Software Inc.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *  This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds  *  it under the terms of the GNU General Public License version 2 as
121da177e4SLinus Torvalds  *  published by the Free Software Foundation.
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/init.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/interrupt.h>
18c0165504Seric miao #include <linux/sysdev.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <asm/hardware.h>
211da177e4SLinus Torvalds #include <asm/irq.h>
221da177e4SLinus Torvalds #include <asm/mach/irq.h>
231da177e4SLinus Torvalds #include <asm/arch/pxa-regs.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include "generic.h"
261da177e4SLinus Torvalds 
27f6fb7af4Seric miao #define IRQ_BIT(n)	(((n) - PXA_IRQ(0)) & 0x1f)
28f6fb7af4Seric miao #define _ICMR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR))
29f6fb7af4Seric miao #define _ICLR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR))
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds /*
321da177e4SLinus Torvalds  * This is for peripheral IRQs internal to the PXA chip.
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds 
35f6fb7af4Seric miao static int pxa_internal_irq_nr;
36f6fb7af4Seric miao 
37f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq)
381da177e4SLinus Torvalds {
39f6fb7af4Seric miao 	_ICMR(irq) &= ~(1 << IRQ_BIT(irq));
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds 
42f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq)
431da177e4SLinus Torvalds {
44f6fb7af4Seric miao 	_ICMR(irq) |= 1 << IRQ_BIT(irq);
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds 
47f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = {
4838c677cbSDavid Brownell 	.name		= "SC",
49f6fb7af4Seric miao 	.ack		= pxa_mask_irq,
50f6fb7af4Seric miao 	.mask		= pxa_mask_irq,
51f6fb7af4Seric miao 	.unmask		= pxa_unmask_irq,
521da177e4SLinus Torvalds };
531da177e4SLinus Torvalds 
54f6fb7af4Seric miao void __init pxa_init_irq(int irq_nr)
5553665a50SEric Miao {
5653665a50SEric Miao 	int irq;
5753665a50SEric Miao 
58f6fb7af4Seric miao 	pxa_internal_irq_nr = irq_nr;
5953665a50SEric Miao 
60f6fb7af4Seric miao 	for (irq = 0; irq < irq_nr; irq += 32) {
61f6fb7af4Seric miao 		_ICMR(irq) = 0;	/* disable all IRQs */
62f6fb7af4Seric miao 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */
63f6fb7af4Seric miao 	}
6453665a50SEric Miao 
6553665a50SEric Miao 	/* only unmasked interrupts kick us out of idle */
6653665a50SEric Miao 	ICCR = 1;
6753665a50SEric Miao 
68f6fb7af4Seric miao 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) {
69f6fb7af4Seric miao 		set_irq_chip(irq, &pxa_internal_irq_chip);
7053665a50SEric Miao 		set_irq_handler(irq, handle_level_irq);
7153665a50SEric Miao 		set_irq_flags(irq, IRQF_VALID);
7253665a50SEric Miao 	}
7353665a50SEric Miao }
7453665a50SEric Miao 
75c95530c7Seric miao void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
76c95530c7Seric miao {
77f6fb7af4Seric miao 	pxa_internal_irq_chip.set_wake = set_wake;
78a7bf4dbaSeric miao 	pxa_init_gpio_set_wake(set_wake);
79c95530c7Seric miao }
80c0165504Seric miao 
81c0165504Seric miao #ifdef CONFIG_PM
82c0165504Seric miao static unsigned long saved_icmr[2];
83c0165504Seric miao 
84c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
85c0165504Seric miao {
86f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
87f6fb7af4Seric miao 
88f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
89f6fb7af4Seric miao 		saved_icmr[i] = _ICMR(irq);
90f6fb7af4Seric miao 		_ICMR(irq) = 0;
91c0165504Seric miao 	}
92c0165504Seric miao 
93c0165504Seric miao 	return 0;
94c0165504Seric miao }
95c0165504Seric miao 
96c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev)
97c0165504Seric miao {
98f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
99f6fb7af4Seric miao 
100f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
101f6fb7af4Seric miao 		_ICMR(irq) = saved_icmr[i];
102f6fb7af4Seric miao 		_ICLR(irq) = 0;
103c0165504Seric miao 	}
104c0165504Seric miao 
105f6fb7af4Seric miao 	ICCR = 1;
106c0165504Seric miao 	return 0;
107c0165504Seric miao }
108c0165504Seric miao #else
109c0165504Seric miao #define pxa_irq_suspend		NULL
110c0165504Seric miao #define pxa_irq_resume		NULL
111c0165504Seric miao #endif
112c0165504Seric miao 
113c0165504Seric miao struct sysdev_class pxa_irq_sysclass = {
114c0165504Seric miao 	.name		= "irq",
115c0165504Seric miao 	.suspend	= pxa_irq_suspend,
116c0165504Seric miao 	.resume		= pxa_irq_resume,
117c0165504Seric miao };
118c0165504Seric miao 
119c0165504Seric miao static int __init pxa_irq_init(void)
120c0165504Seric miao {
121c0165504Seric miao 	return sysdev_class_register(&pxa_irq_sysclass);
122c0165504Seric miao }
123c0165504Seric miao 
124c0165504Seric miao core_initcall(pxa_irq_init);
125