MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / arch / arm / mach-s3c2410 / irq.c
blob1951a0323f178b6a66effef6fedb80f93177588f
1 /* linux/arch/arm/mach-s3c2410/irq.c
3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
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.
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.
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
20 * Changelog:
22 * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
23 * Fixed compile warnings
25 * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
26 * Fixed s3c_extirq_type
28 * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
29 * Addition of ADC/TC demux
31 * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
32 * Fix for set_irq_type() on low EINT numbers
34 * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
35 * Tidy up KF's patch and sort out new release
39 #include <linux/init.h>
40 #include <linux/module.h>
41 #include <linux/interrupt.h>
42 #include <linux/ioport.h>
43 #include <linux/ptrace.h>
44 #include <linux/sysdev.h>
46 #include <asm/hardware.h>
47 #include <asm/irq.h>
48 #include <asm/io.h>
50 #include <asm/mach/irq.h>
52 #include <asm/arch/regs-irq.h>
53 #include <asm/arch/regs-gpio.h>
56 #define irqdbf(x...)
57 #define irqdbf2(x...)
59 static void
60 s3c_irq_mask(unsigned int irqno)
62 unsigned long mask;
64 irqno -= IRQ_EINT0;
66 mask = __raw_readl(S3C2410_INTMSK);
67 mask |= 1UL << irqno;
68 __raw_writel(mask, S3C2410_INTMSK);
71 static inline void
72 s3c_irq_ack(unsigned int irqno)
74 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
76 __raw_writel(bitval, S3C2410_SRCPND);
77 __raw_writel(bitval, S3C2410_INTPND);
80 static inline void
81 s3c_irq_maskack(unsigned int irqno)
83 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
84 unsigned long mask;
86 mask = __raw_readl(S3C2410_INTMSK);
87 __raw_writel(mask|bitval, S3C2410_INTMSK);
89 __raw_writel(bitval, S3C2410_SRCPND);
90 __raw_writel(bitval, S3C2410_INTPND);
94 static void
95 s3c_irq_unmask(unsigned int irqno)
97 unsigned long mask;
99 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
100 irqdbf2("s3c_irq_unmask %d\n", irqno);
102 irqno -= IRQ_EINT0;
104 mask = __raw_readl(S3C2410_INTMSK);
105 mask &= ~(1UL << irqno);
106 __raw_writel(mask, S3C2410_INTMSK);
109 static struct irqchip s3c_irq_level_chip = {
110 .ack = s3c_irq_maskack,
111 .mask = s3c_irq_mask,
112 .unmask = s3c_irq_unmask
115 static struct irqchip s3c_irq_chip = {
116 .ack = s3c_irq_ack,
117 .mask = s3c_irq_mask,
118 .unmask = s3c_irq_unmask
121 /* S3C2410_EINTMASK
122 * S3C2410_EINTPEND
125 #define EXTINT_OFF (IRQ_EINT4 - 4)
127 static void
128 s3c_irqext_mask(unsigned int irqno)
130 unsigned long mask;
132 irqno -= EXTINT_OFF;
134 mask = __raw_readl(S3C2410_EINTMASK);
135 mask |= ( 1UL << irqno);
136 __raw_writel(mask, S3C2410_EINTMASK);
138 if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
139 /* check to see if all need masking */
141 if ((mask & (0xf << 4)) == (0xf << 4)) {
142 /* all masked, mask the parent */
143 s3c_irq_mask(IRQ_EINT4t7);
145 } else {
146 /* todo: the same check as above for the rest of the irq regs...*/
151 static void
152 s3c_irqext_ack(unsigned int irqno)
154 unsigned long req;
155 unsigned long bit;
156 unsigned long mask;
158 bit = 1UL << (irqno - EXTINT_OFF);
161 mask = __raw_readl(S3C2410_EINTMASK);
163 __raw_writel(bit, S3C2410_EINTPEND);
165 req = __raw_readl(S3C2410_EINTPEND);
166 req &= ~mask;
168 /* not sure if we should be acking the parent irq... */
170 if (irqno <= IRQ_EINT7 ) {
171 if ((req & 0xf0) == 0)
172 s3c_irq_ack(IRQ_EINT4t7);
173 } else {
174 if ((req >> 8) == 0)
175 s3c_irq_ack(IRQ_EINT8t23);
179 static void
180 s3c_irqext_unmask(unsigned int irqno)
182 unsigned long mask;
184 irqno -= EXTINT_OFF;
186 mask = __raw_readl(S3C2410_EINTMASK);
187 mask &= ~( 1UL << irqno);
188 __raw_writel(mask, S3C2410_EINTMASK);
190 s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
193 static int
194 s3c_irqext_type(unsigned int irq, unsigned int type)
196 unsigned long extint_reg;
197 unsigned long gpcon_reg;
198 unsigned long gpcon_offset, extint_offset;
199 unsigned long newvalue = 0, value;
201 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
203 gpcon_reg = S3C2410_GPFCON;
204 extint_reg = S3C2410_EXTINT0;
205 gpcon_offset = (irq - IRQ_EINT0) * 2;
206 extint_offset = (irq - IRQ_EINT0) * 4;
208 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
210 gpcon_reg = S3C2410_GPFCON;
211 extint_reg = S3C2410_EXTINT0;
212 gpcon_offset = (irq - (EXTINT_OFF)) * 2;
213 extint_offset = (irq - (EXTINT_OFF)) * 4;
215 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
217 gpcon_reg = S3C2410_GPGCON;
218 extint_reg = S3C2410_EXTINT1;
219 gpcon_offset = (irq - IRQ_EINT8) * 2;
220 extint_offset = (irq - IRQ_EINT8) * 4;
222 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
224 gpcon_reg = S3C2410_GPGCON;
225 extint_reg = S3C2410_EXTINT2;
226 gpcon_offset = (irq - IRQ_EINT8) * 2;
227 extint_offset = (irq - IRQ_EINT16) * 4;
228 } else
229 return -1;
231 /* Set the GPIO to external interrupt mode */
232 value = __raw_readl(gpcon_reg);
233 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
234 __raw_writel(value, gpcon_reg);
236 /* Set the external interrupt to pointed trigger type */
237 switch (type)
239 case IRQT_NOEDGE:
240 printk(KERN_WARNING "No edge setting!\n");
241 break;
243 case IRQT_RISING:
244 newvalue = S3C2410_EXTINT_RISEEDGE;
245 break;
247 case IRQT_FALLING:
248 newvalue = S3C2410_EXTINT_FALLEDGE;
249 break;
251 case IRQT_BOTHEDGE:
252 newvalue = S3C2410_EXTINT_BOTHEDGE;
253 break;
255 case IRQT_LOW:
256 newvalue = S3C2410_EXTINT_LOWLEV;
257 break;
259 case IRQT_HIGH:
260 newvalue = S3C2410_EXTINT_HILEV;
261 break;
263 default:
264 printk(KERN_ERR "No such irq type %d", type);
265 return -1;
268 value = __raw_readl(extint_reg);
269 value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
270 __raw_writel(value, extint_reg);
272 return 0;
275 static struct irqchip s3c_irqext_chip = {
276 .mask = s3c_irqext_mask,
277 .unmask = s3c_irqext_unmask,
278 .ack = s3c_irqext_ack,
279 .type = s3c_irqext_type
282 static struct irqchip s3c_irq_eint0t4 = {
283 .ack = s3c_irq_ack,
284 .mask = s3c_irq_mask,
285 .unmask = s3c_irq_unmask,
286 .type = s3c_irqext_type
289 /* mask values for the parent registers for each of the interrupt types */
291 #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
292 #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
293 #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
294 #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
295 #define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
297 static inline void
298 s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
299 int subcheck)
301 unsigned long mask;
302 unsigned long submask;
304 submask = __raw_readl(S3C2410_INTSUBMSK);
305 mask = __raw_readl(S3C2410_INTMSK);
307 submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
309 /* check to see if we need to mask the parent IRQ */
311 if ((submask & subcheck) == subcheck) {
312 __raw_writel(mask | parentbit, S3C2410_INTMSK);
315 /* write back masks */
316 __raw_writel(submask, S3C2410_INTSUBMSK);
320 static inline void
321 s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
323 unsigned long mask;
324 unsigned long submask;
326 submask = __raw_readl(S3C2410_INTSUBMSK);
327 mask = __raw_readl(S3C2410_INTMSK);
329 submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
330 mask &= ~parentbit;
332 /* write back masks */
333 __raw_writel(submask, S3C2410_INTSUBMSK);
334 __raw_writel(mask, S3C2410_INTMSK);
338 static inline void
339 s3c_irqsub_maskack(unsigned int irqno, unsigned int parentmask, unsigned int group)
341 unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
343 s3c_irqsub_mask(irqno, parentmask, group);
345 __raw_writel(bit, S3C2410_SUBSRCPND);
347 /* only ack parent if we've got all the irqs (seems we must
348 * ack, all and hope that the irq system retriggers ok when
349 * the interrupt goes off again)
352 if (1) {
353 __raw_writel(parentmask, S3C2410_SRCPND);
354 __raw_writel(parentmask, S3C2410_INTPND);
359 /* UART0 */
361 static void
362 s3c_irq_uart0_mask(unsigned int irqno)
364 s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
367 static void
368 s3c_irq_uart0_unmask(unsigned int irqno)
370 s3c_irqsub_unmask(irqno, INTMSK_UART0);
373 static void
374 s3c_irq_uart0_ack(unsigned int irqno)
376 s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
379 static struct irqchip s3c_irq_uart0 = {
380 .mask = s3c_irq_uart0_mask,
381 .unmask = s3c_irq_uart0_unmask,
382 .ack = s3c_irq_uart0_ack,
385 /* UART1 */
387 static void
388 s3c_irq_uart1_mask(unsigned int irqno)
390 s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
393 static void
394 s3c_irq_uart1_unmask(unsigned int irqno)
396 s3c_irqsub_unmask(irqno, INTMSK_UART1);
399 static void
400 s3c_irq_uart1_ack(unsigned int irqno)
402 s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
405 static struct irqchip s3c_irq_uart1 = {
406 .mask = s3c_irq_uart1_mask,
407 .unmask = s3c_irq_uart1_unmask,
408 .ack = s3c_irq_uart1_ack,
411 /* UART2 */
413 static void
414 s3c_irq_uart2_mask(unsigned int irqno)
416 s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
419 static void
420 s3c_irq_uart2_unmask(unsigned int irqno)
422 s3c_irqsub_unmask(irqno, INTMSK_UART2);
425 static void
426 s3c_irq_uart2_ack(unsigned int irqno)
428 s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
431 static struct irqchip s3c_irq_uart2 = {
432 .mask = s3c_irq_uart2_mask,
433 .unmask = s3c_irq_uart2_unmask,
434 .ack = s3c_irq_uart2_ack,
437 /* ADC and Touchscreen */
439 static void
440 s3c_irq_adc_mask(unsigned int irqno)
442 s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
445 static void
446 s3c_irq_adc_unmask(unsigned int irqno)
448 s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
451 static void
452 s3c_irq_adc_ack(unsigned int irqno)
454 s3c_irqsub_maskack(irqno, INTMSK_ADCPARENT, 3 << 9);
457 static struct irqchip s3c_irq_adc = {
458 .mask = s3c_irq_adc_mask,
459 .unmask = s3c_irq_adc_unmask,
460 .ack = s3c_irq_adc_ack,
463 /* irq demux for adc */
464 static void s3c_irq_demux_adc(unsigned int irq,
465 struct irqdesc *desc,
466 struct pt_regs *regs)
468 unsigned int subsrc, submsk;
469 unsigned int offset = 9;
470 struct irqdesc *mydesc;
472 /* read the current pending interrupts, and the mask
473 * for what it is available */
475 subsrc = __raw_readl(S3C2410_SUBSRCPND);
476 submsk = __raw_readl(S3C2410_INTSUBMSK);
478 subsrc &= ~submsk;
479 subsrc >>= offset;
480 subsrc &= 3;
482 if (subsrc != 0) {
483 if (subsrc & 1) {
484 mydesc = irq_desc + IRQ_TC;
485 mydesc->handle( IRQ_TC, mydesc, regs);
487 if (subsrc & 2) {
488 mydesc = irq_desc + IRQ_ADC;
489 mydesc->handle(IRQ_ADC, mydesc, regs);
494 static void s3c_irq_demux_uart(unsigned int start,
495 struct pt_regs *regs)
497 unsigned int subsrc, submsk;
498 unsigned int offset = start - IRQ_S3CUART_RX0;
499 struct irqdesc *desc;
501 /* read the current pending interrupts, and the mask
502 * for what it is available */
504 subsrc = __raw_readl(S3C2410_SUBSRCPND);
505 submsk = __raw_readl(S3C2410_INTSUBMSK);
507 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
508 start, offset, subsrc, submsk);
510 subsrc &= ~submsk;
511 subsrc >>= offset;
512 subsrc &= 7;
514 if (subsrc != 0) {
515 desc = irq_desc + start;
517 if (subsrc & 1)
518 desc->handle(start, desc, regs);
520 desc++;
522 if (subsrc & 2)
523 desc->handle(start+1, desc, regs);
525 desc++;
527 if (subsrc & 4)
528 desc->handle(start+2, desc, regs);
532 /* uart demux entry points */
534 static void
535 s3c_irq_demux_uart0(unsigned int irq,
536 struct irqdesc *desc,
537 struct pt_regs *regs)
539 irq = irq;
540 s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs);
543 static void
544 s3c_irq_demux_uart1(unsigned int irq,
545 struct irqdesc *desc,
546 struct pt_regs *regs)
548 irq = irq;
549 s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs);
552 static void
553 s3c_irq_demux_uart2(unsigned int irq,
554 struct irqdesc *desc,
555 struct pt_regs *regs)
557 irq = irq;
558 s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
561 /* s3c2410_init_irq
563 * Initialise S3C2410 IRQ system
566 void __init s3c2410_init_irq(void)
568 unsigned long pend;
569 unsigned long last;
570 int irqno;
571 int i;
573 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
575 /* first, clear all interrupts pending... */
577 last = 0;
578 for (i = 0; i < 4; i++) {
579 pend = __raw_readl(S3C2410_EINTPEND);
581 if (pend == 0 || pend == last)
582 break;
584 __raw_writel(pend, S3C2410_EINTPEND);
585 printk("irq: clearing pending ext status %08x\n", (int)pend);
586 last = pend;
589 last = 0;
590 for (i = 0; i < 4; i++) {
591 pend = __raw_readl(S3C2410_INTPND);
593 if (pend == 0 || pend == last)
594 break;
596 __raw_writel(pend, S3C2410_SRCPND);
597 __raw_writel(pend, S3C2410_INTPND);
598 printk("irq: clearing pending status %08x\n", (int)pend);
599 last = pend;
602 last = 0;
603 for (i = 0; i < 4; i++) {
604 pend = __raw_readl(S3C2410_SUBSRCPND);
606 if (pend == 0 || pend == last)
607 break;
609 printk("irq: clearing subpending status %08x\n", (int)pend);
610 __raw_writel(pend, S3C2410_SUBSRCPND);
611 last = pend;
614 /* register the main interrupts */
616 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
618 for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
619 /* set all the s3c2410 internal irqs */
621 switch (irqno) {
622 /* deal with the special IRQs (cascaded) */
624 case IRQ_UART0:
625 case IRQ_UART1:
626 case IRQ_UART2:
627 case IRQ_LCD:
628 case IRQ_ADCPARENT:
629 set_irq_chip(irqno, &s3c_irq_level_chip);
630 set_irq_handler(irqno, do_level_IRQ);
631 break;
633 case IRQ_RESERVED6:
634 case IRQ_RESERVED24:
635 /* no IRQ here */
636 break;
638 default:
639 //irqdbf("registering irq %d (s3c irq)\n", irqno);
640 set_irq_chip(irqno, &s3c_irq_chip);
641 set_irq_handler(irqno, do_edge_IRQ);
642 set_irq_flags(irqno, IRQF_VALID);
646 /* setup the cascade irq handlers */
648 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
649 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
650 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
651 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
654 /* external interrupts */
656 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
657 irqdbf("registering irq %d (ext int)\n", irqno);
658 set_irq_chip(irqno, &s3c_irq_eint0t4);
659 set_irq_handler(irqno, do_edge_IRQ);
660 set_irq_flags(irqno, IRQF_VALID);
663 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
664 irqdbf("registering irq %d (extended s3c irq)\n", irqno);
665 set_irq_chip(irqno, &s3c_irqext_chip);
666 set_irq_handler(irqno, do_edge_IRQ);
667 set_irq_flags(irqno, IRQF_VALID);
670 /* register the uart interrupts */
672 irqdbf("s3c2410: registering external interrupts\n");
674 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
675 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
676 set_irq_chip(irqno, &s3c_irq_uart0);
677 set_irq_handler(irqno, do_level_IRQ);
678 set_irq_flags(irqno, IRQF_VALID);
681 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
682 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
683 set_irq_chip(irqno, &s3c_irq_uart1);
684 set_irq_handler(irqno, do_level_IRQ);
685 set_irq_flags(irqno, IRQF_VALID);
688 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
689 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
690 set_irq_chip(irqno, &s3c_irq_uart2);
691 set_irq_handler(irqno, do_level_IRQ);
692 set_irq_flags(irqno, IRQF_VALID);
695 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
696 irqdbf("registering irq %d (s3c adc irq)\n", irqno);
697 set_irq_chip(irqno, &s3c_irq_adc);
698 set_irq_handler(irqno, do_edge_IRQ);
699 set_irq_flags(irqno, IRQF_VALID);
702 irqdbf("s3c2410: registered interrupt handlers\n");