aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-02-05 19:31:33 -0500
committerOlof Johansson <olof@lixom.net>2013-02-05 19:31:51 -0500
commit5060c8881a4b177e27d5bcf351212f2bee125955 (patch)
tree17020202fd68bcdeba1e10a0a26c7e4e7fa83507
parent7dcbeef7926fefa53b0466a27c90238744fb11d8 (diff)
parentf44ddba3635e35317057e976888d4a12dcb0f842 (diff)
Merge branch 'next/irq-s3c24xx' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/cleanup
From Kukjin Kim: This is redoing the s3c24xx irqs in a generic way by using a declarative approach. * 'next/irq-s3c24xx' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung: ARM: S3C24XX: transform s3c2443 subirqs into new structure ARM: S3C24XX: modify s3c2443 irq init to initialize all irqs ARM: S3C24XX: move s3c2443 irq code to irq.c ARM: S3C24XX: transform s3c2416 irqs into new structure ARM: S3C24XX: modify s3c2416 irq init to initialize all irqs ARM: S3C24XX: move s3c2416 irq init to common irq code ARM: S3C24XX: Modify s3c_irq_wake to use the hwirq property ARM: S3C24XX: Move irq syscore-ops to irq-pm ARM: S3C24XX: transform irq handling into a declarative form Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--arch/arm/mach-s3c24xx/Makefile4
-rw-r--r--arch/arm/mach-s3c24xx/common.h2
-rw-r--r--arch/arm/mach-s3c24xx/irq-pm.c41
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2416.c348
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2443.c281
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2416.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2443.c2
-rw-r--r--arch/arm/mach-s3c24xx/s3c2410.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2412.c3
-rw-r--r--arch/arm/mach-s3c24xx/s3c2416.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2440.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2442.c4
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig1
-rw-r--r--arch/arm/plat-s3c24xx/irq.c1110
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h6
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c2416.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c2443.h2
17 files changed, 687 insertions, 1132 deletions
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index 08b87cdb98b7..1d67582da41a 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o
28obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o 28obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o
29obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o 29obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o
30 30
31obj-$(CONFIG_CPU_S3C2416) += s3c2416.o irq-s3c2416.o clock-s3c2416.o 31obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock-s3c2416.o
32obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o 32obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o
33 33
34obj-$(CONFIG_CPU_S3C2440) += s3c2440.o irq-s3c2440.o clock-s3c2440.o 34obj-$(CONFIG_CPU_S3C2440) += s3c2440.o irq-s3c2440.o clock-s3c2440.o
@@ -39,7 +39,7 @@ obj-$(CONFIG_S3C2440_DMA) += dma-s3c2440.o
39obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o 39obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o
40obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o 40obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o
41 41
42obj-$(CONFIG_CPU_S3C2443) += s3c2443.o irq-s3c2443.o clock-s3c2443.o 42obj-$(CONFIG_CPU_S3C2443) += s3c2443.o clock-s3c2443.o
43 43
44# PM 44# PM
45 45
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index c2f596e7bc2d..ed6276fcaa3b 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -15,4 +15,6 @@
15void s3c2410_restart(char mode, const char *cmd); 15void s3c2410_restart(char mode, const char *cmd);
16void s3c244x_restart(char mode, const char *cmd); 16void s3c244x_restart(char mode, const char *cmd);
17 17
18extern struct syscore_ops s3c24xx_irq_syscore_ops;
19
18#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */ 20#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c
index 0efb2e2848c8..e1199599873e 100644
--- a/arch/arm/mach-s3c24xx/irq-pm.c
+++ b/arch/arm/mach-s3c24xx/irq-pm.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/irq.h> 17#include <linux/irq.h>
18#include <linux/syscore_ops.h>
18 19
19#include <plat/cpu.h> 20#include <plat/cpu.h>
20#include <plat/pm.h> 21#include <plat/pm.h>
@@ -29,18 +30,18 @@
29 * set bit to 1 in allow bitfield to enable the wakeup settings on it 30 * set bit to 1 in allow bitfield to enable the wakeup settings on it
30*/ 31*/
31 32
32unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; 33unsigned long s3c_irqwake_intallow = 1L << 30 | 0xfL;
33unsigned long s3c_irqwake_eintallow = 0x0000fff0L; 34unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
34 35
35int s3c_irq_wake(struct irq_data *data, unsigned int state) 36int s3c_irq_wake(struct irq_data *data, unsigned int state)
36{ 37{
37 unsigned long irqbit = 1 << (data->irq - IRQ_EINT0); 38 unsigned long irqbit = 1 << data->hwirq;
38 39
39 if (!(s3c_irqwake_intallow & irqbit)) 40 if (!(s3c_irqwake_intallow & irqbit))
40 return -ENOENT; 41 return -ENOENT;
41 42
42 printk(KERN_INFO "wake %s for irq %d\n", 43 pr_info("wake %s for hwirq %lu\n",
43 state ? "enabled" : "disabled", data->irq); 44 state ? "enabled" : "disabled", data->hwirq);
44 45
45 if (!state) 46 if (!state)
46 s3c_irqwake_intmask |= irqbit; 47 s3c_irqwake_intmask |= irqbit;
@@ -64,7 +65,7 @@ static unsigned long save_extint[3];
64static unsigned long save_eintflt[4]; 65static unsigned long save_eintflt[4];
65static unsigned long save_eintmask; 66static unsigned long save_eintmask;
66 67
67int s3c24xx_irq_suspend(void) 68static int s3c24xx_irq_suspend(void)
68{ 69{
69 unsigned int i; 70 unsigned int i;
70 71
@@ -80,7 +81,7 @@ int s3c24xx_irq_suspend(void)
80 return 0; 81 return 0;
81} 82}
82 83
83void s3c24xx_irq_resume(void) 84static void s3c24xx_irq_resume(void)
84{ 85{
85 unsigned int i; 86 unsigned int i;
86 87
@@ -93,3 +94,31 @@ void s3c24xx_irq_resume(void)
93 s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); 94 s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
94 __raw_writel(save_eintmask, S3C24XX_EINTMASK); 95 __raw_writel(save_eintmask, S3C24XX_EINTMASK);
95} 96}
97
98struct syscore_ops s3c24xx_irq_syscore_ops = {
99 .suspend = s3c24xx_irq_suspend,
100 .resume = s3c24xx_irq_resume,
101};
102
103#ifdef CONFIG_CPU_S3C2416
104static struct sleep_save s3c2416_irq_save[] = {
105 SAVE_ITEM(S3C2416_INTMSK2),
106};
107
108static int s3c2416_irq_suspend(void)
109{
110 s3c_pm_do_save(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
111
112 return 0;
113}
114
115static void s3c2416_irq_resume(void)
116{
117 s3c_pm_do_restore(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
118}
119
120struct syscore_ops s3c2416_irq_syscore_ops = {
121 .suspend = s3c2416_irq_suspend,
122 .resume = s3c2416_irq_resume,
123};
124#endif
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
deleted file mode 100644
index ff141b0af26b..000000000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2416.c
+++ /dev/null
@@ -1,348 +0,0 @@
1/* linux/arch/arm/mach-s3c2416/irq.c
2 *
3 * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
4 * as part of OpenInkpot project
5 * Copyright (c) 2009 Promwad Innovation Company
6 * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22*/
23
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/interrupt.h>
27#include <linux/ioport.h>
28#include <linux/device.h>
29#include <linux/io.h>
30#include <linux/syscore_ops.h>
31
32#include <mach/hardware.h>
33#include <asm/irq.h>
34
35#include <asm/mach/irq.h>
36
37#include <mach/regs-irq.h>
38#include <mach/regs-gpio.h>
39
40#include <plat/cpu.h>
41#include <plat/pm.h>
42#include <plat/irq.h>
43
44#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
45
46static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
47{
48 unsigned int subsrc, submsk;
49 unsigned int end;
50
51 /* read the current pending interrupts, and the mask
52 * for what it is available */
53
54 subsrc = __raw_readl(S3C2410_SUBSRCPND);
55 submsk = __raw_readl(S3C2410_INTSUBMSK);
56
57 subsrc &= ~submsk;
58 subsrc >>= (irq - S3C2410_IRQSUB(0));
59 subsrc &= (1 << len)-1;
60
61 end = len + irq;
62
63 for (; irq < end && subsrc; irq++) {
64 if (subsrc & 1)
65 generic_handle_irq(irq);
66
67 subsrc >>= 1;
68 }
69}
70
71/* WDT/AC97 sub interrupts */
72
73static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
74{
75 s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
76}
77
78#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
79#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
80
81static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
82{
83 s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
84}
85
86static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
87{
88 s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
89}
90
91static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
92{
93 s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
94}
95
96static struct irq_chip s3c2416_irq_wdtac97 = {
97 .irq_mask = s3c2416_irq_wdtac97_mask,
98 .irq_unmask = s3c2416_irq_wdtac97_unmask,
99 .irq_ack = s3c2416_irq_wdtac97_ack,
100};
101
102/* LCD sub interrupts */
103
104static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
105{
106 s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
107}
108
109#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
110#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
111
112static void s3c2416_irq_lcd_mask(struct irq_data *data)
113{
114 s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
115}
116
117static void s3c2416_irq_lcd_unmask(struct irq_data *data)
118{
119 s3c_irqsub_unmask(data->irq, INTMSK_LCD);
120}
121
122static void s3c2416_irq_lcd_ack(struct irq_data *data)
123{
124 s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
125}
126
127static struct irq_chip s3c2416_irq_lcd = {
128 .irq_mask = s3c2416_irq_lcd_mask,
129 .irq_unmask = s3c2416_irq_lcd_unmask,
130 .irq_ack = s3c2416_irq_lcd_ack,
131};
132
133/* DMA sub interrupts */
134
135static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
136{
137 s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
138}
139
140#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
141#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
142
143
144static void s3c2416_irq_dma_mask(struct irq_data *data)
145{
146 s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
147}
148
149static void s3c2416_irq_dma_unmask(struct irq_data *data)
150{
151 s3c_irqsub_unmask(data->irq, INTMSK_DMA);
152}
153
154static void s3c2416_irq_dma_ack(struct irq_data *data)
155{
156 s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
157}
158
159static struct irq_chip s3c2416_irq_dma = {
160 .irq_mask = s3c2416_irq_dma_mask,
161 .irq_unmask = s3c2416_irq_dma_unmask,
162 .irq_ack = s3c2416_irq_dma_ack,
163};
164
165/* UART3 sub interrupts */
166
167static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
168{
169 s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
170}
171
172#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
173#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
174
175static void s3c2416_irq_uart3_mask(struct irq_data *data)
176{
177 s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
178}
179
180static void s3c2416_irq_uart3_unmask(struct irq_data *data)
181{
182 s3c_irqsub_unmask(data->irq, INTMSK_UART3);
183}
184
185static void s3c2416_irq_uart3_ack(struct irq_data *data)
186{
187 s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
188}
189
190static struct irq_chip s3c2416_irq_uart3 = {
191 .irq_mask = s3c2416_irq_uart3_mask,
192 .irq_unmask = s3c2416_irq_uart3_unmask,
193 .irq_ack = s3c2416_irq_uart3_ack,
194};
195
196/* second interrupt register */
197
198static inline void s3c2416_irq_ack_second(struct irq_data *data)
199{
200 unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
201
202 __raw_writel(bitval, S3C2416_SRCPND2);
203 __raw_writel(bitval, S3C2416_INTPND2);
204}
205
206static void s3c2416_irq_mask_second(struct irq_data *data)
207{
208 unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
209 unsigned long mask;
210
211 mask = __raw_readl(S3C2416_INTMSK2);
212 mask |= bitval;
213 __raw_writel(mask, S3C2416_INTMSK2);
214}
215
216static void s3c2416_irq_unmask_second(struct irq_data *data)
217{
218 unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
219 unsigned long mask;
220
221 mask = __raw_readl(S3C2416_INTMSK2);
222 mask &= ~bitval;
223 __raw_writel(mask, S3C2416_INTMSK2);
224}
225
226struct irq_chip s3c2416_irq_second = {
227 .irq_ack = s3c2416_irq_ack_second,
228 .irq_mask = s3c2416_irq_mask_second,
229 .irq_unmask = s3c2416_irq_unmask_second,
230};
231
232
233/* IRQ initialisation code */
234
235static int s3c2416_add_sub(unsigned int base,
236 void (*demux)(unsigned int,
237 struct irq_desc *),
238 struct irq_chip *chip,
239 unsigned int start, unsigned int end)
240{
241 unsigned int irqno;
242
243 irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
244 irq_set_chained_handler(base, demux);
245
246 for (irqno = start; irqno <= end; irqno++) {
247 irq_set_chip_and_handler(irqno, chip, handle_level_irq);
248 set_irq_flags(irqno, IRQF_VALID);
249 }
250
251 return 0;
252}
253
254static void s3c2416_irq_add_second(void)
255{
256 unsigned long pend;
257 unsigned long last;
258 int irqno;
259 int i;
260
261 /* first, clear all interrupts pending... */
262 last = 0;
263 for (i = 0; i < 4; i++) {
264 pend = __raw_readl(S3C2416_INTPND2);
265
266 if (pend == 0 || pend == last)
267 break;
268
269 __raw_writel(pend, S3C2416_SRCPND2);
270 __raw_writel(pend, S3C2416_INTPND2);
271 printk(KERN_INFO "irq: clearing pending status %08x\n",
272 (int)pend);
273 last = pend;
274 }
275
276 for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
277 switch (irqno) {
278 case IRQ_S3C2416_RESERVED2:
279 case IRQ_S3C2416_RESERVED3:
280 /* no IRQ here */
281 break;
282 default:
283 irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
284 handle_edge_irq);
285 set_irq_flags(irqno, IRQF_VALID);
286 }
287 }
288}
289
290static int s3c2416_irq_add(struct device *dev,
291 struct subsys_interface *sif)
292{
293 printk(KERN_INFO "S3C2416: IRQ Support\n");
294
295 s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
296 IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
297
298 s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
299 &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
300
301 s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
302 &s3c2416_irq_uart3,
303 IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
304
305 s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
306 &s3c2416_irq_wdtac97,
307 IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
308
309 s3c2416_irq_add_second();
310
311 return 0;
312}
313
314static struct subsys_interface s3c2416_irq_interface = {
315 .name = "s3c2416_irq",
316 .subsys = &s3c2416_subsys,
317 .add_dev = s3c2416_irq_add,
318};
319
320static int __init s3c2416_irq_init(void)
321{
322 return subsys_interface_register(&s3c2416_irq_interface);
323}
324
325arch_initcall(s3c2416_irq_init);
326
327#ifdef CONFIG_PM
328static struct sleep_save irq_save[] = {
329 SAVE_ITEM(S3C2416_INTMSK2),
330};
331
332int s3c2416_irq_suspend(void)
333{
334 s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
335
336 return 0;
337}
338
339void s3c2416_irq_resume(void)
340{
341 s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
342}
343
344struct syscore_ops s3c2416_irq_syscore_ops = {
345 .suspend = s3c2416_irq_suspend,
346 .resume = s3c2416_irq_resume,
347};
348#endif
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
deleted file mode 100644
index 5e69109c0928..000000000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2443.c
+++ /dev/null
@@ -1,281 +0,0 @@
1/* linux/arch/arm/mach-s3c2443/irq.c
2 *
3 * Copyright (c) 2007 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*/
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/ioport.h>
26#include <linux/device.h>
27#include <linux/io.h>
28
29#include <mach/hardware.h>
30#include <asm/irq.h>
31
32#include <asm/mach/irq.h>
33
34#include <mach/regs-irq.h>
35#include <mach/regs-gpio.h>
36
37#include <plat/cpu.h>
38#include <plat/pm.h>
39#include <plat/irq.h>
40
41#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
42
43static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
44{
45 unsigned int subsrc, submsk;
46 unsigned int end;
47
48 /* read the current pending interrupts, and the mask
49 * for what it is available */
50
51 subsrc = __raw_readl(S3C2410_SUBSRCPND);
52 submsk = __raw_readl(S3C2410_INTSUBMSK);
53
54 subsrc &= ~submsk;
55 subsrc >>= (irq - S3C2410_IRQSUB(0));
56 subsrc &= (1 << len)-1;
57
58 end = len + irq;
59
60 for (; irq < end && subsrc; irq++) {
61 if (subsrc & 1)
62 generic_handle_irq(irq);
63
64 subsrc >>= 1;
65 }
66}
67
68/* WDT/AC97 sub interrupts */
69
70static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
71{
72 s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
73}
74
75#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
76#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
77
78static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
79{
80 s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
81}
82
83static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
84{
85 s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
86}
87
88static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
89{
90 s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
91}
92
93static struct irq_chip s3c2443_irq_wdtac97 = {
94 .irq_mask = s3c2443_irq_wdtac97_mask,
95 .irq_unmask = s3c2443_irq_wdtac97_unmask,
96 .irq_ack = s3c2443_irq_wdtac97_ack,
97};
98
99/* LCD sub interrupts */
100
101static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
102{
103 s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
104}
105
106#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
107#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
108
109static void s3c2443_irq_lcd_mask(struct irq_data *data)
110{
111 s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
112}
113
114static void s3c2443_irq_lcd_unmask(struct irq_data *data)
115{
116 s3c_irqsub_unmask(data->irq, INTMSK_LCD);
117}
118
119static void s3c2443_irq_lcd_ack(struct irq_data *data)
120{
121 s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
122}
123
124static struct irq_chip s3c2443_irq_lcd = {
125 .irq_mask = s3c2443_irq_lcd_mask,
126 .irq_unmask = s3c2443_irq_lcd_unmask,
127 .irq_ack = s3c2443_irq_lcd_ack,
128};
129
130/* DMA sub interrupts */
131
132static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
133{
134 s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
135}
136
137#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
138#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
139
140static void s3c2443_irq_dma_mask(struct irq_data *data)
141{
142 s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
143}
144
145static void s3c2443_irq_dma_unmask(struct irq_data *data)
146{
147 s3c_irqsub_unmask(data->irq, INTMSK_DMA);
148}
149
150static void s3c2443_irq_dma_ack(struct irq_data *data)
151{
152 s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
153}
154
155static struct irq_chip s3c2443_irq_dma = {
156 .irq_mask = s3c2443_irq_dma_mask,
157 .irq_unmask = s3c2443_irq_dma_unmask,
158 .irq_ack = s3c2443_irq_dma_ack,
159};
160
161/* UART3 sub interrupts */
162
163static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
164{
165 s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
166}
167
168#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
169#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
170
171static void s3c2443_irq_uart3_mask(struct irq_data *data)
172{
173 s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
174}
175
176static void s3c2443_irq_uart3_unmask(struct irq_data *data)
177{
178 s3c_irqsub_unmask(data->irq, INTMSK_UART3);
179}
180
181static void s3c2443_irq_uart3_ack(struct irq_data *data)
182{
183 s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
184}
185
186static struct irq_chip s3c2443_irq_uart3 = {
187 .irq_mask = s3c2443_irq_uart3_mask,
188 .irq_unmask = s3c2443_irq_uart3_unmask,
189 .irq_ack = s3c2443_irq_uart3_ack,
190};
191
192/* CAM sub interrupts */
193
194static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
195{
196 s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
197}
198
199#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
200#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
201
202static void s3c2443_irq_cam_mask(struct irq_data *data)
203{
204 s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
205}
206
207static void s3c2443_irq_cam_unmask(struct irq_data *data)
208{
209 s3c_irqsub_unmask(data->irq, INTMSK_CAM);
210}
211
212static void s3c2443_irq_cam_ack(struct irq_data *data)
213{
214 s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
215}
216
217static struct irq_chip s3c2443_irq_cam = {
218 .irq_mask = s3c2443_irq_cam_mask,
219 .irq_unmask = s3c2443_irq_cam_unmask,
220 .irq_ack = s3c2443_irq_cam_ack,
221};
222
223/* IRQ initialisation code */
224
225static int s3c2443_add_sub(unsigned int base,
226 void (*demux)(unsigned int,
227 struct irq_desc *),
228 struct irq_chip *chip,
229 unsigned int start, unsigned int end)
230{
231 unsigned int irqno;
232
233 irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
234 irq_set_chained_handler(base, demux);
235
236 for (irqno = start; irqno <= end; irqno++) {
237 irq_set_chip_and_handler(irqno, chip, handle_level_irq);
238 set_irq_flags(irqno, IRQF_VALID);
239 }
240
241 return 0;
242}
243
244static int s3c2443_irq_add(struct device *dev,
245 struct subsys_interface *sif)
246{
247 printk("S3C2443: IRQ Support\n");
248
249 s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
250 IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
251
252 s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
253 IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
254
255 s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
256 &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
257
258 s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
259 &s3c2443_irq_uart3,
260 IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
261
262 s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
263 &s3c2443_irq_wdtac97,
264 IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
265
266 return 0;
267}
268
269static struct subsys_interface s3c2443_irq_interface = {
270 .name = "s3c2443_irq",
271 .subsys = &s3c2443_subsys,
272 .add_dev = s3c2443_irq_add,
273};
274
275static int __init s3c2443_irq_init(void)
276{
277 return subsys_interface_register(&s3c2443_irq_interface);
278}
279
280arch_initcall(s3c2443_irq_init);
281
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index 72dfec689322..ebb2e61f3d07 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -250,7 +250,7 @@ MACHINE_START(SMDK2416, "SMDK2416")
250 /* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */ 250 /* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
251 .atag_offset = 0x100, 251 .atag_offset = 0x100,
252 252
253 .init_irq = s3c24xx_init_irq, 253 .init_irq = s3c2416_init_irq,
254 .map_io = smdk2416_map_io, 254 .map_io = smdk2416_map_io,
255 .init_machine = smdk2416_machine_init, 255 .init_machine = smdk2416_machine_init,
256 .init_time = s3c24xx_timer_init, 256 .init_time = s3c24xx_timer_init,
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c
index 406c8137620e..fc65d74d3c73 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2443.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c
@@ -140,7 +140,7 @@ MACHINE_START(SMDK2443, "SMDK2443")
140 /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ 140 /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
141 .atag_offset = 0x100, 141 .atag_offset = 0x100,
142 142
143 .init_irq = s3c24xx_init_irq, 143 .init_irq = s3c2443_init_irq,
144 .map_io = smdk2443_map_io, 144 .map_io = smdk2443_map_io,
145 .init_machine = smdk2443_machine_init, 145 .init_machine = smdk2443_machine_init,
146 .init_time = s3c24xx_timer_init, 146 .init_time = s3c24xx_timer_init,
diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c
index a3c5cb086ee2..9ebef95da721 100644
--- a/arch/arm/mach-s3c24xx/s3c2410.c
+++ b/arch/arm/mach-s3c24xx/s3c2410.c
@@ -49,6 +49,8 @@
49#include <plat/gpio-cfg.h> 49#include <plat/gpio-cfg.h>
50#include <plat/gpio-cfg-helpers.h> 50#include <plat/gpio-cfg-helpers.h>
51 51
52#include "common.h"
53
52/* Initial IO mappings */ 54/* Initial IO mappings */
53 55
54static struct map_desc s3c2410_iodesc[] __initdata = { 56static struct map_desc s3c2410_iodesc[] __initdata = {
@@ -182,8 +184,8 @@ int __init s3c2410_init(void)
182 184
183#ifdef CONFIG_PM 185#ifdef CONFIG_PM
184 register_syscore_ops(&s3c2410_pm_syscore_ops); 186 register_syscore_ops(&s3c2410_pm_syscore_ops);
185#endif
186 register_syscore_ops(&s3c24xx_irq_syscore_ops); 187 register_syscore_ops(&s3c24xx_irq_syscore_ops);
188#endif
187 189
188 return device_register(&s3c2410_dev); 190 return device_register(&s3c2410_dev);
189} 191}
diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c
index c511a225f07a..ec0b31818c51 100644
--- a/arch/arm/mach-s3c24xx/s3c2412.c
+++ b/arch/arm/mach-s3c24xx/s3c2412.c
@@ -47,6 +47,7 @@
47#include <plat/regs-spi.h> 47#include <plat/regs-spi.h>
48#include <plat/s3c2412.h> 48#include <plat/s3c2412.h>
49 49
50#include "common.h"
50#include "regs-dsc.h" 51#include "regs-dsc.h"
51 52
52#define S3C2412_SWRST (S3C24XX_VA_CLKPWR + 0x30) 53#define S3C2412_SWRST (S3C24XX_VA_CLKPWR + 0x30)
@@ -245,8 +246,8 @@ int __init s3c2412_init(void)
245 246
246#ifdef CONFIG_PM 247#ifdef CONFIG_PM
247 register_syscore_ops(&s3c2412_pm_syscore_ops); 248 register_syscore_ops(&s3c2412_pm_syscore_ops);
248#endif
249 register_syscore_ops(&s3c24xx_irq_syscore_ops); 249 register_syscore_ops(&s3c24xx_irq_syscore_ops);
250#endif
250 251
251 return device_register(&s3c2412_dev); 252 return device_register(&s3c2412_dev);
252} 253}
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
index 77ee0b732237..e30476db0295 100644
--- a/arch/arm/mach-s3c24xx/s3c2416.c
+++ b/arch/arm/mach-s3c24xx/s3c2416.c
@@ -63,6 +63,8 @@
63#include <plat/rtc-core.h> 63#include <plat/rtc-core.h>
64#include <plat/spi-core.h> 64#include <plat/spi-core.h>
65 65
66#include "common.h"
67
66static struct map_desc s3c2416_iodesc[] __initdata = { 68static struct map_desc s3c2416_iodesc[] __initdata = {
67 IODESC_ENT(WATCHDOG), 69 IODESC_ENT(WATCHDOG),
68 IODESC_ENT(CLKPWR), 70 IODESC_ENT(CLKPWR),
@@ -105,9 +107,9 @@ int __init s3c2416_init(void)
105 107
106#ifdef CONFIG_PM 108#ifdef CONFIG_PM
107 register_syscore_ops(&s3c2416_pm_syscore_ops); 109 register_syscore_ops(&s3c2416_pm_syscore_ops);
108#endif
109 register_syscore_ops(&s3c24xx_irq_syscore_ops); 110 register_syscore_ops(&s3c24xx_irq_syscore_ops);
110 register_syscore_ops(&s3c2416_irq_syscore_ops); 111 register_syscore_ops(&s3c2416_irq_syscore_ops);
112#endif
111 113
112 return device_register(&s3c2416_dev); 114 return device_register(&s3c2416_dev);
113} 115}
diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c
index 2b3dddb49af7..559e394e8989 100644
--- a/arch/arm/mach-s3c24xx/s3c2440.c
+++ b/arch/arm/mach-s3c24xx/s3c2440.c
@@ -40,6 +40,8 @@
40#include <plat/gpio-cfg.h> 40#include <plat/gpio-cfg.h>
41#include <plat/gpio-cfg-helpers.h> 41#include <plat/gpio-cfg-helpers.h>
42 42
43#include "common.h"
44
43static struct device s3c2440_dev = { 45static struct device s3c2440_dev = {
44 .bus = &s3c2440_subsys, 46 .bus = &s3c2440_subsys,
45}; 47};
@@ -57,9 +59,9 @@ int __init s3c2440_init(void)
57 59
58#ifdef CONFIG_PM 60#ifdef CONFIG_PM
59 register_syscore_ops(&s3c2410_pm_syscore_ops); 61 register_syscore_ops(&s3c2410_pm_syscore_ops);
62 register_syscore_ops(&s3c24xx_irq_syscore_ops);
60#endif 63#endif
61 register_syscore_ops(&s3c244x_pm_syscore_ops); 64 register_syscore_ops(&s3c244x_pm_syscore_ops);
62 register_syscore_ops(&s3c24xx_irq_syscore_ops);
63 65
64 /* register our system device for everything else */ 66 /* register our system device for everything else */
65 67
diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c
index 22cb7c94a8c8..f732826c2359 100644
--- a/arch/arm/mach-s3c24xx/s3c2442.c
+++ b/arch/arm/mach-s3c24xx/s3c2442.c
@@ -51,6 +51,8 @@
51#include <plat/gpio-cfg.h> 51#include <plat/gpio-cfg.h>
52#include <plat/gpio-cfg-helpers.h> 52#include <plat/gpio-cfg-helpers.h>
53 53
54#include "common.h"
55
54/* S3C2442 extended clock support */ 56/* S3C2442 extended clock support */
55 57
56static unsigned long s3c2442_camif_upll_round(struct clk *clk, 58static unsigned long s3c2442_camif_upll_round(struct clk *clk,
@@ -172,9 +174,9 @@ int __init s3c2442_init(void)
172 174
173#ifdef CONFIG_PM 175#ifdef CONFIG_PM
174 register_syscore_ops(&s3c2410_pm_syscore_ops); 176 register_syscore_ops(&s3c2410_pm_syscore_ops);
177 register_syscore_ops(&s3c24xx_irq_syscore_ops);
175#endif 178#endif
176 register_syscore_ops(&s3c244x_pm_syscore_ops); 179 register_syscore_ops(&s3c244x_pm_syscore_ops);
177 register_syscore_ops(&s3c24xx_irq_syscore_ops);
178 180
179 return device_register(&s3c2442_dev); 181 return device_register(&s3c2442_dev);
180} 182}
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index eef3b6a2f8a8..3bb5c8fd34a1 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -9,6 +9,7 @@ config PLAT_S3C24XX
9 select ARCH_REQUIRE_GPIOLIB 9 select ARCH_REQUIRE_GPIOLIB
10 select NO_IOPORT 10 select NO_IOPORT
11 select S3C_DEV_NAND 11 select S3C_DEV_NAND
12 select IRQ_DOMAIN
12 help 13 help
13 Base platform code for any Samsung S3C24XX device 14 Base platform code for any Samsung S3C24XX device
14 15
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index fe57bbbf166b..cb9f5e011e73 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -1,7 +1,9 @@
1/* linux/arch/arm/plat-s3c24xx/irq.c 1/*
2 * S3C24XX IRQ handling
2 * 3 *
3 * Copyright (c) 2003-2004 Simtec Electronics 4 * Copyright (c) 2003-2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 5 * Ben Dooks <ben@simtec.co.uk>
6 * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de>
5 * 7 *
6 * This program is free software; you can redistribute it and/or modify 8 * 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 9 * it under the terms of the GNU General Public License as published by
@@ -12,175 +14,123 @@
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. 16 * 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*/ 17*/
20 18
21#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/slab.h>
22#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/io.h>
23#include <linux/err.h>
23#include <linux/interrupt.h> 24#include <linux/interrupt.h>
24#include <linux/ioport.h> 25#include <linux/ioport.h>
25#include <linux/device.h> 26#include <linux/device.h>
26#include <linux/syscore_ops.h> 27#include <linux/irqdomain.h>
27 28
28#include <asm/irq.h>
29#include <asm/mach/irq.h> 29#include <asm/mach/irq.h>
30 30
31#include <plat/regs-irqtype.h> 31#include <mach/regs-irq.h>
32#include <mach/regs-gpio.h>
32 33
33#include <plat/cpu.h> 34#include <plat/cpu.h>
35#include <plat/regs-irqtype.h>
34#include <plat/pm.h> 36#include <plat/pm.h>
35#include <plat/irq.h> 37#include <plat/irq.h>
36 38
37static void 39#define S3C_IRQTYPE_NONE 0
38s3c_irq_mask(struct irq_data *data) 40#define S3C_IRQTYPE_EINT 1
39{ 41#define S3C_IRQTYPE_EDGE 2
40 unsigned int irqno = data->irq - IRQ_EINT0; 42#define S3C_IRQTYPE_LEVEL 3
41 unsigned long mask;
42
43 mask = __raw_readl(S3C2410_INTMSK);
44 mask |= 1UL << irqno;
45 __raw_writel(mask, S3C2410_INTMSK);
46}
47
48static inline void
49s3c_irq_ack(struct irq_data *data)
50{
51 unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
52
53 __raw_writel(bitval, S3C2410_SRCPND);
54 __raw_writel(bitval, S3C2410_INTPND);
55}
56
57static inline void
58s3c_irq_maskack(struct irq_data *data)
59{
60 unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
61 unsigned long mask;
62
63 mask = __raw_readl(S3C2410_INTMSK);
64 __raw_writel(mask|bitval, S3C2410_INTMSK);
65
66 __raw_writel(bitval, S3C2410_SRCPND);
67 __raw_writel(bitval, S3C2410_INTPND);
68}
69
70
71static void
72s3c_irq_unmask(struct irq_data *data)
73{
74 unsigned int irqno = data->irq;
75 unsigned long mask;
76
77 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
78 irqdbf2("s3c_irq_unmask %d\n", irqno);
79 43
80 irqno -= IRQ_EINT0; 44struct s3c_irq_data {
81 45 unsigned int type;
82 mask = __raw_readl(S3C2410_INTMSK); 46 unsigned long parent_irq;
83 mask &= ~(1UL << irqno);
84 __raw_writel(mask, S3C2410_INTMSK);
85}
86 47
87struct irq_chip s3c_irq_level_chip = { 48 /* data gets filled during init */
88 .name = "s3c-level", 49 struct s3c_irq_intc *intc;
89 .irq_ack = s3c_irq_maskack, 50 unsigned long sub_bits;
90 .irq_mask = s3c_irq_mask, 51 struct s3c_irq_intc *sub_intc;
91 .irq_unmask = s3c_irq_unmask,
92 .irq_set_wake = s3c_irq_wake
93}; 52};
94 53
95struct irq_chip s3c_irq_chip = { 54/*
96 .name = "s3c", 55 * Sructure holding the controller data
97 .irq_ack = s3c_irq_ack, 56 * @reg_pending register holding pending irqs
98 .irq_mask = s3c_irq_mask, 57 * @reg_intpnd special register intpnd in main intc
99 .irq_unmask = s3c_irq_unmask, 58 * @reg_mask mask register
100 .irq_set_wake = s3c_irq_wake 59 * @domain irq_domain of the controller
60 * @parent parent controller for ext and sub irqs
61 * @irqs irq-data, always s3c_irq_data[32]
62 */
63struct s3c_irq_intc {
64 void __iomem *reg_pending;
65 void __iomem *reg_intpnd;
66 void __iomem *reg_mask;
67 struct irq_domain *domain;
68 struct s3c_irq_intc *parent;
69 struct s3c_irq_data *irqs;
101}; 70};
102 71
103static void 72static void s3c_irq_mask(struct irq_data *data)
104s3c_irqext_mask(struct irq_data *data)
105{ 73{
106 unsigned int irqno = data->irq - EXTINT_OFF; 74 struct s3c_irq_intc *intc = data->domain->host_data;
75 struct s3c_irq_intc *parent_intc = intc->parent;
76 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
77 struct s3c_irq_data *parent_data;
107 unsigned long mask; 78 unsigned long mask;
79 unsigned int irqno;
80
81 mask = __raw_readl(intc->reg_mask);
82 mask |= (1UL << data->hwirq);
83 __raw_writel(mask, intc->reg_mask);
84
85 if (parent_intc && irq_data->parent_irq) {
86 parent_data = &parent_intc->irqs[irq_data->parent_irq];
108 87
109 mask = __raw_readl(S3C24XX_EINTMASK); 88 /* check to see if we need to mask the parent IRQ */
110 mask |= ( 1UL << irqno); 89 if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
111 __raw_writel(mask, S3C24XX_EINTMASK); 90 irqno = irq_find_mapping(parent_intc->domain,
91 irq_data->parent_irq);
92 s3c_irq_mask(irq_get_irq_data(irqno));
93 }
94 }
112} 95}
113 96
114static void 97static void s3c_irq_unmask(struct irq_data *data)
115s3c_irqext_ack(struct irq_data *data)
116{ 98{
117 unsigned long req; 99 struct s3c_irq_intc *intc = data->domain->host_data;
118 unsigned long bit; 100 struct s3c_irq_intc *parent_intc = intc->parent;
101 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
119 unsigned long mask; 102 unsigned long mask;
103 unsigned int irqno;
120 104
121 bit = 1UL << (data->irq - EXTINT_OFF); 105 mask = __raw_readl(intc->reg_mask);
122 106 mask &= ~(1UL << data->hwirq);
123 mask = __raw_readl(S3C24XX_EINTMASK); 107 __raw_writel(mask, intc->reg_mask);
124
125 __raw_writel(bit, S3C24XX_EINTPEND);
126
127 req = __raw_readl(S3C24XX_EINTPEND);
128 req &= ~mask;
129 108
130 /* not sure if we should be acking the parent irq... */ 109 if (parent_intc && irq_data->parent_irq) {
131 110 irqno = irq_find_mapping(parent_intc->domain,
132 if (data->irq <= IRQ_EINT7) { 111 irq_data->parent_irq);
133 if ((req & 0xf0) == 0) 112 s3c_irq_unmask(irq_get_irq_data(irqno));
134 s3c_irq_ack(irq_get_irq_data(IRQ_EINT4t7));
135 } else {
136 if ((req >> 8) == 0)
137 s3c_irq_ack(irq_get_irq_data(IRQ_EINT8t23));
138 } 113 }
139} 114}
140 115
141static void 116static inline void s3c_irq_ack(struct irq_data *data)
142s3c_irqext_unmask(struct irq_data *data)
143{ 117{
144 unsigned int irqno = data->irq - EXTINT_OFF; 118 struct s3c_irq_intc *intc = data->domain->host_data;
145 unsigned long mask; 119 unsigned long bitval = 1UL << data->hwirq;
146 120
147 mask = __raw_readl(S3C24XX_EINTMASK); 121 __raw_writel(bitval, intc->reg_pending);
148 mask &= ~(1UL << irqno); 122 if (intc->reg_intpnd)
149 __raw_writel(mask, S3C24XX_EINTMASK); 123 __raw_writel(bitval, intc->reg_intpnd);
150} 124}
151 125
152int 126static int s3c_irqext_type_set(void __iomem *gpcon_reg,
153s3c_irqext_type(struct irq_data *data, unsigned int type) 127 void __iomem *extint_reg,
128 unsigned long gpcon_offset,
129 unsigned long extint_offset,
130 unsigned int type)
154{ 131{
155 void __iomem *extint_reg;
156 void __iomem *gpcon_reg;
157 unsigned long gpcon_offset, extint_offset;
158 unsigned long newvalue = 0, value; 132 unsigned long newvalue = 0, value;
159 133
160 if ((data->irq >= IRQ_EINT0) && (data->irq <= IRQ_EINT3)) {
161 gpcon_reg = S3C2410_GPFCON;
162 extint_reg = S3C24XX_EXTINT0;
163 gpcon_offset = (data->irq - IRQ_EINT0) * 2;
164 extint_offset = (data->irq - IRQ_EINT0) * 4;
165 } else if ((data->irq >= IRQ_EINT4) && (data->irq <= IRQ_EINT7)) {
166 gpcon_reg = S3C2410_GPFCON;
167 extint_reg = S3C24XX_EXTINT0;
168 gpcon_offset = (data->irq - (EXTINT_OFF)) * 2;
169 extint_offset = (data->irq - (EXTINT_OFF)) * 4;
170 } else if ((data->irq >= IRQ_EINT8) && (data->irq <= IRQ_EINT15)) {
171 gpcon_reg = S3C2410_GPGCON;
172 extint_reg = S3C24XX_EXTINT1;
173 gpcon_offset = (data->irq - IRQ_EINT8) * 2;
174 extint_offset = (data->irq - IRQ_EINT8) * 4;
175 } else if ((data->irq >= IRQ_EINT16) && (data->irq <= IRQ_EINT23)) {
176 gpcon_reg = S3C2410_GPGCON;
177 extint_reg = S3C24XX_EXTINT2;
178 gpcon_offset = (data->irq - IRQ_EINT8) * 2;
179 extint_offset = (data->irq - IRQ_EINT16) * 4;
180 } else {
181 return -1;
182 }
183
184 /* Set the GPIO to external interrupt mode */ 134 /* Set the GPIO to external interrupt mode */
185 value = __raw_readl(gpcon_reg); 135 value = __raw_readl(gpcon_reg);
186 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); 136 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
@@ -190,7 +140,7 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
190 switch (type) 140 switch (type)
191 { 141 {
192 case IRQ_TYPE_NONE: 142 case IRQ_TYPE_NONE:
193 printk(KERN_WARNING "No edge setting!\n"); 143 pr_warn("No edge setting!\n");
194 break; 144 break;
195 145
196 case IRQ_TYPE_EDGE_RISING: 146 case IRQ_TYPE_EDGE_RISING:
@@ -214,8 +164,8 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
214 break; 164 break;
215 165
216 default: 166 default:
217 printk(KERN_ERR "No such irq type %d", type); 167 pr_err("No such irq type %d", type);
218 return -1; 168 return -EINVAL;
219 } 169 }
220 170
221 value = __raw_readl(extint_reg); 171 value = __raw_readl(extint_reg);
@@ -225,265 +175,113 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
225 return 0; 175 return 0;
226} 176}
227 177
228static struct irq_chip s3c_irqext_chip = { 178/* FIXME: make static when it's out of plat-samsung/irq.h */
229 .name = "s3c-ext", 179int s3c_irqext_type(struct irq_data *data, unsigned int type)
230 .irq_mask = s3c_irqext_mask,
231 .irq_unmask = s3c_irqext_unmask,
232 .irq_ack = s3c_irqext_ack,
233 .irq_set_type = s3c_irqext_type,
234 .irq_set_wake = s3c_irqext_wake
235};
236
237static struct irq_chip s3c_irq_eint0t4 = {
238 .name = "s3c-ext0",
239 .irq_ack = s3c_irq_ack,
240 .irq_mask = s3c_irq_mask,
241 .irq_unmask = s3c_irq_unmask,
242 .irq_set_wake = s3c_irq_wake,
243 .irq_set_type = s3c_irqext_type,
244};
245
246/* mask values for the parent registers for each of the interrupt types */
247
248#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
249#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
250#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
251#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
252
253
254/* UART0 */
255
256static void
257s3c_irq_uart0_mask(struct irq_data *data)
258{ 180{
259 s3c_irqsub_mask(data->irq, INTMSK_UART0, 7); 181 void __iomem *extint_reg;
260} 182 void __iomem *gpcon_reg;
183 unsigned long gpcon_offset, extint_offset;
261 184
262static void 185 if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
263s3c_irq_uart0_unmask(struct irq_data *data) 186 gpcon_reg = S3C2410_GPFCON;
264{ 187 extint_reg = S3C24XX_EXTINT0;
265 s3c_irqsub_unmask(data->irq, INTMSK_UART0); 188 gpcon_offset = (data->hwirq) * 2;
266} 189 extint_offset = (data->hwirq) * 4;
190 } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
191 gpcon_reg = S3C2410_GPGCON;
192 extint_reg = S3C24XX_EXTINT1;
193 gpcon_offset = (data->hwirq - 8) * 2;
194 extint_offset = (data->hwirq - 8) * 4;
195 } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
196 gpcon_reg = S3C2410_GPGCON;
197 extint_reg = S3C24XX_EXTINT2;
198 gpcon_offset = (data->hwirq - 8) * 2;
199 extint_offset = (data->hwirq - 16) * 4;
200 } else {
201 return -EINVAL;
202 }
267 203
268static void 204 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
269s3c_irq_uart0_ack(struct irq_data *data) 205 extint_offset, type);
270{
271 s3c_irqsub_maskack(data->irq, INTMSK_UART0, 7);
272} 206}
273 207
274static struct irq_chip s3c_irq_uart0 = { 208static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
275 .name = "s3c-uart0",
276 .irq_mask = s3c_irq_uart0_mask,
277 .irq_unmask = s3c_irq_uart0_unmask,
278 .irq_ack = s3c_irq_uart0_ack,
279};
280
281/* UART1 */
282
283static void
284s3c_irq_uart1_mask(struct irq_data *data)
285{ 209{
286 s3c_irqsub_mask(data->irq, INTMSK_UART1, 7 << 3); 210 void __iomem *extint_reg;
287} 211 void __iomem *gpcon_reg;
212 unsigned long gpcon_offset, extint_offset;
288 213
289static void 214 if ((data->hwirq >= 0) && (data->hwirq <= 3)) {
290s3c_irq_uart1_unmask(struct irq_data *data) 215 gpcon_reg = S3C2410_GPFCON;
291{ 216 extint_reg = S3C24XX_EXTINT0;
292 s3c_irqsub_unmask(data->irq, INTMSK_UART1); 217 gpcon_offset = (data->hwirq) * 2;
293} 218 extint_offset = (data->hwirq) * 4;
219 } else {
220 return -EINVAL;
221 }
294 222
295static void 223 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
296s3c_irq_uart1_ack(struct irq_data *data) 224 extint_offset, type);
297{
298 s3c_irqsub_maskack(data->irq, INTMSK_UART1, 7 << 3);
299} 225}
300 226
301static struct irq_chip s3c_irq_uart1 = { 227struct irq_chip s3c_irq_chip = {
302 .name = "s3c-uart1", 228 .name = "s3c",
303 .irq_mask = s3c_irq_uart1_mask, 229 .irq_ack = s3c_irq_ack,
304 .irq_unmask = s3c_irq_uart1_unmask, 230 .irq_mask = s3c_irq_mask,
305 .irq_ack = s3c_irq_uart1_ack, 231 .irq_unmask = s3c_irq_unmask,
232 .irq_set_wake = s3c_irq_wake
306}; 233};
307 234
308/* UART2 */ 235struct irq_chip s3c_irq_level_chip = {
309 236 .name = "s3c-level",
310static void 237 .irq_mask = s3c_irq_mask,
311s3c_irq_uart2_mask(struct irq_data *data) 238 .irq_unmask = s3c_irq_unmask,
312{ 239 .irq_ack = s3c_irq_ack,
313 s3c_irqsub_mask(data->irq, INTMSK_UART2, 7 << 6);
314}
315
316static void
317s3c_irq_uart2_unmask(struct irq_data *data)
318{
319 s3c_irqsub_unmask(data->irq, INTMSK_UART2);
320}
321
322static void
323s3c_irq_uart2_ack(struct irq_data *data)
324{
325 s3c_irqsub_maskack(data->irq, INTMSK_UART2, 7 << 6);
326}
327
328static struct irq_chip s3c_irq_uart2 = {
329 .name = "s3c-uart2",
330 .irq_mask = s3c_irq_uart2_mask,
331 .irq_unmask = s3c_irq_uart2_unmask,
332 .irq_ack = s3c_irq_uart2_ack,
333}; 240};
334 241
335/* ADC and Touchscreen */ 242static struct irq_chip s3c_irqext_chip = {
336 243 .name = "s3c-ext",
337static void 244 .irq_mask = s3c_irq_mask,
338s3c_irq_adc_mask(struct irq_data *d) 245 .irq_unmask = s3c_irq_unmask,
339{ 246 .irq_ack = s3c_irq_ack,
340 s3c_irqsub_mask(d->irq, INTMSK_ADCPARENT, 3 << 9); 247 .irq_set_type = s3c_irqext_type,
341} 248 .irq_set_wake = s3c_irqext_wake
342
343static void
344s3c_irq_adc_unmask(struct irq_data *d)
345{
346 s3c_irqsub_unmask(d->irq, INTMSK_ADCPARENT);
347}
348
349static void
350s3c_irq_adc_ack(struct irq_data *d)
351{
352 s3c_irqsub_ack(d->irq, INTMSK_ADCPARENT, 3 << 9);
353}
354
355static struct irq_chip s3c_irq_adc = {
356 .name = "s3c-adc",
357 .irq_mask = s3c_irq_adc_mask,
358 .irq_unmask = s3c_irq_adc_unmask,
359 .irq_ack = s3c_irq_adc_ack,
360}; 249};
361 250
362/* irq demux for adc */ 251static struct irq_chip s3c_irq_eint0t4 = {
363static void s3c_irq_demux_adc(unsigned int irq, 252 .name = "s3c-ext0",
364 struct irq_desc *desc) 253 .irq_ack = s3c_irq_ack,
365{ 254 .irq_mask = s3c_irq_mask,
366 unsigned int subsrc, submsk; 255 .irq_unmask = s3c_irq_unmask,
367 unsigned int offset = 9; 256 .irq_set_wake = s3c_irq_wake,
368 257 .irq_set_type = s3c_irqext0_type,
369 /* read the current pending interrupts, and the mask 258};
370 * for what it is available */
371
372 subsrc = __raw_readl(S3C2410_SUBSRCPND);
373 submsk = __raw_readl(S3C2410_INTSUBMSK);
374
375 subsrc &= ~submsk;
376 subsrc >>= offset;
377 subsrc &= 3;
378
379 if (subsrc != 0) {
380 if (subsrc & 1) {
381 generic_handle_irq(IRQ_TC);
382 }
383 if (subsrc & 2) {
384 generic_handle_irq(IRQ_ADC);
385 }
386 }
387}
388 259
389static void s3c_irq_demux_uart(unsigned int start) 260static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
390{ 261{
391 unsigned int subsrc, submsk; 262 struct irq_chip *chip = irq_desc_get_chip(desc);
392 unsigned int offset = start - IRQ_S3CUART_RX0; 263 struct s3c_irq_intc *intc = desc->irq_data.domain->host_data;
393 264 struct s3c_irq_data *irq_data = &intc->irqs[desc->irq_data.hwirq];
394 /* read the current pending interrupts, and the mask 265 struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
395 * for what it is available */ 266 unsigned long src;
396 267 unsigned long msk;
397 subsrc = __raw_readl(S3C2410_SUBSRCPND); 268 unsigned int n;
398 submsk = __raw_readl(S3C2410_INTSUBMSK); 269
399 270 chained_irq_enter(chip, desc);
400 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", 271
401 start, offset, subsrc, submsk); 272 src = __raw_readl(sub_intc->reg_pending);
402 273 msk = __raw_readl(sub_intc->reg_mask);
403 subsrc &= ~submsk; 274
404 subsrc >>= offset; 275 src &= ~msk;
405 subsrc &= 7; 276 src &= irq_data->sub_bits;
406 277
407 if (subsrc != 0) { 278 while (src) {
408 if (subsrc & 1) 279 n = __ffs(src);
409 generic_handle_irq(start); 280 src &= ~(1 << n);
410 281 generic_handle_irq(irq_find_mapping(sub_intc->domain, n));
411 if (subsrc & 2)
412 generic_handle_irq(start+1);
413
414 if (subsrc & 4)
415 generic_handle_irq(start+2);
416 } 282 }
417}
418
419/* uart demux entry points */
420
421static void
422s3c_irq_demux_uart0(unsigned int irq,
423 struct irq_desc *desc)
424{
425 irq = irq;
426 s3c_irq_demux_uart(IRQ_S3CUART_RX0);
427}
428 283
429static void 284 chained_irq_exit(chip, desc);
430s3c_irq_demux_uart1(unsigned int irq,
431 struct irq_desc *desc)
432{
433 irq = irq;
434 s3c_irq_demux_uart(IRQ_S3CUART_RX1);
435}
436
437static void
438s3c_irq_demux_uart2(unsigned int irq,
439 struct irq_desc *desc)
440{
441 irq = irq;
442 s3c_irq_demux_uart(IRQ_S3CUART_RX2);
443}
444
445static void
446s3c_irq_demux_extint8(unsigned int irq,
447 struct irq_desc *desc)
448{
449 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
450 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
451
452 eintpnd &= ~eintmsk;
453 eintpnd &= ~0xff; /* ignore lower irqs */
454
455 /* we may as well handle all the pending IRQs here */
456
457 while (eintpnd) {
458 irq = __ffs(eintpnd);
459 eintpnd &= ~(1<<irq);
460
461 irq += (IRQ_EINT4 - 4);
462 generic_handle_irq(irq);
463 }
464
465}
466
467static void
468s3c_irq_demux_extint4t7(unsigned int irq,
469 struct irq_desc *desc)
470{
471 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
472 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
473
474 eintpnd &= ~eintmsk;
475 eintpnd &= 0xff; /* only lower irqs */
476
477 /* we may as well handle all the pending IRQs here */
478
479 while (eintpnd) {
480 irq = __ffs(eintpnd);
481 eintpnd &= ~(1<<irq);
482
483 irq += (IRQ_EINT4 - 4);
484
485 generic_handle_irq(irq);
486 }
487} 285}
488 286
489#ifdef CONFIG_FIQ 287#ifdef CONFIG_FIQ
@@ -519,158 +317,506 @@ int s3c24xx_set_fiq(unsigned int irq, bool on)
519EXPORT_SYMBOL_GPL(s3c24xx_set_fiq); 317EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
520#endif 318#endif
521 319
320static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
321 irq_hw_number_t hw)
322{
323 struct s3c_irq_intc *intc = h->host_data;
324 struct s3c_irq_data *irq_data = &intc->irqs[hw];
325 struct s3c_irq_intc *parent_intc;
326 struct s3c_irq_data *parent_irq_data;
327 unsigned int irqno;
328
329 if (!intc) {
330 pr_err("irq-s3c24xx: no controller found for hwirq %lu\n", hw);
331 return -EINVAL;
332 }
522 333
523/* s3c24xx_init_irq 334 if (!irq_data) {
524 * 335 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", hw);
525 * Initialise S3C2410 IRQ system 336 return -EINVAL;
526*/ 337 }
527 338
528void __init s3c24xx_init_irq(void) 339 /* attach controller pointer to irq_data */
340 irq_data->intc = intc;
341
342 /* set handler and flags */
343 switch (irq_data->type) {
344 case S3C_IRQTYPE_NONE:
345 return 0;
346 case S3C_IRQTYPE_EINT:
347 if (irq_data->parent_irq)
348 irq_set_chip_and_handler(virq, &s3c_irqext_chip,
349 handle_edge_irq);
350 else
351 irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
352 handle_edge_irq);
353 break;
354 case S3C_IRQTYPE_EDGE:
355 if (irq_data->parent_irq ||
356 intc->reg_pending == S3C2416_SRCPND2)
357 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
358 handle_edge_irq);
359 else
360 irq_set_chip_and_handler(virq, &s3c_irq_chip,
361 handle_edge_irq);
362 break;
363 case S3C_IRQTYPE_LEVEL:
364 if (irq_data->parent_irq)
365 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
366 handle_level_irq);
367 else
368 irq_set_chip_and_handler(virq, &s3c_irq_chip,
369 handle_level_irq);
370 break;
371 default:
372 pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
373 return -EINVAL;
374 }
375 set_irq_flags(virq, IRQF_VALID);
376
377 if (irq_data->parent_irq) {
378 parent_intc = intc->parent;
379 if (!parent_intc) {
380 pr_err("irq-s3c24xx: no parent controller found for hwirq %lu\n",
381 hw);
382 goto err;
383 }
384
385 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
386 if (!irq_data) {
387 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n",
388 hw);
389 goto err;
390 }
391
392 parent_irq_data->sub_intc = intc;
393 parent_irq_data->sub_bits |= (1UL << hw);
394
395 /* attach the demuxer to the parent irq */
396 irqno = irq_find_mapping(parent_intc->domain,
397 irq_data->parent_irq);
398 if (!irqno) {
399 pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
400 irq_data->parent_irq);
401 goto err;
402 }
403 irq_set_chained_handler(irqno, s3c_irq_demux);
404 }
405
406 return 0;
407
408err:
409 set_irq_flags(virq, 0);
410
411 /* the only error can result from bad mapping data*/
412 return -EINVAL;
413}
414
415static struct irq_domain_ops s3c24xx_irq_ops = {
416 .map = s3c24xx_irq_map,
417 .xlate = irq_domain_xlate_twocell,
418};
419
420static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
529{ 421{
422 void __iomem *reg_source;
530 unsigned long pend; 423 unsigned long pend;
531 unsigned long last; 424 unsigned long last;
532 int irqno;
533 int i; 425 int i;
534 426
535#ifdef CONFIG_FIQ 427 /* if intpnd is set, read the next pending irq from there */
536 init_FIQ(FIQ_START); 428 reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
537#endif
538
539 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
540
541 /* first, clear all interrupts pending... */
542 429
543 last = 0; 430 last = 0;
544 for (i = 0; i < 4; i++) { 431 for (i = 0; i < 4; i++) {
545 pend = __raw_readl(S3C24XX_EINTPEND); 432 pend = __raw_readl(reg_source);
546 433
547 if (pend == 0 || pend == last) 434 if (pend == 0 || pend == last)
548 break; 435 break;
549 436
550 __raw_writel(pend, S3C24XX_EINTPEND); 437 __raw_writel(pend, intc->reg_pending);
551 printk("irq: clearing pending ext status %08x\n", (int)pend); 438 if (intc->reg_intpnd)
439 __raw_writel(pend, intc->reg_intpnd);
440
441 pr_info("irq: clearing pending status %08x\n", (int)pend);
552 last = pend; 442 last = pend;
553 } 443 }
444}
554 445
555 last = 0; 446struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
556 for (i = 0; i < 4; i++) { 447 struct s3c_irq_data *irq_data,
557 pend = __raw_readl(S3C2410_INTPND); 448 struct s3c_irq_intc *parent,
558 449 unsigned long address)
559 if (pend == 0 || pend == last) 450{
560 break; 451 struct s3c_irq_intc *intc;
561 452 void __iomem *base = (void *)0xf6000000; /* static mapping */
562 __raw_writel(pend, S3C2410_SRCPND); 453 int irq_num;
563 __raw_writel(pend, S3C2410_INTPND); 454 int irq_start;
564 printk("irq: clearing pending status %08x\n", (int)pend); 455 int irq_offset;
565 last = pend; 456 int ret;
457
458 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
459 if (!intc)
460 return ERR_PTR(-ENOMEM);
461
462 intc->irqs = irq_data;
463
464 if (parent)
465 intc->parent = parent;
466
467 /* select the correct data for the controller.
468 * Need to hard code the irq num start and offset
469 * to preserve the static mapping for now
470 */
471 switch (address) {
472 case 0x4a000000:
473 pr_debug("irq: found main intc\n");
474 intc->reg_pending = base;
475 intc->reg_mask = base + 0x08;
476 intc->reg_intpnd = base + 0x10;
477 irq_num = 32;
478 irq_start = S3C2410_IRQ(0);
479 irq_offset = 0;
480 break;
481 case 0x4a000018:
482 pr_debug("irq: found subintc\n");
483 intc->reg_pending = base + 0x18;
484 intc->reg_mask = base + 0x1c;
485 irq_num = 29;
486 irq_start = S3C2410_IRQSUB(0);
487 irq_offset = 0;
488 break;
489 case 0x4a000040:
490 pr_debug("irq: found intc2\n");
491 intc->reg_pending = base + 0x40;
492 intc->reg_mask = base + 0x48;
493 intc->reg_intpnd = base + 0x50;
494 irq_num = 8;
495 irq_start = S3C2416_IRQ(0);
496 irq_offset = 0;
497 break;
498 case 0x560000a4:
499 pr_debug("irq: found eintc\n");
500 base = (void *)0xfd000000;
501
502 intc->reg_mask = base + 0xa4;
503 intc->reg_pending = base + 0x08;
504 irq_num = 20;
505 irq_start = S3C2410_IRQ(32);
506 irq_offset = 4;
507 break;
508 default:
509 pr_err("irq: unsupported controller address\n");
510 ret = -EINVAL;
511 goto err;
566 } 512 }
567 513
568 last = 0; 514 /* now that all the data is complete, init the irq-domain */
569 for (i = 0; i < 4; i++) { 515 s3c24xx_clear_intc(intc);
570 pend = __raw_readl(S3C2410_SUBSRCPND); 516 intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
517 irq_offset, &s3c24xx_irq_ops,
518 intc);
519 if (!intc->domain) {
520 pr_err("irq: could not create irq-domain\n");
521 ret = -EINVAL;
522 goto err;
523 }
571 524
572 if (pend == 0 || pend == last) 525 return intc;
573 break;
574 526
575 printk("irq: clearing subpending status %08x\n", (int)pend); 527err:
576 __raw_writel(pend, S3C2410_SUBSRCPND); 528 kfree(intc);
577 last = pend; 529 return ERR_PTR(ret);
578 } 530}
579 531
580 /* register the main interrupts */ 532/* s3c24xx_init_irq
533 *
534 * Initialise S3C2410 IRQ system
535*/
581 536
582 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); 537static struct s3c_irq_data init_base[32] = {
538 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
539 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
540 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
541 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
542 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
543 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
544 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
545 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
546 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
547 { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
548 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
549 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
550 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
551 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
552 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
553 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
554 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
555 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
556 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
557 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
558 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
559 { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
560 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
561 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
562 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
563 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
564 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
565 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
566 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
567 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
568 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
569 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
570};
583 571
584 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { 572static struct s3c_irq_data init_eint[32] = {
585 /* set all the s3c2410 internal irqs */ 573 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
574 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
575 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
576 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
577 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
578 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
579 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
580 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
581 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
582 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
583 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
584 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
585 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
586 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
587 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
588 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
589 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
590 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
591 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
592 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
593 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
594 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
595 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
596 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
597};
586 598
587 switch (irqno) { 599static struct s3c_irq_data init_subint[32] = {
588 /* deal with the special IRQs (cascaded) */ 600 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
601 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
602 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
603 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
604 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
605 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
606 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
607 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
608 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
609 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
610 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
611};
589 612
590 case IRQ_EINT4t7: 613void __init s3c24xx_init_irq(void)
591 case IRQ_EINT8t23: 614{
592 case IRQ_UART0: 615 struct s3c_irq_intc *main_intc;
593 case IRQ_UART1:
594 case IRQ_UART2:
595 case IRQ_ADCPARENT:
596 irq_set_chip_and_handler(irqno, &s3c_irq_level_chip,
597 handle_level_irq);
598 break;
599 616
600 case IRQ_RESERVED6: 617#ifdef CONFIG_FIQ
601 case IRQ_RESERVED24: 618 init_FIQ(FIQ_START);
602 /* no IRQ here */ 619#endif
603 break;
604 620
605 default: 621 main_intc = s3c24xx_init_intc(NULL, &init_base[0], NULL, 0x4a000000);
606 //irqdbf("registering irq %d (s3c irq)\n", irqno); 622 if (IS_ERR(main_intc)) {
607 irq_set_chip_and_handler(irqno, &s3c_irq_chip, 623 pr_err("irq: could not create main interrupt controller\n");
608 handle_edge_irq); 624 return;
609 set_irq_flags(irqno, IRQF_VALID);
610 }
611 } 625 }
612 626
613 /* setup the cascade irq handlers */ 627 s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018);
628 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
629}
614 630
615 irq_set_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); 631#ifdef CONFIG_CPU_S3C2416
616 irq_set_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); 632static struct s3c_irq_data init_s3c2416base[32] = {
633 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
634 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
635 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
636 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
637 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
638 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
639 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
640 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
641 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
642 { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
643 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
644 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
645 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
646 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
647 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
648 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
649 { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
650 { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
651 { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
652 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
653 { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
654 { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
655 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
656 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
657 { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
658 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
659 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
660 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
661 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
662 { .type = S3C_IRQTYPE_NONE, },
663 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
664 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
665};
617 666
618 irq_set_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); 667static struct s3c_irq_data init_s3c2416subint[32] = {
619 irq_set_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); 668 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
620 irq_set_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); 669 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
621 irq_set_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); 670 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
671 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
672 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
673 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
674 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
675 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
676 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
677 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
678 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
679 { .type = S3C_IRQTYPE_NONE }, /* reserved */
680 { .type = S3C_IRQTYPE_NONE }, /* reserved */
681 { .type = S3C_IRQTYPE_NONE }, /* reserved */
682 { .type = S3C_IRQTYPE_NONE }, /* reserved */
683 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
684 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
685 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
686 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
687 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
688 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
689 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
690 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
691 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
692 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
693 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
694 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
695 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
696 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
697};
622 698
623 /* external interrupts */ 699static struct s3c_irq_data init_s3c2416_second[32] = {
700 { .type = S3C_IRQTYPE_EDGE }, /* 2D */
701 { .type = S3C_IRQTYPE_EDGE }, /* IIC1 */
702 { .type = S3C_IRQTYPE_NONE }, /* reserved */
703 { .type = S3C_IRQTYPE_NONE }, /* reserved */
704 { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
705 { .type = S3C_IRQTYPE_EDGE }, /* PCM1 */
706 { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
707 { .type = S3C_IRQTYPE_EDGE }, /* I2S1 */
708};
624 709
625 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { 710void __init s3c2416_init_irq(void)
626 irqdbf("registering irq %d (ext int)\n", irqno); 711{
627 irq_set_chip_and_handler(irqno, &s3c_irq_eint0t4, 712 struct s3c_irq_intc *main_intc;
628 handle_edge_irq); 713
629 set_irq_flags(irqno, IRQF_VALID); 714 pr_info("S3C2416: IRQ Support\n");
630 } 715
716#ifdef CONFIG_FIQ
717 init_FIQ(FIQ_START);
718#endif
631 719
632 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { 720 main_intc = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, 0x4a000000);
633 irqdbf("registering irq %d (extended s3c irq)\n", irqno); 721 if (IS_ERR(main_intc)) {
634 irq_set_chip_and_handler(irqno, &s3c_irqext_chip, 722 pr_err("irq: could not create main interrupt controller\n");
635 handle_edge_irq); 723 return;
636 set_irq_flags(irqno, IRQF_VALID);
637 } 724 }
638 725
639 /* register the uart interrupts */ 726 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
727 s3c24xx_init_intc(NULL, &init_s3c2416subint[0], main_intc, 0x4a000018);
640 728
641 irqdbf("s3c2410: registering external interrupts\n"); 729 s3c24xx_init_intc(NULL, &init_s3c2416_second[0], NULL, 0x4a000040);
730}
642 731
643 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { 732#endif
644 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
645 irq_set_chip_and_handler(irqno, &s3c_irq_uart0,
646 handle_level_irq);
647 set_irq_flags(irqno, IRQF_VALID);
648 }
649 733
650 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { 734#ifdef CONFIG_CPU_S3C2443
651 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); 735static struct s3c_irq_data init_s3c2443base[32] = {
652 irq_set_chip_and_handler(irqno, &s3c_irq_uart1, 736 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
653 handle_level_irq); 737 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
654 set_irq_flags(irqno, IRQF_VALID); 738 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
655 } 739 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
740 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
741 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
742 { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
743 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
744 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
745 { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
746 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
747 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
748 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
749 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
750 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
751 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
752 { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
753 { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
754 { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
755 { .type = S3C_IRQTYPE_EDGE, }, /* CFON */
756 { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
757 { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
758 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
759 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
760 { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
761 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
762 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
763 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
764 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
765 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
766 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
767 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
768};
656 769
657 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
658 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
659 irq_set_chip_and_handler(irqno, &s3c_irq_uart2,
660 handle_level_irq);
661 set_irq_flags(irqno, IRQF_VALID);
662 }
663 770
664 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { 771static struct s3c_irq_data init_s3c2443subint[32] = {
665 irqdbf("registering irq %d (s3c adc irq)\n", irqno); 772 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
666 irq_set_chip_and_handler(irqno, &s3c_irq_adc, handle_edge_irq); 773 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
667 set_irq_flags(irqno, IRQF_VALID); 774 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
775 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
776 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
777 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
778 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
779 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
780 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
781 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
782 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
783 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
784 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
785 { .type = S3C_IRQTYPE_NONE }, /* reserved */
786 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
787 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
788 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
789 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
790 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
791 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
792 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
793 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
794 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
795 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
796 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
797 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
798 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
799 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
800 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
801};
802
803void __init s3c2443_init_irq(void)
804{
805 struct s3c_irq_intc *main_intc;
806
807 pr_info("S3C2443: IRQ Support\n");
808
809#ifdef CONFIG_FIQ
810 init_FIQ(FIQ_START);
811#endif
812
813 main_intc = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, 0x4a000000);
814 if (IS_ERR(main_intc)) {
815 pr_err("irq: could not create main interrupt controller\n");
816 return;
668 } 817 }
669 818
670 irqdbf("s3c2410: registered interrupt handlers\n"); 819 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
820 s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018);
671} 821}
672 822#endif
673struct syscore_ops s3c24xx_irq_syscore_ops = {
674 .suspend = s3c24xx_irq_suspend,
675 .resume = s3c24xx_irq_resume,
676};
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 887a0c954379..f6fcadeee969 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -109,17 +109,11 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
109#ifdef CONFIG_PM 109#ifdef CONFIG_PM
110extern int s3c_irq_wake(struct irq_data *data, unsigned int state); 110extern int s3c_irq_wake(struct irq_data *data, unsigned int state);
111extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); 111extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
112extern int s3c24xx_irq_suspend(void);
113extern void s3c24xx_irq_resume(void);
114#else 112#else
115#define s3c_irq_wake NULL 113#define s3c_irq_wake NULL
116#define s3c_irqext_wake NULL 114#define s3c_irqext_wake NULL
117#define s3c24xx_irq_suspend NULL
118#define s3c24xx_irq_resume NULL
119#endif 115#endif
120 116
121extern struct syscore_ops s3c24xx_irq_syscore_ops;
122
123/* PM debug functions */ 117/* PM debug functions */
124 118
125#ifdef CONFIG_SAMSUNG_PM_DEBUG 119#ifdef CONFIG_SAMSUNG_PM_DEBUG
diff --git a/arch/arm/plat-samsung/include/plat/s3c2416.h b/arch/arm/plat-samsung/include/plat/s3c2416.h
index 7178e338e25e..f27399a3c68d 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2416.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2416.h
@@ -25,6 +25,7 @@ extern int s3c2416_baseclk_add(void);
25 25
26extern void s3c2416_restart(char mode, const char *cmd); 26extern void s3c2416_restart(char mode, const char *cmd);
27 27
28extern void s3c2416_init_irq(void);
28extern struct syscore_ops s3c2416_irq_syscore_ops; 29extern struct syscore_ops s3c2416_irq_syscore_ops;
29 30
30#else 31#else
diff --git a/arch/arm/plat-samsung/include/plat/s3c2443.h b/arch/arm/plat-samsung/include/plat/s3c2443.h
index a5b794ff838b..71b88ec48956 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2443.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2443.h
@@ -25,6 +25,8 @@ extern void s3c2443_init_clocks(int xtal);
25extern int s3c2443_baseclk_add(void); 25extern int s3c2443_baseclk_add(void);
26 26
27extern void s3c2443_restart(char mode, const char *cmd); 27extern void s3c2443_restart(char mode, const char *cmd);
28
29extern void s3c2443_init_irq(void);
28#else 30#else
29#define s3c2443_init_clocks NULL 31#define s3c2443_init_clocks NULL
30#define s3c2443_init_uarts NULL 32#define s3c2443_init_uarts NULL