xref: /openbmc/linux/arch/arm/mach-pxa/irq.c (revision c482ae4d)
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 
20a09e64fbSRussell King #include <mach/hardware.h>
211da177e4SLinus Torvalds #include <asm/irq.h>
221da177e4SLinus Torvalds #include <asm/mach/irq.h>
23a58fbcd8SEric Miao #include <mach/gpio.h>
245bf3df3fSEric Miao #include <mach/regs-intc.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include "generic.h"
271da177e4SLinus Torvalds 
28c482ae4dSHaojian Zhuang #define MAX_INTERNAL_IRQS	128
29c482ae4dSHaojian Zhuang 
30f6fb7af4Seric miao #define IRQ_BIT(n)	(((n) - PXA_IRQ(0)) & 0x1f)
31f6fb7af4Seric miao #define _ICMR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR))
32f6fb7af4Seric miao #define _ICLR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR))
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds /*
351da177e4SLinus Torvalds  * This is for peripheral IRQs internal to the PXA chip.
361da177e4SLinus Torvalds  */
371da177e4SLinus Torvalds 
38f6fb7af4Seric miao static int pxa_internal_irq_nr;
39f6fb7af4Seric miao 
40f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq)
411da177e4SLinus Torvalds {
42f6fb7af4Seric miao 	_ICMR(irq) &= ~(1 << IRQ_BIT(irq));
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds 
45f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq)
461da177e4SLinus Torvalds {
47f6fb7af4Seric miao 	_ICMR(irq) |= 1 << IRQ_BIT(irq);
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
50f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = {
5138c677cbSDavid Brownell 	.name		= "SC",
52f6fb7af4Seric miao 	.ack		= pxa_mask_irq,
53f6fb7af4Seric miao 	.mask		= pxa_mask_irq,
54f6fb7af4Seric miao 	.unmask		= pxa_unmask_irq,
551da177e4SLinus Torvalds };
561da177e4SLinus Torvalds 
57a58fbcd8SEric Miao /*
58a58fbcd8SEric Miao  * GPIO IRQs for GPIO 0 and 1
59a58fbcd8SEric Miao  */
60a58fbcd8SEric Miao static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
61a58fbcd8SEric Miao {
62a58fbcd8SEric Miao 	int gpio = irq - IRQ_GPIO0;
63a58fbcd8SEric Miao 
64a58fbcd8SEric Miao 	if (__gpio_is_occupied(gpio)) {
65a58fbcd8SEric Miao 		pr_err("%s failed: GPIO is configured\n", __func__);
66a58fbcd8SEric Miao 		return -EINVAL;
67a58fbcd8SEric Miao 	}
68a58fbcd8SEric Miao 
69a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_RISING)
70a58fbcd8SEric Miao 		GRER0 |= GPIO_bit(gpio);
71a58fbcd8SEric Miao 	else
72a58fbcd8SEric Miao 		GRER0 &= ~GPIO_bit(gpio);
73a58fbcd8SEric Miao 
74a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_FALLING)
75a58fbcd8SEric Miao 		GFER0 |= GPIO_bit(gpio);
76a58fbcd8SEric Miao 	else
77a58fbcd8SEric Miao 		GFER0 &= ~GPIO_bit(gpio);
78a58fbcd8SEric Miao 
79a58fbcd8SEric Miao 	return 0;
80a58fbcd8SEric Miao }
81a58fbcd8SEric Miao 
82a58fbcd8SEric Miao static void pxa_ack_low_gpio(unsigned int irq)
83a58fbcd8SEric Miao {
84a58fbcd8SEric Miao 	GEDR0 = (1 << (irq - IRQ_GPIO0));
85a58fbcd8SEric Miao }
86a58fbcd8SEric Miao 
87a58fbcd8SEric Miao static void pxa_mask_low_gpio(unsigned int irq)
88a58fbcd8SEric Miao {
89a58fbcd8SEric Miao 	ICMR &= ~(1 << (irq - PXA_IRQ(0)));
90a58fbcd8SEric Miao }
91a58fbcd8SEric Miao 
92a58fbcd8SEric Miao static void pxa_unmask_low_gpio(unsigned int irq)
93a58fbcd8SEric Miao {
94a58fbcd8SEric Miao 	ICMR |= 1 << (irq - PXA_IRQ(0));
95a58fbcd8SEric Miao }
96a58fbcd8SEric Miao 
97a58fbcd8SEric Miao static struct irq_chip pxa_low_gpio_chip = {
98a58fbcd8SEric Miao 	.name		= "GPIO-l",
99a58fbcd8SEric Miao 	.ack		= pxa_ack_low_gpio,
100a58fbcd8SEric Miao 	.mask		= pxa_mask_low_gpio,
101a58fbcd8SEric Miao 	.unmask		= pxa_unmask_low_gpio,
102a58fbcd8SEric Miao 	.set_type	= pxa_set_low_gpio_type,
103a58fbcd8SEric Miao };
104a58fbcd8SEric Miao 
105a58fbcd8SEric Miao static void __init pxa_init_low_gpio_irq(set_wake_t fn)
106a58fbcd8SEric Miao {
107a58fbcd8SEric Miao 	int irq;
108a58fbcd8SEric Miao 
109a58fbcd8SEric Miao 	/* clear edge detection on GPIO 0 and 1 */
110a58fbcd8SEric Miao 	GFER0 &= ~0x3;
111a58fbcd8SEric Miao 	GRER0 &= ~0x3;
112a58fbcd8SEric Miao 	GEDR0 = 0x3;
113a58fbcd8SEric Miao 
114a58fbcd8SEric Miao 	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
115a58fbcd8SEric Miao 		set_irq_chip(irq, &pxa_low_gpio_chip);
116a58fbcd8SEric Miao 		set_irq_handler(irq, handle_edge_irq);
117a58fbcd8SEric Miao 		set_irq_flags(irq, IRQF_VALID);
118a58fbcd8SEric Miao 	}
119a58fbcd8SEric Miao 
120a58fbcd8SEric Miao 	pxa_low_gpio_chip.set_wake = fn;
121a58fbcd8SEric Miao }
122a58fbcd8SEric Miao 
123b9e25aceSeric miao void __init pxa_init_irq(int irq_nr, set_wake_t fn)
12453665a50SEric Miao {
125d2c37068SHaojian Zhuang 	int irq, i;
12653665a50SEric Miao 
127c482ae4dSHaojian Zhuang 	BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
128c482ae4dSHaojian Zhuang 
129f6fb7af4Seric miao 	pxa_internal_irq_nr = irq_nr;
13053665a50SEric Miao 
13157a7a62eSMarc Zyngier 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq += 32) {
132f6fb7af4Seric miao 		_ICMR(irq) = 0;	/* disable all IRQs */
133f6fb7af4Seric miao 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */
134f6fb7af4Seric miao 	}
13553665a50SEric Miao 
136d2c37068SHaojian Zhuang 	/* initialize interrupt priority */
137d2c37068SHaojian Zhuang 	if (cpu_is_pxa27x() || cpu_is_pxa3xx()) {
138d2c37068SHaojian Zhuang 		for (i = 0; i < irq_nr; i++)
139d2c37068SHaojian Zhuang 			IPR(i) = i | (1 << 31);
140d2c37068SHaojian Zhuang 	}
141d2c37068SHaojian Zhuang 
14253665a50SEric Miao 	/* only unmasked interrupts kick us out of idle */
14353665a50SEric Miao 	ICCR = 1;
14453665a50SEric Miao 
145f6fb7af4Seric miao 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) {
146f6fb7af4Seric miao 		set_irq_chip(irq, &pxa_internal_irq_chip);
14753665a50SEric Miao 		set_irq_handler(irq, handle_level_irq);
14853665a50SEric Miao 		set_irq_flags(irq, IRQF_VALID);
14953665a50SEric Miao 	}
15053665a50SEric Miao 
151b9e25aceSeric miao 	pxa_internal_irq_chip.set_wake = fn;
152a58fbcd8SEric Miao 	pxa_init_low_gpio_irq(fn);
153c95530c7Seric miao }
154c0165504Seric miao 
155c0165504Seric miao #ifdef CONFIG_PM
156c482ae4dSHaojian Zhuang static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
157c482ae4dSHaojian Zhuang static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
158c0165504Seric miao 
159c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
160c0165504Seric miao {
161f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
162f6fb7af4Seric miao 
163f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
164f6fb7af4Seric miao 		saved_icmr[i] = _ICMR(irq);
165f6fb7af4Seric miao 		_ICMR(irq) = 0;
166c0165504Seric miao 	}
167c482ae4dSHaojian Zhuang 	for (i = 0; i < pxa_internal_irq_nr; i++)
168c482ae4dSHaojian Zhuang 		saved_ipr[i] = IPR(i);
169c0165504Seric miao 
170c0165504Seric miao 	return 0;
171c0165504Seric miao }
172c0165504Seric miao 
173c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev)
174c0165504Seric miao {
175f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
176f6fb7af4Seric miao 
177f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
178f6fb7af4Seric miao 		_ICMR(irq) = saved_icmr[i];
179f6fb7af4Seric miao 		_ICLR(irq) = 0;
180c0165504Seric miao 	}
181c482ae4dSHaojian Zhuang 	for (i = 0; i < pxa_internal_irq_nr; i++)
182c482ae4dSHaojian Zhuang 		IPR(i) = saved_ipr[i];
183c0165504Seric miao 
184f6fb7af4Seric miao 	ICCR = 1;
185c0165504Seric miao 	return 0;
186c0165504Seric miao }
187c0165504Seric miao #else
188c0165504Seric miao #define pxa_irq_suspend		NULL
189c0165504Seric miao #define pxa_irq_resume		NULL
190c0165504Seric miao #endif
191c0165504Seric miao 
192c0165504Seric miao struct sysdev_class pxa_irq_sysclass = {
193c0165504Seric miao 	.name		= "irq",
194c0165504Seric miao 	.suspend	= pxa_irq_suspend,
195c0165504Seric miao 	.resume		= pxa_irq_resume,
196c0165504Seric miao };
197c0165504Seric miao 
198c0165504Seric miao static int __init pxa_irq_init(void)
199c0165504Seric miao {
200c0165504Seric miao 	return sysdev_class_register(&pxa_irq_sysclass);
201c0165504Seric miao }
202c0165504Seric miao 
203c0165504Seric miao core_initcall(pxa_irq_init);
204