xref: /openbmc/linux/arch/arm/mach-pxa/irq.c (revision a58fbcd8)
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>
23a09e64fbSRussell King #include <mach/pxa-regs.h>
24a58fbcd8SEric Miao #include <mach/gpio.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include "generic.h"
271da177e4SLinus Torvalds 
28f6fb7af4Seric miao #define IRQ_BIT(n)	(((n) - PXA_IRQ(0)) & 0x1f)
29f6fb7af4Seric miao #define _ICMR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR))
30f6fb7af4Seric miao #define _ICLR(n)	(*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR))
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /*
331da177e4SLinus Torvalds  * This is for peripheral IRQs internal to the PXA chip.
341da177e4SLinus Torvalds  */
351da177e4SLinus Torvalds 
36f6fb7af4Seric miao static int pxa_internal_irq_nr;
37f6fb7af4Seric miao 
38f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq)
391da177e4SLinus Torvalds {
40f6fb7af4Seric miao 	_ICMR(irq) &= ~(1 << IRQ_BIT(irq));
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds 
43f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq)
441da177e4SLinus Torvalds {
45f6fb7af4Seric miao 	_ICMR(irq) |= 1 << IRQ_BIT(irq);
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
48f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = {
4938c677cbSDavid Brownell 	.name		= "SC",
50f6fb7af4Seric miao 	.ack		= pxa_mask_irq,
51f6fb7af4Seric miao 	.mask		= pxa_mask_irq,
52f6fb7af4Seric miao 	.unmask		= pxa_unmask_irq,
531da177e4SLinus Torvalds };
541da177e4SLinus Torvalds 
55a58fbcd8SEric Miao /*
56a58fbcd8SEric Miao  * GPIO IRQs for GPIO 0 and 1
57a58fbcd8SEric Miao  */
58a58fbcd8SEric Miao static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
59a58fbcd8SEric Miao {
60a58fbcd8SEric Miao 	int gpio = irq - IRQ_GPIO0;
61a58fbcd8SEric Miao 
62a58fbcd8SEric Miao 	if (__gpio_is_occupied(gpio)) {
63a58fbcd8SEric Miao 		pr_err("%s failed: GPIO is configured\n", __func__);
64a58fbcd8SEric Miao 		return -EINVAL;
65a58fbcd8SEric Miao 	}
66a58fbcd8SEric Miao 
67a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_RISING)
68a58fbcd8SEric Miao 		GRER0 |= GPIO_bit(gpio);
69a58fbcd8SEric Miao 	else
70a58fbcd8SEric Miao 		GRER0 &= ~GPIO_bit(gpio);
71a58fbcd8SEric Miao 
72a58fbcd8SEric Miao 	if (type & IRQ_TYPE_EDGE_FALLING)
73a58fbcd8SEric Miao 		GFER0 |= GPIO_bit(gpio);
74a58fbcd8SEric Miao 	else
75a58fbcd8SEric Miao 		GFER0 &= ~GPIO_bit(gpio);
76a58fbcd8SEric Miao 
77a58fbcd8SEric Miao 	return 0;
78a58fbcd8SEric Miao }
79a58fbcd8SEric Miao 
80a58fbcd8SEric Miao static void pxa_ack_low_gpio(unsigned int irq)
81a58fbcd8SEric Miao {
82a58fbcd8SEric Miao 	GEDR0 = (1 << (irq - IRQ_GPIO0));
83a58fbcd8SEric Miao }
84a58fbcd8SEric Miao 
85a58fbcd8SEric Miao static void pxa_mask_low_gpio(unsigned int irq)
86a58fbcd8SEric Miao {
87a58fbcd8SEric Miao 	ICMR &= ~(1 << (irq - PXA_IRQ(0)));
88a58fbcd8SEric Miao }
89a58fbcd8SEric Miao 
90a58fbcd8SEric Miao static void pxa_unmask_low_gpio(unsigned int irq)
91a58fbcd8SEric Miao {
92a58fbcd8SEric Miao 	ICMR |= 1 << (irq - PXA_IRQ(0));
93a58fbcd8SEric Miao }
94a58fbcd8SEric Miao 
95a58fbcd8SEric Miao static struct irq_chip pxa_low_gpio_chip = {
96a58fbcd8SEric Miao 	.name		= "GPIO-l",
97a58fbcd8SEric Miao 	.ack		= pxa_ack_low_gpio,
98a58fbcd8SEric Miao 	.mask		= pxa_mask_low_gpio,
99a58fbcd8SEric Miao 	.unmask		= pxa_unmask_low_gpio,
100a58fbcd8SEric Miao 	.set_type	= pxa_set_low_gpio_type,
101a58fbcd8SEric Miao };
102a58fbcd8SEric Miao 
103a58fbcd8SEric Miao static void __init pxa_init_low_gpio_irq(set_wake_t fn)
104a58fbcd8SEric Miao {
105a58fbcd8SEric Miao 	int irq;
106a58fbcd8SEric Miao 
107a58fbcd8SEric Miao 	/* clear edge detection on GPIO 0 and 1 */
108a58fbcd8SEric Miao 	GFER0 &= ~0x3;
109a58fbcd8SEric Miao 	GRER0 &= ~0x3;
110a58fbcd8SEric Miao 	GEDR0 = 0x3;
111a58fbcd8SEric Miao 
112a58fbcd8SEric Miao 	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
113a58fbcd8SEric Miao 		set_irq_chip(irq, &pxa_low_gpio_chip);
114a58fbcd8SEric Miao 		set_irq_handler(irq, handle_edge_irq);
115a58fbcd8SEric Miao 		set_irq_flags(irq, IRQF_VALID);
116a58fbcd8SEric Miao 	}
117a58fbcd8SEric Miao 
118a58fbcd8SEric Miao 	pxa_low_gpio_chip.set_wake = fn;
119a58fbcd8SEric Miao }
120a58fbcd8SEric Miao 
121b9e25aceSeric miao void __init pxa_init_irq(int irq_nr, set_wake_t fn)
12253665a50SEric Miao {
12353665a50SEric Miao 	int irq;
12453665a50SEric Miao 
125f6fb7af4Seric miao 	pxa_internal_irq_nr = irq_nr;
12653665a50SEric Miao 
12757a7a62eSMarc Zyngier 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq += 32) {
128f6fb7af4Seric miao 		_ICMR(irq) = 0;	/* disable all IRQs */
129f6fb7af4Seric miao 		_ICLR(irq) = 0;	/* all IRQs are IRQ, not FIQ */
130f6fb7af4Seric miao 	}
13153665a50SEric Miao 
13253665a50SEric Miao 	/* only unmasked interrupts kick us out of idle */
13353665a50SEric Miao 	ICCR = 1;
13453665a50SEric Miao 
135f6fb7af4Seric miao 	for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) {
136f6fb7af4Seric miao 		set_irq_chip(irq, &pxa_internal_irq_chip);
13753665a50SEric Miao 		set_irq_handler(irq, handle_level_irq);
13853665a50SEric Miao 		set_irq_flags(irq, IRQF_VALID);
13953665a50SEric Miao 	}
14053665a50SEric Miao 
141b9e25aceSeric miao 	pxa_internal_irq_chip.set_wake = fn;
142a58fbcd8SEric Miao 	pxa_init_low_gpio_irq(fn);
143c95530c7Seric miao }
144c0165504Seric miao 
145c0165504Seric miao #ifdef CONFIG_PM
146c0165504Seric miao static unsigned long saved_icmr[2];
147c0165504Seric miao 
148c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
149c0165504Seric miao {
150f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
151f6fb7af4Seric miao 
152f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
153f6fb7af4Seric miao 		saved_icmr[i] = _ICMR(irq);
154f6fb7af4Seric miao 		_ICMR(irq) = 0;
155c0165504Seric miao 	}
156c0165504Seric miao 
157c0165504Seric miao 	return 0;
158c0165504Seric miao }
159c0165504Seric miao 
160c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev)
161c0165504Seric miao {
162f6fb7af4Seric miao 	int i, irq = PXA_IRQ(0);
163f6fb7af4Seric miao 
164f6fb7af4Seric miao 	for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) {
165f6fb7af4Seric miao 		_ICMR(irq) = saved_icmr[i];
166f6fb7af4Seric miao 		_ICLR(irq) = 0;
167c0165504Seric miao 	}
168c0165504Seric miao 
169f6fb7af4Seric miao 	ICCR = 1;
170c0165504Seric miao 	return 0;
171c0165504Seric miao }
172c0165504Seric miao #else
173c0165504Seric miao #define pxa_irq_suspend		NULL
174c0165504Seric miao #define pxa_irq_resume		NULL
175c0165504Seric miao #endif
176c0165504Seric miao 
177c0165504Seric miao struct sysdev_class pxa_irq_sysclass = {
178c0165504Seric miao 	.name		= "irq",
179c0165504Seric miao 	.suspend	= pxa_irq_suspend,
180c0165504Seric miao 	.resume		= pxa_irq_resume,
181c0165504Seric miao };
182c0165504Seric miao 
183c0165504Seric miao static int __init pxa_irq_init(void)
184c0165504Seric miao {
185c0165504Seric miao 	return sysdev_class_register(&pxa_irq_sysclass);
186c0165504Seric miao }
187c0165504Seric miao 
188c0165504Seric miao core_initcall(pxa_irq_init);
189