1 /* arch/arm/plat-s3c64xx/irq.c
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
8 * S3C64XX - Interrupt handling
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.
15 #include <linux/kernel.h>
16 #include <linux/interrupt.h>
17 #include <linux/irq.h>
20 #include <asm/hardware/vic.h>
23 #include <plat/regs-timer.h>
26 /* Timer interrupt handling */
28 static void s3c_irq_demux_timer(unsigned int base_irq
, unsigned int sub_irq
)
30 generic_handle_irq(sub_irq
);
33 static void s3c_irq_demux_timer0(unsigned int irq
, struct irq_desc
*desc
)
35 s3c_irq_demux_timer(irq
, IRQ_TIMER0
);
38 static void s3c_irq_demux_timer1(unsigned int irq
, struct irq_desc
*desc
)
40 s3c_irq_demux_timer(irq
, IRQ_TIMER1
);
43 static void s3c_irq_demux_timer2(unsigned int irq
, struct irq_desc
*desc
)
45 s3c_irq_demux_timer(irq
, IRQ_TIMER2
);
48 static void s3c_irq_demux_timer3(unsigned int irq
, struct irq_desc
*desc
)
50 s3c_irq_demux_timer(irq
, IRQ_TIMER3
);
53 static void s3c_irq_demux_timer4(unsigned int irq
, struct irq_desc
*desc
)
55 s3c_irq_demux_timer(irq
, IRQ_TIMER4
);
58 /* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
60 static void s3c_irq_timer_mask(unsigned int irq
)
62 u32 reg
= __raw_readl(S3C64XX_TINT_CSTAT
);
64 reg
&= 0x1f; /* mask out pending interrupts */
65 reg
&= ~(1 << (irq
- IRQ_TIMER0
));
66 __raw_writel(reg
, S3C64XX_TINT_CSTAT
);
69 static void s3c_irq_timer_unmask(unsigned int irq
)
71 u32 reg
= __raw_readl(S3C64XX_TINT_CSTAT
);
73 reg
&= 0x1f; /* mask out pending interrupts */
74 reg
|= 1 << (irq
- IRQ_TIMER0
);
75 __raw_writel(reg
, S3C64XX_TINT_CSTAT
);
78 static void s3c_irq_timer_ack(unsigned int irq
)
80 u32 reg
= __raw_readl(S3C64XX_TINT_CSTAT
);
83 reg
|= (1 << 5) << (irq
- IRQ_TIMER0
);
84 __raw_writel(reg
, S3C64XX_TINT_CSTAT
);
87 static struct irq_chip s3c_irq_timer
= {
89 .mask
= s3c_irq_timer_mask
,
90 .unmask
= s3c_irq_timer_unmask
,
91 .ack
= s3c_irq_timer_ack
,
96 unsigned int base_irq
;
97 unsigned int parent_irq
;
100 /* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
101 * are consecutive when looking up the interrupt in the demux routines.
103 static struct uart_irq uart_irqs
[] = {
105 .regs
= S3C_VA_UART0
,
106 .base_irq
= IRQ_S3CUART_BASE0
,
107 .parent_irq
= IRQ_UART0
,
110 .regs
= S3C_VA_UART1
,
111 .base_irq
= IRQ_S3CUART_BASE1
,
112 .parent_irq
= IRQ_UART1
,
115 .regs
= S3C_VA_UART2
,
116 .base_irq
= IRQ_S3CUART_BASE2
,
117 .parent_irq
= IRQ_UART2
,
120 .regs
= S3C_VA_UART3
,
121 .base_irq
= IRQ_S3CUART_BASE3
,
122 .parent_irq
= IRQ_UART3
,
126 static inline void __iomem
*s3c_irq_uart_base(unsigned int irq
)
128 struct uart_irq
*uirq
= get_irq_chip_data(irq
);
132 static inline unsigned int s3c_irq_uart_bit(unsigned int irq
)
137 /* UART interrupt registers, not worth adding to seperate include header */
138 #define S3C64XX_UINTP 0x30
139 #define S3C64XX_UINTSP 0x34
140 #define S3C64XX_UINTM 0x38
142 static void s3c_irq_uart_mask(unsigned int irq
)
144 void __iomem
*regs
= s3c_irq_uart_base(irq
);
145 unsigned int bit
= s3c_irq_uart_bit(irq
);
148 reg
= __raw_readl(regs
+ S3C64XX_UINTM
);
150 __raw_writel(reg
, regs
+ S3C64XX_UINTM
);
153 static void s3c_irq_uart_maskack(unsigned int irq
)
155 void __iomem
*regs
= s3c_irq_uart_base(irq
);
156 unsigned int bit
= s3c_irq_uart_bit(irq
);
159 reg
= __raw_readl(regs
+ S3C64XX_UINTM
);
161 __raw_writel(reg
, regs
+ S3C64XX_UINTM
);
162 __raw_writel(1 << bit
, regs
+ S3C64XX_UINTP
);
165 static void s3c_irq_uart_unmask(unsigned int irq
)
167 void __iomem
*regs
= s3c_irq_uart_base(irq
);
168 unsigned int bit
= s3c_irq_uart_bit(irq
);
171 reg
= __raw_readl(regs
+ S3C64XX_UINTM
);
173 __raw_writel(reg
, regs
+ S3C64XX_UINTM
);
176 static void s3c_irq_uart_ack(unsigned int irq
)
178 void __iomem
*regs
= s3c_irq_uart_base(irq
);
179 unsigned int bit
= s3c_irq_uart_bit(irq
);
181 __raw_writel(1 << bit
, regs
+ S3C64XX_UINTP
);
184 static void s3c_irq_demux_uart(unsigned int irq
, struct irq_desc
*desc
)
186 struct uart_irq
*uirq
= &uart_irqs
[irq
- IRQ_UART0
];
187 u32 pend
= __raw_readl(uirq
->regs
+ S3C64XX_UINTP
);
188 int base
= uirq
->base_irq
;
191 generic_handle_irq(base
);
193 generic_handle_irq(base
+ 1);
195 generic_handle_irq(base
+ 2);
197 generic_handle_irq(base
+ 3);
200 static struct irq_chip s3c_irq_uart
= {
202 .mask
= s3c_irq_uart_mask
,
203 .unmask
= s3c_irq_uart_unmask
,
204 .mask_ack
= s3c_irq_uart_maskack
,
205 .ack
= s3c_irq_uart_ack
,
208 static void __init
s3c64xx_uart_irq(struct uart_irq
*uirq
)
210 void __iomem
*reg_base
= uirq
->regs
;
214 /* mask all interrupts at the start. */
215 __raw_writel(0xf, reg_base
+ S3C64XX_UINTM
);
217 for (offs
= 0; offs
< 3; offs
++) {
218 irq
= uirq
->base_irq
+ offs
;
220 set_irq_chip(irq
, &s3c_irq_uart
);
221 set_irq_chip_data(irq
, uirq
);
222 set_irq_handler(irq
, handle_level_irq
);
223 set_irq_flags(irq
, IRQF_VALID
);
226 set_irq_chained_handler(uirq
->parent_irq
, s3c_irq_demux_uart
);
229 void __init
s3c64xx_init_irq(u32 vic0_valid
, u32 vic1_valid
)
233 printk(KERN_DEBUG
"%s: initialising interrupts\n", __func__
);
235 /* initialise the pair of VICs */
236 vic_init(S3C_VA_VIC0
, S3C_VIC0_BASE
, vic0_valid
);
237 vic_init(S3C_VA_VIC1
, S3C_VIC1_BASE
, vic1_valid
);
239 /* add the timer sub-irqs */
241 set_irq_chained_handler(IRQ_TIMER0_VIC
, s3c_irq_demux_timer0
);
242 set_irq_chained_handler(IRQ_TIMER1_VIC
, s3c_irq_demux_timer1
);
243 set_irq_chained_handler(IRQ_TIMER2_VIC
, s3c_irq_demux_timer2
);
244 set_irq_chained_handler(IRQ_TIMER3_VIC
, s3c_irq_demux_timer3
);
245 set_irq_chained_handler(IRQ_TIMER4_VIC
, s3c_irq_demux_timer4
);
247 for (irq
= IRQ_TIMER0
; irq
<= IRQ_TIMER4
; irq
++) {
248 set_irq_chip(irq
, &s3c_irq_timer
);
249 set_irq_handler(irq
, handle_level_irq
);
250 set_irq_flags(irq
, IRQF_VALID
);
253 for (uart
= 0; uart
< ARRAY_SIZE(uart_irqs
); uart
++)
254 s3c64xx_uart_irq(&uart_irqs
[uart
]);