xref: /openbmc/linux/arch/arm/mach-pxa/irq.c (revision bb71bdd3)
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 
40bb71bdd3SHaojian Zhuang static inline int cpu_has_ipr(void)
41bb71bdd3SHaojian Zhuang {
42bb71bdd3SHaojian Zhuang 	return !cpu_is_pxa25x();
43bb71bdd3SHaojian Zhuang }
44bb71bdd3SHaojian Zhuang 
45f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq)
461da177e4SLinus Torvalds {
47f6fb7af4Seric miao 	_ICMR(irq) &= ~(1 << IRQ_BIT(irq));
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
50f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq)
511da177e4SLinus Torvalds {
52f6fb7af4Seric miao 	_ICMR(irq) |= 1 << IRQ_BIT(irq);
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
55f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = {
5638c677cbSDavid Brownell 	.name		= "SC",
57f6fb7af4Seric miao 	.ack		= pxa_mask_irq,
58f6fb7af4Seric miao 	.mask		= pxa_mask_irq,
59f6fb7af4Seric miao 	.unmask		= pxa_unmask_irq,
601da177e4SLinus Torvalds };
611da177e4SLinus Torvalds 
62a58fbcd8SEric Miao /*
63a58fbcd8SEric Miao  * GPIO IRQs for GPIO 0 and 1
64a58fbcd8SEric Miao  */
65a58fbcd8SEric Miao static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
66a58fbcd8SEric Miao {
67a58fbcd8SEric Miao 	int gpio = irq - IRQ_GPIO0;
68a58fbcd8SEric Miao 
69a58fbcd8SEric Miao 	if (__gpio_is_occupied(gpio)) {
70a58fbcd8SEric Miao 		pr_err("%s failed: GPIO is configured\n", __func__);
71a58fbcd8SEric Miao 		return -EINVAL;
72a58fbcd8SEric Miao 	}
73a58fbcd8SEric Miao 
74a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_RISING)
75a58fbcd8SEric Miao 		GRER0 |= GPIO_bit(gpio);
76a58fbcd8SEric Miao 	else
77a58fbcd8SEric Miao 		GRER0 &= ~GPIO_bit(gpio);
78a58fbcd8SEric Miao 
79a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_FALLING)
80a58fbcd8SEric Miao 		GFER0 |= GPIO_bit(gpio);
81a58fbcd8SEric Miao 	else
82a58fbcd8SEric Miao 		GFER0 &= ~GPIO_bit(gpio);
83a58fbcd8SEric Miao 
84a58fbcd8SEric Miao 	return 0;
85a58fbcd8SEric Miao }
86a58fbcd8SEric Miao 
87a58fbcd8SEric Miao static void pxa_ack_low_gpio(unsigned int irq)
88a58fbcd8SEric Miao {
89a58fbcd8SEric Miao 	GEDR0 = (1 << (irq - IRQ_GPIO0));
90a58fbcd8SEric Miao }
91a58fbcd8SEric Miao 
92a58fbcd8SEric Miao static void pxa_mask_low_gpio(unsigned int irq)
93a58fbcd8SEric Miao {
94a58fbcd8SEric Miao 	ICMR &= ~(1 << (irq - PXA_IRQ(0)));
95a58fbcd8SEric Miao }
96a58fbcd8SEric Miao 
97a58fbcd8SEric Miao static void pxa_unmask_low_gpio(unsigned int irq)
98a58fbcd8SEric Miao {
99a58fbcd8SEric Miao 	ICMR |= 1 << (irq - PXA_IRQ(0));
100a58fbcd8SEric Miao }
101a58fbcd8SEric Miao 
102a58fbcd8SEric Miao static struct irq_chip pxa_low_gpio_chip = {
103a58fbcd8SEric Miao 	.name		= "GPIO-l",
104a58fbcd8SEric Miao 	.ack		= pxa_ack_low_gpio,
105a58fbcd8SEric Miao 	.mask		= pxa_mask_low_gpio,
106a58fbcd8SEric Miao 	.unmask		= pxa_unmask_low_gpio,
107a58fbcd8SEric Miao 	.set_type	= pxa_set_low_gpio_type,
108a58fbcd8SEric Miao };
109a58fbcd8SEric Miao 
110a58fbcd8SEric Miao static void __init pxa_init_low_gpio_irq(set_wake_t fn)
111a58fbcd8SEric Miao {
112a58fbcd8SEric Miao 	int irq;
113a58fbcd8SEric Miao 
114a58fbcd8SEric Miao 	/* clear edge detection on GPIO 0 and 1 */
115a58fbcd8SEric Miao 	GFER0 &= ~0x3;
116a58fbcd8SEric Miao 	GRER0 &= ~0x3;
117a58fbcd8SEric Miao 	GEDR0 = 0x3;
118a58fbcd8SEric Miao 
119a58fbcd8SEric Miao 	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
120a58fbcd8SEric Miao 		set_irq_chip(irq, &pxa_low_gpio_chip);
121a58fbcd8SEric Miao 		set_irq_handler(irq, handle_edge_irq);
122a58fbcd8SEric Miao 		set_irq_flags(irq, IRQF_VALID);
123a58fbcd8SEric Miao 	}
124a58fbcd8SEric Miao 
125a58fbcd8SEric Miao 	pxa_low_gpio_chip.set_wake = fn;
126a58fbcd8SEric Miao }
127a58fbcd8SEric Miao 
128b9e25aceSeric miao void __init pxa_init_irq(int irq_nr, set_wake_t fn)
12953665a50SEric Miao {
130d2c37068SHaojian Zhuang 	int irq, i;
13153665a50SEric Miao 
132c482ae4dSHaojian Zhuang 	BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
133c482ae4dSHaojian Zhuang 
134f6fb7af4Seric miao 	pxa_internal_irq_nr = irq_nr;
13553665a50SEric Miao 
13657a7a62eSMarc Zyngier 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq += 32) {
137f6fb7af4Seric miao 		_ICMR(irq) = 0;	/* disable all IRQs */
138f6fb7af4Seric miao 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */
139f6fb7af4Seric miao 	}
14053665a50SEric Miao 
141d2c37068SHaojian Zhuang 	/* initialize interrupt priority */
142bb71bdd3SHaojian Zhuang 	if (cpu_has_ipr()) {
143d2c37068SHaojian Zhuang 		for (i = 0; i < irq_nr; i++)
144d2c37068SHaojian Zhuang 			IPR(i) = i | (1 << 31);
145d2c37068SHaojian Zhuang 	}
146d2c37068SHaojian Zhuang 
14753665a50SEric Miao 	/* only unmasked interrupts kick us out of idle */
14853665a50SEric Miao 	ICCR = 1;
14953665a50SEric Miao 
150f6fb7af4Seric miao 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) {
151f6fb7af4Seric miao 		set_irq_chip(irq, &pxa_internal_irq_chip);
15253665a50SEric Miao 		set_irq_handler(irq, handle_level_irq);
15353665a50SEric Miao 		set_irq_flags(irq, IRQF_VALID);
15453665a50SEric Miao 	}
15553665a50SEric Miao 
156b9e25aceSeric miao 	pxa_internal_irq_chip.set_wake = fn;
157a58fbcd8SEric Miao 	pxa_init_low_gpio_irq(fn);
158c95530c7Seric miao }
159c0165504Seric miao 
160c0165504Seric miao #ifdef CONFIG_PM
161c482ae4dSHaojian Zhuang static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
162c482ae4dSHaojian Zhuang static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
163c0165504Seric miao 
164c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
165c0165504Seric miao {
166f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
167f6fb7af4Seric miao 
168f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
169f6fb7af4Seric miao 		saved_icmr[i] = _ICMR(irq);
170f6fb7af4Seric miao 		_ICMR(irq) = 0;
171c0165504Seric miao 	}
172c70f5a60SEric Miao 
173bb71bdd3SHaojian Zhuang 	if (cpu_has_ipr()) {
174c482ae4dSHaojian Zhuang 		for (i = 0; i < pxa_internal_irq_nr; i++)
175c482ae4dSHaojian Zhuang 			saved_ipr[i] = IPR(i);
176c70f5a60SEric Miao 	}
177c0165504Seric miao 
178c0165504Seric miao 	return 0;
179c0165504Seric miao }
180c0165504Seric miao 
181c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev)
182c0165504Seric miao {
183f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
184f6fb7af4Seric miao 
185bb71bdd3SHaojian Zhuang 	if (cpu_has_ipr()) {
186c70f5a60SEric Miao 		for (i = 0; i < pxa_internal_irq_nr; i++)
187c70f5a60SEric Miao 			IPR(i) = saved_ipr[i];
188c70f5a60SEric Miao 	}
189c70f5a60SEric Miao 
190f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
191f6fb7af4Seric miao 		_ICMR(irq) = saved_icmr[i];
192f6fb7af4Seric miao 		_ICLR(irq) = 0;
193c0165504Seric miao 	}
194c0165504Seric miao 
195f6fb7af4Seric miao 	ICCR = 1;
196c0165504Seric miao 	return 0;
197c0165504Seric miao }
198c0165504Seric miao #else
199c0165504Seric miao #define pxa_irq_suspend		NULL
200c0165504Seric miao #define pxa_irq_resume		NULL
201c0165504Seric miao #endif
202c0165504Seric miao 
203c0165504Seric miao struct sysdev_class pxa_irq_sysclass = {
204c0165504Seric miao 	.name		= "irq",
205c0165504Seric miao 	.suspend	= pxa_irq_suspend,
206c0165504Seric miao 	.resume		= pxa_irq_resume,
207c0165504Seric miao };
208c0165504Seric miao 
209c0165504Seric miao static int __init pxa_irq_init(void)
210c0165504Seric miao {
211c0165504Seric miao 	return sysdev_class_register(&pxa_irq_sysclass);
212c0165504Seric miao }
213c0165504Seric miao 
214c0165504Seric miao core_initcall(pxa_irq_init);
215