diff options
Diffstat (limited to 'arch/arm/mach-s3c2410/irq.c')
-rw-r--r-- | arch/arm/mach-s3c2410/irq.c | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c new file mode 100644 index 000000000000..b668c48f4399 --- /dev/null +++ b/arch/arm/mach-s3c2410/irq.c | |||
@@ -0,0 +1,966 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/irq.c | ||
2 | * | ||
3 | * Copyright (c) 2003,2004 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | * Changelog: | ||
21 | * | ||
22 | * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> | ||
23 | * Fixed compile warnings | ||
24 | * | ||
25 | * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> | ||
26 | * Fixed s3c_extirq_type | ||
27 | * | ||
28 | * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> | ||
29 | * Addition of ADC/TC demux | ||
30 | * | ||
31 | * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> | ||
32 | * Fix for set_irq_type() on low EINT numbers | ||
33 | * | ||
34 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
35 | * Tidy up KF's patch and sort out new release | ||
36 | * | ||
37 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
38 | * Add support for power management controls | ||
39 | * | ||
40 | * 04-Nov-2004 Ben Dooks | ||
41 | * Fix standard IRQ wake for EINT0..4 and RTC | ||
42 | * | ||
43 | * 22-Feb-2004 Ben Dooks | ||
44 | * Fixed edge-triggering on ADC IRQ | ||
45 | */ | ||
46 | |||
47 | #include <linux/init.h> | ||
48 | #include <linux/module.h> | ||
49 | #include <linux/interrupt.h> | ||
50 | #include <linux/ioport.h> | ||
51 | #include <linux/ptrace.h> | ||
52 | #include <linux/sysdev.h> | ||
53 | |||
54 | #include <asm/hardware.h> | ||
55 | #include <asm/irq.h> | ||
56 | #include <asm/io.h> | ||
57 | |||
58 | #include <asm/mach/irq.h> | ||
59 | |||
60 | #include <asm/arch/regs-irq.h> | ||
61 | #include <asm/arch/regs-gpio.h> | ||
62 | |||
63 | #include "cpu.h" | ||
64 | #include "pm.h" | ||
65 | |||
66 | #define irqdbf(x...) | ||
67 | #define irqdbf2(x...) | ||
68 | |||
69 | #define EXTINT_OFF (IRQ_EINT4 - 4) | ||
70 | |||
71 | /* wakeup irq control */ | ||
72 | |||
73 | #ifdef CONFIG_PM | ||
74 | |||
75 | /* state for IRQs over sleep */ | ||
76 | |||
77 | /* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources | ||
78 | * | ||
79 | * set bit to 1 in allow bitfield to enable the wakeup settings on it | ||
80 | */ | ||
81 | |||
82 | unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; | ||
83 | unsigned long s3c_irqwake_intmask = 0xffffffffL; | ||
84 | unsigned long s3c_irqwake_eintallow = 0x0000fff0L; | ||
85 | unsigned long s3c_irqwake_eintmask = 0xffffffffL; | ||
86 | |||
87 | static int | ||
88 | s3c_irq_wake(unsigned int irqno, unsigned int state) | ||
89 | { | ||
90 | unsigned long irqbit = 1 << (irqno - IRQ_EINT0); | ||
91 | |||
92 | if (!(s3c_irqwake_intallow & irqbit)) | ||
93 | return -ENOENT; | ||
94 | |||
95 | printk(KERN_INFO "wake %s for irq %d\n", | ||
96 | state ? "enabled" : "disabled", irqno); | ||
97 | |||
98 | if (!state) | ||
99 | s3c_irqwake_intmask |= irqbit; | ||
100 | else | ||
101 | s3c_irqwake_intmask &= ~irqbit; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int | ||
107 | s3c_irqext_wake(unsigned int irqno, unsigned int state) | ||
108 | { | ||
109 | unsigned long bit = 1L << (irqno - EXTINT_OFF); | ||
110 | |||
111 | if (!(s3c_irqwake_eintallow & bit)) | ||
112 | return -ENOENT; | ||
113 | |||
114 | printk(KERN_INFO "wake %s for irq %d\n", | ||
115 | state ? "enabled" : "disabled", irqno); | ||
116 | |||
117 | if (!state) | ||
118 | s3c_irqwake_eintmask |= bit; | ||
119 | else | ||
120 | s3c_irqwake_eintmask &= ~bit; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | #else | ||
126 | #define s3c_irqext_wake NULL | ||
127 | #define s3c_irq_wake NULL | ||
128 | #endif | ||
129 | |||
130 | |||
131 | static void | ||
132 | s3c_irq_mask(unsigned int irqno) | ||
133 | { | ||
134 | unsigned long mask; | ||
135 | |||
136 | irqno -= IRQ_EINT0; | ||
137 | |||
138 | mask = __raw_readl(S3C2410_INTMSK); | ||
139 | mask |= 1UL << irqno; | ||
140 | __raw_writel(mask, S3C2410_INTMSK); | ||
141 | } | ||
142 | |||
143 | static inline void | ||
144 | s3c_irq_ack(unsigned int irqno) | ||
145 | { | ||
146 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
147 | |||
148 | __raw_writel(bitval, S3C2410_SRCPND); | ||
149 | __raw_writel(bitval, S3C2410_INTPND); | ||
150 | } | ||
151 | |||
152 | static inline void | ||
153 | s3c_irq_maskack(unsigned int irqno) | ||
154 | { | ||
155 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
156 | unsigned long mask; | ||
157 | |||
158 | mask = __raw_readl(S3C2410_INTMSK); | ||
159 | __raw_writel(mask|bitval, S3C2410_INTMSK); | ||
160 | |||
161 | __raw_writel(bitval, S3C2410_SRCPND); | ||
162 | __raw_writel(bitval, S3C2410_INTPND); | ||
163 | } | ||
164 | |||
165 | |||
166 | static void | ||
167 | s3c_irq_unmask(unsigned int irqno) | ||
168 | { | ||
169 | unsigned long mask; | ||
170 | |||
171 | if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) | ||
172 | irqdbf2("s3c_irq_unmask %d\n", irqno); | ||
173 | |||
174 | irqno -= IRQ_EINT0; | ||
175 | |||
176 | mask = __raw_readl(S3C2410_INTMSK); | ||
177 | mask &= ~(1UL << irqno); | ||
178 | __raw_writel(mask, S3C2410_INTMSK); | ||
179 | } | ||
180 | |||
181 | static struct irqchip s3c_irq_level_chip = { | ||
182 | .ack = s3c_irq_maskack, | ||
183 | .mask = s3c_irq_mask, | ||
184 | .unmask = s3c_irq_unmask, | ||
185 | .wake = s3c_irq_wake | ||
186 | }; | ||
187 | |||
188 | static struct irqchip s3c_irq_chip = { | ||
189 | .ack = s3c_irq_ack, | ||
190 | .mask = s3c_irq_mask, | ||
191 | .unmask = s3c_irq_unmask, | ||
192 | .wake = s3c_irq_wake | ||
193 | }; | ||
194 | |||
195 | /* S3C2410_EINTMASK | ||
196 | * S3C2410_EINTPEND | ||
197 | */ | ||
198 | |||
199 | static void | ||
200 | s3c_irqext_mask(unsigned int irqno) | ||
201 | { | ||
202 | unsigned long mask; | ||
203 | |||
204 | irqno -= EXTINT_OFF; | ||
205 | |||
206 | mask = __raw_readl(S3C2410_EINTMASK); | ||
207 | mask |= ( 1UL << irqno); | ||
208 | __raw_writel(mask, S3C2410_EINTMASK); | ||
209 | |||
210 | if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { | ||
211 | /* check to see if all need masking */ | ||
212 | |||
213 | if ((mask & (0xf << 4)) == (0xf << 4)) { | ||
214 | /* all masked, mask the parent */ | ||
215 | s3c_irq_mask(IRQ_EINT4t7); | ||
216 | } | ||
217 | } else { | ||
218 | /* todo: the same check as above for the rest of the irq regs...*/ | ||
219 | |||
220 | } | ||
221 | } | ||
222 | |||
223 | static void | ||
224 | s3c_irqext_ack(unsigned int irqno) | ||
225 | { | ||
226 | unsigned long req; | ||
227 | unsigned long bit; | ||
228 | unsigned long mask; | ||
229 | |||
230 | bit = 1UL << (irqno - EXTINT_OFF); | ||
231 | |||
232 | |||
233 | mask = __raw_readl(S3C2410_EINTMASK); | ||
234 | |||
235 | __raw_writel(bit, S3C2410_EINTPEND); | ||
236 | |||
237 | req = __raw_readl(S3C2410_EINTPEND); | ||
238 | req &= ~mask; | ||
239 | |||
240 | /* not sure if we should be acking the parent irq... */ | ||
241 | |||
242 | if (irqno <= IRQ_EINT7 ) { | ||
243 | if ((req & 0xf0) == 0) | ||
244 | s3c_irq_ack(IRQ_EINT4t7); | ||
245 | } else { | ||
246 | if ((req >> 8) == 0) | ||
247 | s3c_irq_ack(IRQ_EINT8t23); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static void | ||
252 | s3c_irqext_unmask(unsigned int irqno) | ||
253 | { | ||
254 | unsigned long mask; | ||
255 | |||
256 | irqno -= EXTINT_OFF; | ||
257 | |||
258 | mask = __raw_readl(S3C2410_EINTMASK); | ||
259 | mask &= ~( 1UL << irqno); | ||
260 | __raw_writel(mask, S3C2410_EINTMASK); | ||
261 | |||
262 | s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); | ||
263 | } | ||
264 | |||
265 | static int | ||
266 | s3c_irqext_type(unsigned int irq, unsigned int type) | ||
267 | { | ||
268 | void __iomem *extint_reg; | ||
269 | void __iomem *gpcon_reg; | ||
270 | unsigned long gpcon_offset, extint_offset; | ||
271 | unsigned long newvalue = 0, value; | ||
272 | |||
273 | if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) | ||
274 | { | ||
275 | gpcon_reg = S3C2410_GPFCON; | ||
276 | extint_reg = S3C2410_EXTINT0; | ||
277 | gpcon_offset = (irq - IRQ_EINT0) * 2; | ||
278 | extint_offset = (irq - IRQ_EINT0) * 4; | ||
279 | } | ||
280 | else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) | ||
281 | { | ||
282 | gpcon_reg = S3C2410_GPFCON; | ||
283 | extint_reg = S3C2410_EXTINT0; | ||
284 | gpcon_offset = (irq - (EXTINT_OFF)) * 2; | ||
285 | extint_offset = (irq - (EXTINT_OFF)) * 4; | ||
286 | } | ||
287 | else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) | ||
288 | { | ||
289 | gpcon_reg = S3C2410_GPGCON; | ||
290 | extint_reg = S3C2410_EXTINT1; | ||
291 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
292 | extint_offset = (irq - IRQ_EINT8) * 4; | ||
293 | } | ||
294 | else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) | ||
295 | { | ||
296 | gpcon_reg = S3C2410_GPGCON; | ||
297 | extint_reg = S3C2410_EXTINT2; | ||
298 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
299 | extint_offset = (irq - IRQ_EINT16) * 4; | ||
300 | } else | ||
301 | return -1; | ||
302 | |||
303 | /* Set the GPIO to external interrupt mode */ | ||
304 | value = __raw_readl(gpcon_reg); | ||
305 | value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); | ||
306 | __raw_writel(value, gpcon_reg); | ||
307 | |||
308 | /* Set the external interrupt to pointed trigger type */ | ||
309 | switch (type) | ||
310 | { | ||
311 | case IRQT_NOEDGE: | ||
312 | printk(KERN_WARNING "No edge setting!\n"); | ||
313 | break; | ||
314 | |||
315 | case IRQT_RISING: | ||
316 | newvalue = S3C2410_EXTINT_RISEEDGE; | ||
317 | break; | ||
318 | |||
319 | case IRQT_FALLING: | ||
320 | newvalue = S3C2410_EXTINT_FALLEDGE; | ||
321 | break; | ||
322 | |||
323 | case IRQT_BOTHEDGE: | ||
324 | newvalue = S3C2410_EXTINT_BOTHEDGE; | ||
325 | break; | ||
326 | |||
327 | case IRQT_LOW: | ||
328 | newvalue = S3C2410_EXTINT_LOWLEV; | ||
329 | break; | ||
330 | |||
331 | case IRQT_HIGH: | ||
332 | newvalue = S3C2410_EXTINT_HILEV; | ||
333 | break; | ||
334 | |||
335 | default: | ||
336 | printk(KERN_ERR "No such irq type %d", type); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | value = __raw_readl(extint_reg); | ||
341 | value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); | ||
342 | __raw_writel(value, extint_reg); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static struct irqchip s3c_irqext_chip = { | ||
348 | .mask = s3c_irqext_mask, | ||
349 | .unmask = s3c_irqext_unmask, | ||
350 | .ack = s3c_irqext_ack, | ||
351 | .type = s3c_irqext_type, | ||
352 | .wake = s3c_irqext_wake | ||
353 | }; | ||
354 | |||
355 | static struct irqchip s3c_irq_eint0t4 = { | ||
356 | .ack = s3c_irq_ack, | ||
357 | .mask = s3c_irq_mask, | ||
358 | .unmask = s3c_irq_unmask, | ||
359 | .wake = s3c_irq_wake, | ||
360 | .type = s3c_irqext_type, | ||
361 | }; | ||
362 | |||
363 | /* mask values for the parent registers for each of the interrupt types */ | ||
364 | |||
365 | #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) | ||
366 | #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) | ||
367 | #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) | ||
368 | #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) | ||
369 | #define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) | ||
370 | |||
371 | static inline void | ||
372 | s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit, | ||
373 | int subcheck) | ||
374 | { | ||
375 | unsigned long mask; | ||
376 | unsigned long submask; | ||
377 | |||
378 | submask = __raw_readl(S3C2410_INTSUBMSK); | ||
379 | mask = __raw_readl(S3C2410_INTMSK); | ||
380 | |||
381 | submask |= (1UL << (irqno - IRQ_S3CUART_RX0)); | ||
382 | |||
383 | /* check to see if we need to mask the parent IRQ */ | ||
384 | |||
385 | if ((submask & subcheck) == subcheck) { | ||
386 | __raw_writel(mask | parentbit, S3C2410_INTMSK); | ||
387 | } | ||
388 | |||
389 | /* write back masks */ | ||
390 | __raw_writel(submask, S3C2410_INTSUBMSK); | ||
391 | |||
392 | } | ||
393 | |||
394 | static inline void | ||
395 | s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit) | ||
396 | { | ||
397 | unsigned long mask; | ||
398 | unsigned long submask; | ||
399 | |||
400 | submask = __raw_readl(S3C2410_INTSUBMSK); | ||
401 | mask = __raw_readl(S3C2410_INTMSK); | ||
402 | |||
403 | submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0)); | ||
404 | mask &= ~parentbit; | ||
405 | |||
406 | /* write back masks */ | ||
407 | __raw_writel(submask, S3C2410_INTSUBMSK); | ||
408 | __raw_writel(mask, S3C2410_INTMSK); | ||
409 | } | ||
410 | |||
411 | |||
412 | static inline void | ||
413 | s3c_irqsub_maskack(unsigned int irqno, unsigned int parentmask, unsigned int group) | ||
414 | { | ||
415 | unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0); | ||
416 | |||
417 | s3c_irqsub_mask(irqno, parentmask, group); | ||
418 | |||
419 | __raw_writel(bit, S3C2410_SUBSRCPND); | ||
420 | |||
421 | /* only ack parent if we've got all the irqs (seems we must | ||
422 | * ack, all and hope that the irq system retriggers ok when | ||
423 | * the interrupt goes off again) | ||
424 | */ | ||
425 | |||
426 | if (1) { | ||
427 | __raw_writel(parentmask, S3C2410_SRCPND); | ||
428 | __raw_writel(parentmask, S3C2410_INTPND); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static inline void | ||
433 | s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group) | ||
434 | { | ||
435 | unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0); | ||
436 | |||
437 | __raw_writel(bit, S3C2410_SUBSRCPND); | ||
438 | |||
439 | /* only ack parent if we've got all the irqs (seems we must | ||
440 | * ack, all and hope that the irq system retriggers ok when | ||
441 | * the interrupt goes off again) | ||
442 | */ | ||
443 | |||
444 | if (1) { | ||
445 | __raw_writel(parentmask, S3C2410_SRCPND); | ||
446 | __raw_writel(parentmask, S3C2410_INTPND); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | /* UART0 */ | ||
451 | |||
452 | static void | ||
453 | s3c_irq_uart0_mask(unsigned int irqno) | ||
454 | { | ||
455 | s3c_irqsub_mask(irqno, INTMSK_UART0, 7); | ||
456 | } | ||
457 | |||
458 | static void | ||
459 | s3c_irq_uart0_unmask(unsigned int irqno) | ||
460 | { | ||
461 | s3c_irqsub_unmask(irqno, INTMSK_UART0); | ||
462 | } | ||
463 | |||
464 | static void | ||
465 | s3c_irq_uart0_ack(unsigned int irqno) | ||
466 | { | ||
467 | s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); | ||
468 | } | ||
469 | |||
470 | static struct irqchip s3c_irq_uart0 = { | ||
471 | .mask = s3c_irq_uart0_mask, | ||
472 | .unmask = s3c_irq_uart0_unmask, | ||
473 | .ack = s3c_irq_uart0_ack, | ||
474 | }; | ||
475 | |||
476 | /* UART1 */ | ||
477 | |||
478 | static void | ||
479 | s3c_irq_uart1_mask(unsigned int irqno) | ||
480 | { | ||
481 | s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); | ||
482 | } | ||
483 | |||
484 | static void | ||
485 | s3c_irq_uart1_unmask(unsigned int irqno) | ||
486 | { | ||
487 | s3c_irqsub_unmask(irqno, INTMSK_UART1); | ||
488 | } | ||
489 | |||
490 | static void | ||
491 | s3c_irq_uart1_ack(unsigned int irqno) | ||
492 | { | ||
493 | s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); | ||
494 | } | ||
495 | |||
496 | static struct irqchip s3c_irq_uart1 = { | ||
497 | .mask = s3c_irq_uart1_mask, | ||
498 | .unmask = s3c_irq_uart1_unmask, | ||
499 | .ack = s3c_irq_uart1_ack, | ||
500 | }; | ||
501 | |||
502 | /* UART2 */ | ||
503 | |||
504 | static void | ||
505 | s3c_irq_uart2_mask(unsigned int irqno) | ||
506 | { | ||
507 | s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); | ||
508 | } | ||
509 | |||
510 | static void | ||
511 | s3c_irq_uart2_unmask(unsigned int irqno) | ||
512 | { | ||
513 | s3c_irqsub_unmask(irqno, INTMSK_UART2); | ||
514 | } | ||
515 | |||
516 | static void | ||
517 | s3c_irq_uart2_ack(unsigned int irqno) | ||
518 | { | ||
519 | s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); | ||
520 | } | ||
521 | |||
522 | static struct irqchip s3c_irq_uart2 = { | ||
523 | .mask = s3c_irq_uart2_mask, | ||
524 | .unmask = s3c_irq_uart2_unmask, | ||
525 | .ack = s3c_irq_uart2_ack, | ||
526 | }; | ||
527 | |||
528 | /* ADC and Touchscreen */ | ||
529 | |||
530 | static void | ||
531 | s3c_irq_adc_mask(unsigned int irqno) | ||
532 | { | ||
533 | s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
534 | } | ||
535 | |||
536 | static void | ||
537 | s3c_irq_adc_unmask(unsigned int irqno) | ||
538 | { | ||
539 | s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); | ||
540 | } | ||
541 | |||
542 | static void | ||
543 | s3c_irq_adc_ack(unsigned int irqno) | ||
544 | { | ||
545 | s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
546 | } | ||
547 | |||
548 | static struct irqchip s3c_irq_adc = { | ||
549 | .mask = s3c_irq_adc_mask, | ||
550 | .unmask = s3c_irq_adc_unmask, | ||
551 | .ack = s3c_irq_adc_ack, | ||
552 | }; | ||
553 | |||
554 | /* irq demux for adc */ | ||
555 | static void s3c_irq_demux_adc(unsigned int irq, | ||
556 | struct irqdesc *desc, | ||
557 | struct pt_regs *regs) | ||
558 | { | ||
559 | unsigned int subsrc, submsk; | ||
560 | unsigned int offset = 9; | ||
561 | struct irqdesc *mydesc; | ||
562 | |||
563 | /* read the current pending interrupts, and the mask | ||
564 | * for what it is available */ | ||
565 | |||
566 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
567 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
568 | |||
569 | subsrc &= ~submsk; | ||
570 | subsrc >>= offset; | ||
571 | subsrc &= 3; | ||
572 | |||
573 | if (subsrc != 0) { | ||
574 | if (subsrc & 1) { | ||
575 | mydesc = irq_desc + IRQ_TC; | ||
576 | mydesc->handle( IRQ_TC, mydesc, regs); | ||
577 | } | ||
578 | if (subsrc & 2) { | ||
579 | mydesc = irq_desc + IRQ_ADC; | ||
580 | mydesc->handle(IRQ_ADC, mydesc, regs); | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static void s3c_irq_demux_uart(unsigned int start, | ||
586 | struct pt_regs *regs) | ||
587 | { | ||
588 | unsigned int subsrc, submsk; | ||
589 | unsigned int offset = start - IRQ_S3CUART_RX0; | ||
590 | struct irqdesc *desc; | ||
591 | |||
592 | /* read the current pending interrupts, and the mask | ||
593 | * for what it is available */ | ||
594 | |||
595 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
596 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
597 | |||
598 | irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", | ||
599 | start, offset, subsrc, submsk); | ||
600 | |||
601 | subsrc &= ~submsk; | ||
602 | subsrc >>= offset; | ||
603 | subsrc &= 7; | ||
604 | |||
605 | if (subsrc != 0) { | ||
606 | desc = irq_desc + start; | ||
607 | |||
608 | if (subsrc & 1) | ||
609 | desc->handle(start, desc, regs); | ||
610 | |||
611 | desc++; | ||
612 | |||
613 | if (subsrc & 2) | ||
614 | desc->handle(start+1, desc, regs); | ||
615 | |||
616 | desc++; | ||
617 | |||
618 | if (subsrc & 4) | ||
619 | desc->handle(start+2, desc, regs); | ||
620 | } | ||
621 | } | ||
622 | |||
623 | /* uart demux entry points */ | ||
624 | |||
625 | static void | ||
626 | s3c_irq_demux_uart0(unsigned int irq, | ||
627 | struct irqdesc *desc, | ||
628 | struct pt_regs *regs) | ||
629 | { | ||
630 | irq = irq; | ||
631 | s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs); | ||
632 | } | ||
633 | |||
634 | static void | ||
635 | s3c_irq_demux_uart1(unsigned int irq, | ||
636 | struct irqdesc *desc, | ||
637 | struct pt_regs *regs) | ||
638 | { | ||
639 | irq = irq; | ||
640 | s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs); | ||
641 | } | ||
642 | |||
643 | static void | ||
644 | s3c_irq_demux_uart2(unsigned int irq, | ||
645 | struct irqdesc *desc, | ||
646 | struct pt_regs *regs) | ||
647 | { | ||
648 | irq = irq; | ||
649 | s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); | ||
650 | } | ||
651 | |||
652 | |||
653 | /* s3c24xx_init_irq | ||
654 | * | ||
655 | * Initialise S3C2410 IRQ system | ||
656 | */ | ||
657 | |||
658 | void __init s3c24xx_init_irq(void) | ||
659 | { | ||
660 | unsigned long pend; | ||
661 | unsigned long last; | ||
662 | int irqno; | ||
663 | int i; | ||
664 | |||
665 | irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); | ||
666 | |||
667 | /* first, clear all interrupts pending... */ | ||
668 | |||
669 | last = 0; | ||
670 | for (i = 0; i < 4; i++) { | ||
671 | pend = __raw_readl(S3C2410_EINTPEND); | ||
672 | |||
673 | if (pend == 0 || pend == last) | ||
674 | break; | ||
675 | |||
676 | __raw_writel(pend, S3C2410_EINTPEND); | ||
677 | printk("irq: clearing pending ext status %08x\n", (int)pend); | ||
678 | last = pend; | ||
679 | } | ||
680 | |||
681 | last = 0; | ||
682 | for (i = 0; i < 4; i++) { | ||
683 | pend = __raw_readl(S3C2410_INTPND); | ||
684 | |||
685 | if (pend == 0 || pend == last) | ||
686 | break; | ||
687 | |||
688 | __raw_writel(pend, S3C2410_SRCPND); | ||
689 | __raw_writel(pend, S3C2410_INTPND); | ||
690 | printk("irq: clearing pending status %08x\n", (int)pend); | ||
691 | last = pend; | ||
692 | } | ||
693 | |||
694 | last = 0; | ||
695 | for (i = 0; i < 4; i++) { | ||
696 | pend = __raw_readl(S3C2410_SUBSRCPND); | ||
697 | |||
698 | if (pend == 0 || pend == last) | ||
699 | break; | ||
700 | |||
701 | printk("irq: clearing subpending status %08x\n", (int)pend); | ||
702 | __raw_writel(pend, S3C2410_SUBSRCPND); | ||
703 | last = pend; | ||
704 | } | ||
705 | |||
706 | /* register the main interrupts */ | ||
707 | |||
708 | irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); | ||
709 | |||
710 | for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { | ||
711 | /* set all the s3c2410 internal irqs */ | ||
712 | |||
713 | switch (irqno) { | ||
714 | /* deal with the special IRQs (cascaded) */ | ||
715 | |||
716 | case IRQ_UART0: | ||
717 | case IRQ_UART1: | ||
718 | case IRQ_UART2: | ||
719 | case IRQ_LCD: | ||
720 | case IRQ_ADCPARENT: | ||
721 | set_irq_chip(irqno, &s3c_irq_level_chip); | ||
722 | set_irq_handler(irqno, do_level_IRQ); | ||
723 | break; | ||
724 | |||
725 | case IRQ_RESERVED6: | ||
726 | case IRQ_RESERVED24: | ||
727 | /* no IRQ here */ | ||
728 | break; | ||
729 | |||
730 | default: | ||
731 | //irqdbf("registering irq %d (s3c irq)\n", irqno); | ||
732 | set_irq_chip(irqno, &s3c_irq_chip); | ||
733 | set_irq_handler(irqno, do_edge_IRQ); | ||
734 | set_irq_flags(irqno, IRQF_VALID); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | /* setup the cascade irq handlers */ | ||
739 | |||
740 | set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); | ||
741 | set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); | ||
742 | set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); | ||
743 | set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); | ||
744 | |||
745 | |||
746 | /* external interrupts */ | ||
747 | |||
748 | for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { | ||
749 | irqdbf("registering irq %d (ext int)\n", irqno); | ||
750 | set_irq_chip(irqno, &s3c_irq_eint0t4); | ||
751 | set_irq_handler(irqno, do_edge_IRQ); | ||
752 | set_irq_flags(irqno, IRQF_VALID); | ||
753 | } | ||
754 | |||
755 | for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { | ||
756 | irqdbf("registering irq %d (extended s3c irq)\n", irqno); | ||
757 | set_irq_chip(irqno, &s3c_irqext_chip); | ||
758 | set_irq_handler(irqno, do_edge_IRQ); | ||
759 | set_irq_flags(irqno, IRQF_VALID); | ||
760 | } | ||
761 | |||
762 | /* register the uart interrupts */ | ||
763 | |||
764 | irqdbf("s3c2410: registering external interrupts\n"); | ||
765 | |||
766 | for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { | ||
767 | irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); | ||
768 | set_irq_chip(irqno, &s3c_irq_uart0); | ||
769 | set_irq_handler(irqno, do_level_IRQ); | ||
770 | set_irq_flags(irqno, IRQF_VALID); | ||
771 | } | ||
772 | |||
773 | for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { | ||
774 | irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); | ||
775 | set_irq_chip(irqno, &s3c_irq_uart1); | ||
776 | set_irq_handler(irqno, do_level_IRQ); | ||
777 | set_irq_flags(irqno, IRQF_VALID); | ||
778 | } | ||
779 | |||
780 | for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { | ||
781 | irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); | ||
782 | set_irq_chip(irqno, &s3c_irq_uart2); | ||
783 | set_irq_handler(irqno, do_level_IRQ); | ||
784 | set_irq_flags(irqno, IRQF_VALID); | ||
785 | } | ||
786 | |||
787 | for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { | ||
788 | irqdbf("registering irq %d (s3c adc irq)\n", irqno); | ||
789 | set_irq_chip(irqno, &s3c_irq_adc); | ||
790 | set_irq_handler(irqno, do_edge_IRQ); | ||
791 | set_irq_flags(irqno, IRQF_VALID); | ||
792 | } | ||
793 | |||
794 | irqdbf("s3c2410: registered interrupt handlers\n"); | ||
795 | } | ||
796 | |||
797 | /* s3c2440 irq code | ||
798 | */ | ||
799 | |||
800 | #ifdef CONFIG_CPU_S3C2440 | ||
801 | |||
802 | /* WDT/AC97 */ | ||
803 | |||
804 | static void s3c_irq_demux_wdtac97(unsigned int irq, | ||
805 | struct irqdesc *desc, | ||
806 | struct pt_regs *regs) | ||
807 | { | ||
808 | unsigned int subsrc, submsk; | ||
809 | struct irqdesc *mydesc; | ||
810 | |||
811 | /* read the current pending interrupts, and the mask | ||
812 | * for what it is available */ | ||
813 | |||
814 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
815 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
816 | |||
817 | subsrc &= ~submsk; | ||
818 | subsrc >>= 13; | ||
819 | subsrc &= 3; | ||
820 | |||
821 | if (subsrc != 0) { | ||
822 | if (subsrc & 1) { | ||
823 | mydesc = irq_desc + IRQ_S3C2440_WDT; | ||
824 | mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); | ||
825 | } | ||
826 | if (subsrc & 2) { | ||
827 | mydesc = irq_desc + IRQ_S3C2440_AC97; | ||
828 | mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); | ||
829 | } | ||
830 | } | ||
831 | } | ||
832 | |||
833 | |||
834 | #define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) | ||
835 | |||
836 | static void | ||
837 | s3c_irq_wdtac97_mask(unsigned int irqno) | ||
838 | { | ||
839 | s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13); | ||
840 | } | ||
841 | |||
842 | static void | ||
843 | s3c_irq_wdtac97_unmask(unsigned int irqno) | ||
844 | { | ||
845 | s3c_irqsub_unmask(irqno, INTMSK_WDT); | ||
846 | } | ||
847 | |||
848 | static void | ||
849 | s3c_irq_wdtac97_ack(unsigned int irqno) | ||
850 | { | ||
851 | s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13); | ||
852 | } | ||
853 | |||
854 | static struct irqchip s3c_irq_wdtac97 = { | ||
855 | .mask = s3c_irq_wdtac97_mask, | ||
856 | .unmask = s3c_irq_wdtac97_unmask, | ||
857 | .ack = s3c_irq_wdtac97_ack, | ||
858 | }; | ||
859 | |||
860 | /* camera irq */ | ||
861 | |||
862 | static void s3c_irq_demux_cam(unsigned int irq, | ||
863 | struct irqdesc *desc, | ||
864 | struct pt_regs *regs) | ||
865 | { | ||
866 | unsigned int subsrc, submsk; | ||
867 | struct irqdesc *mydesc; | ||
868 | |||
869 | /* read the current pending interrupts, and the mask | ||
870 | * for what it is available */ | ||
871 | |||
872 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
873 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
874 | |||
875 | subsrc &= ~submsk; | ||
876 | subsrc >>= 11; | ||
877 | subsrc &= 3; | ||
878 | |||
879 | if (subsrc != 0) { | ||
880 | if (subsrc & 1) { | ||
881 | mydesc = irq_desc + IRQ_S3C2440_CAM_C; | ||
882 | mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs); | ||
883 | } | ||
884 | if (subsrc & 2) { | ||
885 | mydesc = irq_desc + IRQ_S3C2440_CAM_P; | ||
886 | mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs); | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | |||
891 | #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) | ||
892 | |||
893 | static void | ||
894 | s3c_irq_cam_mask(unsigned int irqno) | ||
895 | { | ||
896 | s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11); | ||
897 | } | ||
898 | |||
899 | static void | ||
900 | s3c_irq_cam_unmask(unsigned int irqno) | ||
901 | { | ||
902 | s3c_irqsub_unmask(irqno, INTMSK_CAM); | ||
903 | } | ||
904 | |||
905 | static void | ||
906 | s3c_irq_cam_ack(unsigned int irqno) | ||
907 | { | ||
908 | s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11); | ||
909 | } | ||
910 | |||
911 | static struct irqchip s3c_irq_cam = { | ||
912 | .mask = s3c_irq_cam_mask, | ||
913 | .unmask = s3c_irq_cam_unmask, | ||
914 | .ack = s3c_irq_cam_ack, | ||
915 | }; | ||
916 | |||
917 | static int s3c2440_irq_add(struct sys_device *sysdev) | ||
918 | { | ||
919 | unsigned int irqno; | ||
920 | |||
921 | printk("S3C2440: IRQ Support\n"); | ||
922 | |||
923 | set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip); | ||
924 | set_irq_handler(IRQ_NFCON, do_level_IRQ); | ||
925 | set_irq_flags(IRQ_NFCON, IRQF_VALID); | ||
926 | |||
927 | /* add new chained handler for wdt, ac7 */ | ||
928 | |||
929 | set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); | ||
930 | set_irq_handler(IRQ_WDT, do_level_IRQ); | ||
931 | set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); | ||
932 | |||
933 | for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { | ||
934 | set_irq_chip(irqno, &s3c_irq_wdtac97); | ||
935 | set_irq_handler(irqno, do_level_IRQ); | ||
936 | set_irq_flags(irqno, IRQF_VALID); | ||
937 | } | ||
938 | |||
939 | /* add chained handler for camera */ | ||
940 | |||
941 | set_irq_chip(IRQ_CAM, &s3c_irq_level_chip); | ||
942 | set_irq_handler(IRQ_CAM, do_level_IRQ); | ||
943 | set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam); | ||
944 | |||
945 | for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { | ||
946 | set_irq_chip(irqno, &s3c_irq_cam); | ||
947 | set_irq_handler(irqno, do_level_IRQ); | ||
948 | set_irq_flags(irqno, IRQF_VALID); | ||
949 | } | ||
950 | |||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | static struct sysdev_driver s3c2440_irq_driver = { | ||
955 | .add = s3c2440_irq_add, | ||
956 | }; | ||
957 | |||
958 | static int s3c24xx_irq_driver(void) | ||
959 | { | ||
960 | return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver); | ||
961 | } | ||
962 | |||
963 | arch_initcall(s3c24xx_irq_driver); | ||
964 | |||
965 | #endif /* CONFIG_CPU_S3C2440 */ | ||
966 | |||