diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-pxa/irq.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/mach-pxa/irq.c')
-rw-r--r-- | arch/arm/mach-pxa/irq.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c new file mode 100644 index 000000000000..f3cac43124a5 --- /dev/null +++ b/arch/arm/mach-pxa/irq.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/irq.c | ||
3 | * | ||
4 | * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Jun 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | |||
20 | #include <asm/hardware.h> | ||
21 | #include <asm/irq.h> | ||
22 | #include <asm/mach/irq.h> | ||
23 | #include <asm/arch/pxa-regs.h> | ||
24 | |||
25 | #include "generic.h" | ||
26 | |||
27 | |||
28 | /* | ||
29 | * This is for peripheral IRQs internal to the PXA chip. | ||
30 | */ | ||
31 | |||
32 | static void pxa_mask_low_irq(unsigned int irq) | ||
33 | { | ||
34 | ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); | ||
35 | } | ||
36 | |||
37 | static void pxa_unmask_low_irq(unsigned int irq) | ||
38 | { | ||
39 | ICMR |= (1 << (irq + PXA_IRQ_SKIP)); | ||
40 | } | ||
41 | |||
42 | static struct irqchip pxa_internal_chip_low = { | ||
43 | .ack = pxa_mask_low_irq, | ||
44 | .mask = pxa_mask_low_irq, | ||
45 | .unmask = pxa_unmask_low_irq, | ||
46 | }; | ||
47 | |||
48 | #if PXA_INTERNAL_IRQS > 32 | ||
49 | |||
50 | /* | ||
51 | * This is for the second set of internal IRQs as found on the PXA27x. | ||
52 | */ | ||
53 | |||
54 | static void pxa_mask_high_irq(unsigned int irq) | ||
55 | { | ||
56 | ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); | ||
57 | } | ||
58 | |||
59 | static void pxa_unmask_high_irq(unsigned int irq) | ||
60 | { | ||
61 | ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); | ||
62 | } | ||
63 | |||
64 | static struct irqchip pxa_internal_chip_high = { | ||
65 | .ack = pxa_mask_high_irq, | ||
66 | .mask = pxa_mask_high_irq, | ||
67 | .unmask = pxa_unmask_high_irq, | ||
68 | }; | ||
69 | |||
70 | #endif | ||
71 | |||
72 | /* | ||
73 | * PXA GPIO edge detection for IRQs: | ||
74 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | ||
75 | * Use this instead of directly setting GRER/GFER. | ||
76 | */ | ||
77 | |||
78 | static long GPIO_IRQ_rising_edge[4]; | ||
79 | static long GPIO_IRQ_falling_edge[4]; | ||
80 | static long GPIO_IRQ_mask[4]; | ||
81 | |||
82 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) | ||
83 | { | ||
84 | int gpio, idx; | ||
85 | |||
86 | gpio = IRQ_TO_GPIO(irq); | ||
87 | idx = gpio >> 5; | ||
88 | |||
89 | if (type == IRQT_PROBE) { | ||
90 | /* Don't mess with enabled GPIOs using preconfigured edges or | ||
91 | GPIOs set to alternate function during probe */ | ||
92 | if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & | ||
93 | GPIO_bit(gpio)) | ||
94 | return 0; | ||
95 | if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) | ||
96 | return 0; | ||
97 | type = __IRQT_RISEDGE | __IRQT_FALEDGE; | ||
98 | } | ||
99 | |||
100 | /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */ | ||
101 | |||
102 | pxa_gpio_mode(gpio | GPIO_IN); | ||
103 | |||
104 | if (type & __IRQT_RISEDGE) { | ||
105 | /* printk("rising "); */ | ||
106 | __set_bit (gpio, GPIO_IRQ_rising_edge); | ||
107 | } else | ||
108 | __clear_bit (gpio, GPIO_IRQ_rising_edge); | ||
109 | |||
110 | if (type & __IRQT_FALEDGE) { | ||
111 | /* printk("falling "); */ | ||
112 | __set_bit (gpio, GPIO_IRQ_falling_edge); | ||
113 | } else | ||
114 | __clear_bit (gpio, GPIO_IRQ_falling_edge); | ||
115 | |||
116 | /* printk("edges\n"); */ | ||
117 | |||
118 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | ||
119 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * GPIO IRQs must be acknowledged. This is for GPIO 0 and 1. | ||
125 | */ | ||
126 | |||
127 | static void pxa_ack_low_gpio(unsigned int irq) | ||
128 | { | ||
129 | GEDR0 = (1 << (irq - IRQ_GPIO0)); | ||
130 | } | ||
131 | |||
132 | static struct irqchip pxa_low_gpio_chip = { | ||
133 | .ack = pxa_ack_low_gpio, | ||
134 | .mask = pxa_mask_low_irq, | ||
135 | .unmask = pxa_unmask_low_irq, | ||
136 | .type = pxa_gpio_irq_type, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Demux handler for GPIO>=2 edge detect interrupts | ||
141 | */ | ||
142 | |||
143 | static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, | ||
144 | struct pt_regs *regs) | ||
145 | { | ||
146 | unsigned int mask; | ||
147 | int loop; | ||
148 | |||
149 | do { | ||
150 | loop = 0; | ||
151 | |||
152 | mask = GEDR0 & ~3; | ||
153 | if (mask) { | ||
154 | GEDR0 = mask; | ||
155 | irq = IRQ_GPIO(2); | ||
156 | desc = irq_desc + irq; | ||
157 | mask >>= 2; | ||
158 | do { | ||
159 | if (mask & 1) | ||
160 | desc->handle(irq, desc, regs); | ||
161 | irq++; | ||
162 | desc++; | ||
163 | mask >>= 1; | ||
164 | } while (mask); | ||
165 | loop = 1; | ||
166 | } | ||
167 | |||
168 | mask = GEDR1; | ||
169 | if (mask) { | ||
170 | GEDR1 = mask; | ||
171 | irq = IRQ_GPIO(32); | ||
172 | desc = irq_desc + irq; | ||
173 | do { | ||
174 | if (mask & 1) | ||
175 | desc->handle(irq, desc, regs); | ||
176 | irq++; | ||
177 | desc++; | ||
178 | mask >>= 1; | ||
179 | } while (mask); | ||
180 | loop = 1; | ||
181 | } | ||
182 | |||
183 | mask = GEDR2; | ||
184 | if (mask) { | ||
185 | GEDR2 = mask; | ||
186 | irq = IRQ_GPIO(64); | ||
187 | desc = irq_desc + irq; | ||
188 | do { | ||
189 | if (mask & 1) | ||
190 | desc->handle(irq, desc, regs); | ||
191 | irq++; | ||
192 | desc++; | ||
193 | mask >>= 1; | ||
194 | } while (mask); | ||
195 | loop = 1; | ||
196 | } | ||
197 | |||
198 | #if PXA_LAST_GPIO >= 96 | ||
199 | mask = GEDR3; | ||
200 | if (mask) { | ||
201 | GEDR3 = mask; | ||
202 | irq = IRQ_GPIO(96); | ||
203 | desc = irq_desc + irq; | ||
204 | do { | ||
205 | if (mask & 1) | ||
206 | desc->handle(irq, desc, regs); | ||
207 | irq++; | ||
208 | desc++; | ||
209 | mask >>= 1; | ||
210 | } while (mask); | ||
211 | loop = 1; | ||
212 | } | ||
213 | #endif | ||
214 | } while (loop); | ||
215 | } | ||
216 | |||
217 | static void pxa_ack_muxed_gpio(unsigned int irq) | ||
218 | { | ||
219 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
220 | GEDR(gpio) = GPIO_bit(gpio); | ||
221 | } | ||
222 | |||
223 | static void pxa_mask_muxed_gpio(unsigned int irq) | ||
224 | { | ||
225 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
226 | __clear_bit(gpio, GPIO_IRQ_mask); | ||
227 | GRER(gpio) &= ~GPIO_bit(gpio); | ||
228 | GFER(gpio) &= ~GPIO_bit(gpio); | ||
229 | } | ||
230 | |||
231 | static void pxa_unmask_muxed_gpio(unsigned int irq) | ||
232 | { | ||
233 | int gpio = irq - IRQ_GPIO(2) + 2; | ||
234 | int idx = gpio >> 5; | ||
235 | __set_bit(gpio, GPIO_IRQ_mask); | ||
236 | GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | ||
237 | GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | ||
238 | } | ||
239 | |||
240 | static struct irqchip pxa_muxed_gpio_chip = { | ||
241 | .ack = pxa_ack_muxed_gpio, | ||
242 | .mask = pxa_mask_muxed_gpio, | ||
243 | .unmask = pxa_unmask_muxed_gpio, | ||
244 | .type = pxa_gpio_irq_type, | ||
245 | }; | ||
246 | |||
247 | |||
248 | void __init pxa_init_irq(void) | ||
249 | { | ||
250 | int irq; | ||
251 | |||
252 | /* disable all IRQs */ | ||
253 | ICMR = 0; | ||
254 | |||
255 | /* all IRQs are IRQ, not FIQ */ | ||
256 | ICLR = 0; | ||
257 | |||
258 | /* clear all GPIO edge detects */ | ||
259 | GFER0 = 0; | ||
260 | GFER1 = 0; | ||
261 | GFER2 = 0; | ||
262 | GRER0 = 0; | ||
263 | GRER1 = 0; | ||
264 | GRER2 = 0; | ||
265 | GEDR0 = GEDR0; | ||
266 | GEDR1 = GEDR1; | ||
267 | GEDR2 = GEDR2; | ||
268 | |||
269 | #ifdef CONFIG_PXA27x | ||
270 | /* And similarly for the extra regs on the PXA27x */ | ||
271 | ICMR2 = 0; | ||
272 | ICLR2 = 0; | ||
273 | GFER3 = 0; | ||
274 | GRER3 = 0; | ||
275 | GEDR3 = GEDR3; | ||
276 | #endif | ||
277 | |||
278 | /* only unmasked interrupts kick us out of idle */ | ||
279 | ICCR = 1; | ||
280 | |||
281 | /* GPIO 0 and 1 must have their mask bit always set */ | ||
282 | GPIO_IRQ_mask[0] = 3; | ||
283 | |||
284 | for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { | ||
285 | set_irq_chip(irq, &pxa_internal_chip_low); | ||
286 | set_irq_handler(irq, do_level_IRQ); | ||
287 | set_irq_flags(irq, IRQF_VALID); | ||
288 | } | ||
289 | |||
290 | #if PXA_INTERNAL_IRQS > 32 | ||
291 | for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { | ||
292 | set_irq_chip(irq, &pxa_internal_chip_high); | ||
293 | set_irq_handler(irq, do_level_IRQ); | ||
294 | set_irq_flags(irq, IRQF_VALID); | ||
295 | } | ||
296 | #endif | ||
297 | |||
298 | for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { | ||
299 | set_irq_chip(irq, &pxa_low_gpio_chip); | ||
300 | set_irq_handler(irq, do_edge_IRQ); | ||
301 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
302 | } | ||
303 | |||
304 | for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { | ||
305 | set_irq_chip(irq, &pxa_muxed_gpio_chip); | ||
306 | set_irq_handler(irq, do_edge_IRQ); | ||
307 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
308 | } | ||
309 | |||
310 | /* Install handler for GPIO>=2 edge detect interrupts */ | ||
311 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); | ||
312 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); | ||
313 | } | ||