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
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>
50 #include <asm/mach/irq.h>
52 #include <asm/arch/regs-irq.h>
53 #include <asm/arch/regs-gpio.h>
60 s3c_irq_mask(unsigned int irqno
)
66 mask
= __raw_readl(S3C2410_INTMSK
);
68 __raw_writel(mask
, S3C2410_INTMSK
);
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
);
81 s3c_irq_maskack(unsigned int irqno
)
83 unsigned long bitval
= 1UL << (irqno
- IRQ_EINT0
);
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
);
95 s3c_irq_unmask(unsigned int irqno
)
99 if (irqno
!= IRQ_TIMER4
&& irqno
!= IRQ_EINT8t23
)
100 irqdbf2("s3c_irq_unmask %d\n", irqno
);
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
= {
117 .mask
= s3c_irq_mask
,
118 .unmask
= s3c_irq_unmask
125 #define EXTINT_OFF (IRQ_EINT4 - 4)
128 s3c_irqext_mask(unsigned int irqno
)
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
);
146 /* todo: the same check as above for the rest of the irq regs...*/
152 s3c_irqext_ack(unsigned int irqno
)
158 bit
= 1UL << (irqno
- EXTINT_OFF
);
161 mask
= __raw_readl(S3C2410_EINTMASK
);
163 __raw_writel(bit
, S3C2410_EINTPEND
);
165 req
= __raw_readl(S3C2410_EINTPEND
);
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
);
175 s3c_irq_ack(IRQ_EINT8t23
);
180 s3c_irqext_unmask(unsigned int irqno
)
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
);
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;
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 */
240 printk(KERN_WARNING
"No edge setting!\n");
244 newvalue
= S3C2410_EXTINT_RISEEDGE
;
248 newvalue
= S3C2410_EXTINT_FALLEDGE
;
252 newvalue
= S3C2410_EXTINT_BOTHEDGE
;
256 newvalue
= S3C2410_EXTINT_LOWLEV
;
260 newvalue
= S3C2410_EXTINT_HILEV
;
264 printk(KERN_ERR
"No such irq type %d", type
);
268 value
= __raw_readl(extint_reg
);
269 value
= (value
& ~(7 << extint_offset
)) | (newvalue
<< extint_offset
);
270 __raw_writel(value
, extint_reg
);
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
= {
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))
298 s3c_irqsub_mask(unsigned int irqno
, unsigned int parentbit
,
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
);
321 s3c_irqsub_unmask(unsigned int irqno
, unsigned int parentbit
)
324 unsigned long submask
;
326 submask
= __raw_readl(S3C2410_INTSUBMSK
);
327 mask
= __raw_readl(S3C2410_INTMSK
);
329 submask
&= ~(1UL << (irqno
- IRQ_S3CUART_RX0
));
332 /* write back masks */
333 __raw_writel(submask
, S3C2410_INTSUBMSK
);
334 __raw_writel(mask
, S3C2410_INTMSK
);
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)
353 __raw_writel(parentmask
, S3C2410_SRCPND
);
354 __raw_writel(parentmask
, S3C2410_INTPND
);
362 s3c_irq_uart0_mask(unsigned int irqno
)
364 s3c_irqsub_mask(irqno
, INTMSK_UART0
, 7);
368 s3c_irq_uart0_unmask(unsigned int irqno
)
370 s3c_irqsub_unmask(irqno
, INTMSK_UART0
);
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
,
388 s3c_irq_uart1_mask(unsigned int irqno
)
390 s3c_irqsub_mask(irqno
, INTMSK_UART1
, 7 << 3);
394 s3c_irq_uart1_unmask(unsigned int irqno
)
396 s3c_irqsub_unmask(irqno
, INTMSK_UART1
);
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
,
414 s3c_irq_uart2_mask(unsigned int irqno
)
416 s3c_irqsub_mask(irqno
, INTMSK_UART2
, 7 << 6);
420 s3c_irq_uart2_unmask(unsigned int irqno
)
422 s3c_irqsub_unmask(irqno
, INTMSK_UART2
);
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 */
440 s3c_irq_adc_mask(unsigned int irqno
)
442 s3c_irqsub_mask(irqno
, INTMSK_ADCPARENT
, 3 << 9);
446 s3c_irq_adc_unmask(unsigned int irqno
)
448 s3c_irqsub_unmask(irqno
, INTMSK_ADCPARENT
);
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
);
484 mydesc
= irq_desc
+ IRQ_TC
;
485 mydesc
->handle( IRQ_TC
, mydesc
, regs
);
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
);
515 desc
= irq_desc
+ start
;
518 desc
->handle(start
, desc
, regs
);
523 desc
->handle(start
+1, desc
, regs
);
528 desc
->handle(start
+2, desc
, regs
);
532 /* uart demux entry points */
535 s3c_irq_demux_uart0(unsigned int irq
,
536 struct irqdesc
*desc
,
537 struct pt_regs
*regs
)
540 s3c_irq_demux_uart(IRQ_S3CUART_RX0
, regs
);
544 s3c_irq_demux_uart1(unsigned int irq
,
545 struct irqdesc
*desc
,
546 struct pt_regs
*regs
)
549 s3c_irq_demux_uart(IRQ_S3CUART_RX1
, regs
);
553 s3c_irq_demux_uart2(unsigned int irq
,
554 struct irqdesc
*desc
,
555 struct pt_regs
*regs
)
558 s3c_irq_demux_uart(IRQ_S3CUART_RX2
, regs
);
563 * Initialise S3C2410 IRQ system
566 void __init
s3c2410_init_irq(void)
573 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
575 /* first, clear all interrupts pending... */
578 for (i
= 0; i
< 4; i
++) {
579 pend
= __raw_readl(S3C2410_EINTPEND
);
581 if (pend
== 0 || pend
== last
)
584 __raw_writel(pend
, S3C2410_EINTPEND
);
585 printk("irq: clearing pending ext status %08x\n", (int)pend
);
590 for (i
= 0; i
< 4; i
++) {
591 pend
= __raw_readl(S3C2410_INTPND
);
593 if (pend
== 0 || pend
== last
)
596 __raw_writel(pend
, S3C2410_SRCPND
);
597 __raw_writel(pend
, S3C2410_INTPND
);
598 printk("irq: clearing pending status %08x\n", (int)pend
);
603 for (i
= 0; i
< 4; i
++) {
604 pend
= __raw_readl(S3C2410_SUBSRCPND
);
606 if (pend
== 0 || pend
== last
)
609 printk("irq: clearing subpending status %08x\n", (int)pend
);
610 __raw_writel(pend
, S3C2410_SUBSRCPND
);
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 */
622 /* deal with the special IRQs (cascaded) */
629 set_irq_chip(irqno
, &s3c_irq_level_chip
);
630 set_irq_handler(irqno
, do_level_IRQ
);
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");