aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-s3c24xx.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 15:31:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 15:31:18 -0400
commit6fa52ed33bea997374a88dbacbba5bf8c7ac4fef (patch)
treea0904b78d66c9b99d6acf944cf58bcaa0cffc511 /drivers/irqchip/irq-s3c24xx.c
parent1db772216f48978d5146b858586f6178433aad38 (diff)
parentbc8fd900c4d460b4e4bf785bb48bfced0ac9941b (diff)
Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver changes from Olof Johansson: "This is a rather large set of patches for device drivers that for one reason or another the subsystem maintainer preferred to get merged through the arm-soc tree. There are both new drivers as well as existing drivers that are getting converted from platform-specific code into standalone drivers using the appropriate subsystem specific interfaces. In particular, we can now have pinctrl, clk, clksource and irqchip drivers in one file per driver, without the need to call into platform specific interface, or to get called from platform specific code, as long as all information about the hardware is provided through a device tree. Most of the drivers we touch this time are for clocksource. Since now most of them are part of drivers/clocksource, I expect that we won't have to touch these again from arm-soc and can let the clocksource maintainers take care of these in the future. Another larger part of this series is specific to the exynos platform, which is seeing some significant effort in upstreaming and modernization of its device drivers this time around, which unfortunately is also the cause for the churn and a lot of the merge conflicts. There is one new subsystem that gets merged as part of this series: the reset controller interface, which is a very simple interface for taking devices on the SoC out of reset or back into reset. Patches to use this interface on i.MX follow later in this merge window, and we are going to have other platforms (at least tegra and sirf) get converted in 3.11. This will let us get rid of platform specific callbacks in a number of platform independent device drivers." * tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (256 commits) irqchip: s3c24xx: add missing __init annotations ARM: dts: Disable the RTC by default on exynos5 clk: exynos5250: Fix parent clock for sclk_mmc{0,1,2,3} ARM: exynos: restore mach/regs-clock.h for exynos5 clocksource: exynos_mct: fix build error on non-DT pinctrl: vt8500: wmt: Fix checking return value of pinctrl_register() irqchip: vt8500: Convert arch-vt8500 to new irqchip infrastructure reset: NULL deref on allocation failure reset: Add reset controller API dt: describe base reset signal binding ARM: EXYNOS: Add arm-pmu DT binding for exynos421x ARM: EXYNOS: Add arm-pmu DT binding for exynos5250 ARM: EXYNOS: Enable PMUs for exynos4 irqchip: exynos-combiner: Correct combined IRQs for exynos4 irqchip: exynos-combiner: Add set_irq_affinity function for combiner_irq ARM: EXYNOS: fix compilation error introduced due to common clock migration clk: exynos5250: Fix divider values for sclk_mmc{0,1,2,3} clk: exynos4: export clocks required for fimc-is clk: samsung: Fix compilation error clk: tegra: fix enum tegra114_clk to match binding ...
Diffstat (limited to 'drivers/irqchip/irq-s3c24xx.c')
-rw-r--r--drivers/irqchip/irq-s3c24xx.c1356
1 files changed, 1356 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
new file mode 100644
index 000000000000..bbcc944ed94f
--- /dev/null
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -0,0 +1,1356 @@
1/*
2 * S3C24XX IRQ handling
3 *
4 * Copyright (c) 2003-2004 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de>
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
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/module.h>
22#include <linux/io.h>
23#include <linux/err.h>
24#include <linux/interrupt.h>
25#include <linux/ioport.h>
26#include <linux/device.h>
27#include <linux/irqdomain.h>
28#include <linux/irqchip/chained_irq.h>
29#include <linux/of.h>
30#include <linux/of_irq.h>
31#include <linux/of_address.h>
32
33#include <asm/exception.h>
34#include <asm/mach/irq.h>
35
36#include <mach/regs-irq.h>
37#include <mach/regs-gpio.h>
38
39#include <plat/cpu.h>
40#include <plat/regs-irqtype.h>
41#include <plat/pm.h>
42
43#include "irqchip.h"
44
45#define S3C_IRQTYPE_NONE 0
46#define S3C_IRQTYPE_EINT 1
47#define S3C_IRQTYPE_EDGE 2
48#define S3C_IRQTYPE_LEVEL 3
49
50struct s3c_irq_data {
51 unsigned int type;
52 unsigned long offset;
53 unsigned long parent_irq;
54
55 /* data gets filled during init */
56 struct s3c_irq_intc *intc;
57 unsigned long sub_bits;
58 struct s3c_irq_intc *sub_intc;
59};
60
61/*
62 * Sructure holding the controller data
63 * @reg_pending register holding pending irqs
64 * @reg_intpnd special register intpnd in main intc
65 * @reg_mask mask register
66 * @domain irq_domain of the controller
67 * @parent parent controller for ext and sub irqs
68 * @irqs irq-data, always s3c_irq_data[32]
69 */
70struct s3c_irq_intc {
71 void __iomem *reg_pending;
72 void __iomem *reg_intpnd;
73 void __iomem *reg_mask;
74 struct irq_domain *domain;
75 struct s3c_irq_intc *parent;
76 struct s3c_irq_data *irqs;
77};
78
79/*
80 * Array holding pointers to the global controller structs
81 * [0] ... main_intc
82 * [1] ... sub_intc
83 * [2] ... main_intc2 on s3c2416
84 */
85static struct s3c_irq_intc *s3c_intc[3];
86
87static void s3c_irq_mask(struct irq_data *data)
88{
89 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
90 struct s3c_irq_intc *intc = irq_data->intc;
91 struct s3c_irq_intc *parent_intc = intc->parent;
92 struct s3c_irq_data *parent_data;
93 unsigned long mask;
94 unsigned int irqno;
95
96 mask = __raw_readl(intc->reg_mask);
97 mask |= (1UL << irq_data->offset);
98 __raw_writel(mask, intc->reg_mask);
99
100 if (parent_intc) {
101 parent_data = &parent_intc->irqs[irq_data->parent_irq];
102
103 /* check to see if we need to mask the parent IRQ
104 * The parent_irq is always in main_intc, so the hwirq
105 * for find_mapping does not need an offset in any case.
106 */
107 if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
108 irqno = irq_find_mapping(parent_intc->domain,
109 irq_data->parent_irq);
110 s3c_irq_mask(irq_get_irq_data(irqno));
111 }
112 }
113}
114
115static void s3c_irq_unmask(struct irq_data *data)
116{
117 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
118 struct s3c_irq_intc *intc = irq_data->intc;
119 struct s3c_irq_intc *parent_intc = intc->parent;
120 unsigned long mask;
121 unsigned int irqno;
122
123 mask = __raw_readl(intc->reg_mask);
124 mask &= ~(1UL << irq_data->offset);
125 __raw_writel(mask, intc->reg_mask);
126
127 if (parent_intc) {
128 irqno = irq_find_mapping(parent_intc->domain,
129 irq_data->parent_irq);
130 s3c_irq_unmask(irq_get_irq_data(irqno));
131 }
132}
133
134static inline void s3c_irq_ack(struct irq_data *data)
135{
136 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
137 struct s3c_irq_intc *intc = irq_data->intc;
138 unsigned long bitval = 1UL << irq_data->offset;
139
140 __raw_writel(bitval, intc->reg_pending);
141 if (intc->reg_intpnd)
142 __raw_writel(bitval, intc->reg_intpnd);
143}
144
145static int s3c_irq_type(struct irq_data *data, unsigned int type)
146{
147 switch (type) {
148 case IRQ_TYPE_NONE:
149 break;
150 case IRQ_TYPE_EDGE_RISING:
151 case IRQ_TYPE_EDGE_FALLING:
152 case IRQ_TYPE_EDGE_BOTH:
153 irq_set_handler(data->irq, handle_edge_irq);
154 break;
155 case IRQ_TYPE_LEVEL_LOW:
156 case IRQ_TYPE_LEVEL_HIGH:
157 irq_set_handler(data->irq, handle_level_irq);
158 break;
159 default:
160 pr_err("No such irq type %d", type);
161 return -EINVAL;
162 }
163
164 return 0;
165}
166
167static int s3c_irqext_type_set(void __iomem *gpcon_reg,
168 void __iomem *extint_reg,
169 unsigned long gpcon_offset,
170 unsigned long extint_offset,
171 unsigned int type)
172{
173 unsigned long newvalue = 0, value;
174
175 /* Set the GPIO to external interrupt mode */
176 value = __raw_readl(gpcon_reg);
177 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
178 __raw_writel(value, gpcon_reg);
179
180 /* Set the external interrupt to pointed trigger type */
181 switch (type)
182 {
183 case IRQ_TYPE_NONE:
184 pr_warn("No edge setting!\n");
185 break;
186
187 case IRQ_TYPE_EDGE_RISING:
188 newvalue = S3C2410_EXTINT_RISEEDGE;
189 break;
190
191 case IRQ_TYPE_EDGE_FALLING:
192 newvalue = S3C2410_EXTINT_FALLEDGE;
193 break;
194
195 case IRQ_TYPE_EDGE_BOTH:
196 newvalue = S3C2410_EXTINT_BOTHEDGE;
197 break;
198
199 case IRQ_TYPE_LEVEL_LOW:
200 newvalue = S3C2410_EXTINT_LOWLEV;
201 break;
202
203 case IRQ_TYPE_LEVEL_HIGH:
204 newvalue = S3C2410_EXTINT_HILEV;
205 break;
206
207 default:
208 pr_err("No such irq type %d", type);
209 return -EINVAL;
210 }
211
212 value = __raw_readl(extint_reg);
213 value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
214 __raw_writel(value, extint_reg);
215
216 return 0;
217}
218
219static int s3c_irqext_type(struct irq_data *data, unsigned int type)
220{
221 void __iomem *extint_reg;
222 void __iomem *gpcon_reg;
223 unsigned long gpcon_offset, extint_offset;
224
225 if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
226 gpcon_reg = S3C2410_GPFCON;
227 extint_reg = S3C24XX_EXTINT0;
228 gpcon_offset = (data->hwirq) * 2;
229 extint_offset = (data->hwirq) * 4;
230 } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
231 gpcon_reg = S3C2410_GPGCON;
232 extint_reg = S3C24XX_EXTINT1;
233 gpcon_offset = (data->hwirq - 8) * 2;
234 extint_offset = (data->hwirq - 8) * 4;
235 } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
236 gpcon_reg = S3C2410_GPGCON;
237 extint_reg = S3C24XX_EXTINT2;
238 gpcon_offset = (data->hwirq - 8) * 2;
239 extint_offset = (data->hwirq - 16) * 4;
240 } else {
241 return -EINVAL;
242 }
243
244 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
245 extint_offset, type);
246}
247
248static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
249{
250 void __iomem *extint_reg;
251 void __iomem *gpcon_reg;
252 unsigned long gpcon_offset, extint_offset;
253
254 if ((data->hwirq >= 0) && (data->hwirq <= 3)) {
255 gpcon_reg = S3C2410_GPFCON;
256 extint_reg = S3C24XX_EXTINT0;
257 gpcon_offset = (data->hwirq) * 2;
258 extint_offset = (data->hwirq) * 4;
259 } else {
260 return -EINVAL;
261 }
262
263 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
264 extint_offset, type);
265}
266
267static struct irq_chip s3c_irq_chip = {
268 .name = "s3c",
269 .irq_ack = s3c_irq_ack,
270 .irq_mask = s3c_irq_mask,
271 .irq_unmask = s3c_irq_unmask,
272 .irq_set_type = s3c_irq_type,
273 .irq_set_wake = s3c_irq_wake
274};
275
276static struct irq_chip s3c_irq_level_chip = {
277 .name = "s3c-level",
278 .irq_mask = s3c_irq_mask,
279 .irq_unmask = s3c_irq_unmask,
280 .irq_ack = s3c_irq_ack,
281 .irq_set_type = s3c_irq_type,
282};
283
284static struct irq_chip s3c_irqext_chip = {
285 .name = "s3c-ext",
286 .irq_mask = s3c_irq_mask,
287 .irq_unmask = s3c_irq_unmask,
288 .irq_ack = s3c_irq_ack,
289 .irq_set_type = s3c_irqext_type,
290 .irq_set_wake = s3c_irqext_wake
291};
292
293static struct irq_chip s3c_irq_eint0t4 = {
294 .name = "s3c-ext0",
295 .irq_ack = s3c_irq_ack,
296 .irq_mask = s3c_irq_mask,
297 .irq_unmask = s3c_irq_unmask,
298 .irq_set_wake = s3c_irq_wake,
299 .irq_set_type = s3c_irqext0_type,
300};
301
302static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
303{
304 struct irq_chip *chip = irq_desc_get_chip(desc);
305 struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc);
306 struct s3c_irq_intc *intc = irq_data->intc;
307 struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
308 unsigned long src;
309 unsigned long msk;
310 unsigned int n;
311 unsigned int offset;
312
313 /* we're using individual domains for the non-dt case
314 * and one big domain for the dt case where the subintc
315 * starts at hwirq number 32.
316 */
317 offset = (intc->domain->of_node) ? 32 : 0;
318
319 chained_irq_enter(chip, desc);
320
321 src = __raw_readl(sub_intc->reg_pending);
322 msk = __raw_readl(sub_intc->reg_mask);
323
324 src &= ~msk;
325 src &= irq_data->sub_bits;
326
327 while (src) {
328 n = __ffs(src);
329 src &= ~(1 << n);
330 irq = irq_find_mapping(sub_intc->domain, offset + n);
331 generic_handle_irq(irq);
332 }
333
334 chained_irq_exit(chip, desc);
335}
336
337static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
338 struct pt_regs *regs, int intc_offset)
339{
340 int pnd;
341 int offset;
342 int irq;
343
344 pnd = __raw_readl(intc->reg_intpnd);
345 if (!pnd)
346 return false;
347
348 /* non-dt machines use individual domains */
349 if (!intc->domain->of_node)
350 intc_offset = 0;
351
352 /* We have a problem that the INTOFFSET register does not always
353 * show one interrupt. Occasionally we get two interrupts through
354 * the prioritiser, and this causes the INTOFFSET register to show
355 * what looks like the logical-or of the two interrupt numbers.
356 *
357 * Thanks to Klaus, Shannon, et al for helping to debug this problem
358 */
359 offset = __raw_readl(intc->reg_intpnd + 4);
360
361 /* Find the bit manually, when the offset is wrong.
362 * The pending register only ever contains the one bit of the next
363 * interrupt to handle.
364 */
365 if (!(pnd & (1 << offset)))
366 offset = __ffs(pnd);
367
368 irq = irq_find_mapping(intc->domain, intc_offset + offset);
369 handle_IRQ(irq, regs);
370 return true;
371}
372
373asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
374{
375 do {
376 if (likely(s3c_intc[0]))
377 if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
378 continue;
379
380 if (s3c_intc[2])
381 if (s3c24xx_handle_intc(s3c_intc[2], regs, 64))
382 continue;
383
384 break;
385 } while (1);
386}
387
388#ifdef CONFIG_FIQ
389/**
390 * s3c24xx_set_fiq - set the FIQ routing
391 * @irq: IRQ number to route to FIQ on processor.
392 * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing.
393 *
394 * Change the state of the IRQ to FIQ routing depending on @irq and @on. If
395 * @on is true, the @irq is checked to see if it can be routed and the
396 * interrupt controller updated to route the IRQ. If @on is false, the FIQ
397 * routing is cleared, regardless of which @irq is specified.
398 */
399int s3c24xx_set_fiq(unsigned int irq, bool on)
400{
401 u32 intmod;
402 unsigned offs;
403
404 if (on) {
405 offs = irq - FIQ_START;
406 if (offs > 31)
407 return -EINVAL;
408
409 intmod = 1 << offs;
410 } else {
411 intmod = 0;
412 }
413
414 __raw_writel(intmod, S3C2410_INTMOD);
415 return 0;
416}
417
418EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
419#endif
420
421static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
422 irq_hw_number_t hw)
423{
424 struct s3c_irq_intc *intc = h->host_data;
425 struct s3c_irq_data *irq_data = &intc->irqs[hw];
426 struct s3c_irq_intc *parent_intc;
427 struct s3c_irq_data *parent_irq_data;
428 unsigned int irqno;
429
430 /* attach controller pointer to irq_data */
431 irq_data->intc = intc;
432 irq_data->offset = hw;
433
434 parent_intc = intc->parent;
435
436 /* set handler and flags */
437 switch (irq_data->type) {
438 case S3C_IRQTYPE_NONE:
439 return 0;
440 case S3C_IRQTYPE_EINT:
441 /* On the S3C2412, the EINT0to3 have a parent irq
442 * but need the s3c_irq_eint0t4 chip
443 */
444 if (parent_intc && (!soc_is_s3c2412() || hw >= 4))
445 irq_set_chip_and_handler(virq, &s3c_irqext_chip,
446 handle_edge_irq);
447 else
448 irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
449 handle_edge_irq);
450 break;
451 case S3C_IRQTYPE_EDGE:
452 if (parent_intc || intc->reg_pending == S3C2416_SRCPND2)
453 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
454 handle_edge_irq);
455 else
456 irq_set_chip_and_handler(virq, &s3c_irq_chip,
457 handle_edge_irq);
458 break;
459 case S3C_IRQTYPE_LEVEL:
460 if (parent_intc)
461 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
462 handle_level_irq);
463 else
464 irq_set_chip_and_handler(virq, &s3c_irq_chip,
465 handle_level_irq);
466 break;
467 default:
468 pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
469 return -EINVAL;
470 }
471
472 irq_set_chip_data(virq, irq_data);
473
474 set_irq_flags(virq, IRQF_VALID);
475
476 if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) {
477 if (irq_data->parent_irq > 31) {
478 pr_err("irq-s3c24xx: parent irq %lu is out of range\n",
479 irq_data->parent_irq);
480 goto err;
481 }
482
483 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
484 parent_irq_data->sub_intc = intc;
485 parent_irq_data->sub_bits |= (1UL << hw);
486
487 /* attach the demuxer to the parent irq */
488 irqno = irq_find_mapping(parent_intc->domain,
489 irq_data->parent_irq);
490 if (!irqno) {
491 pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
492 irq_data->parent_irq);
493 goto err;
494 }
495 irq_set_chained_handler(irqno, s3c_irq_demux);
496 }
497
498 return 0;
499
500err:
501 set_irq_flags(virq, 0);
502
503 /* the only error can result from bad mapping data*/
504 return -EINVAL;
505}
506
507static struct irq_domain_ops s3c24xx_irq_ops = {
508 .map = s3c24xx_irq_map,
509 .xlate = irq_domain_xlate_twocell,
510};
511
512static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
513{
514 void __iomem *reg_source;
515 unsigned long pend;
516 unsigned long last;
517 int i;
518
519 /* if intpnd is set, read the next pending irq from there */
520 reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
521
522 last = 0;
523 for (i = 0; i < 4; i++) {
524 pend = __raw_readl(reg_source);
525
526 if (pend == 0 || pend == last)
527 break;
528
529 __raw_writel(pend, intc->reg_pending);
530 if (intc->reg_intpnd)
531 __raw_writel(pend, intc->reg_intpnd);
532
533 pr_info("irq: clearing pending status %08x\n", (int)pend);
534 last = pend;
535 }
536}
537
538static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np,
539 struct s3c_irq_data *irq_data,
540 struct s3c_irq_intc *parent,
541 unsigned long address)
542{
543 struct s3c_irq_intc *intc;
544 void __iomem *base = (void *)0xf6000000; /* static mapping */
545 int irq_num;
546 int irq_start;
547 int ret;
548
549 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
550 if (!intc)
551 return ERR_PTR(-ENOMEM);
552
553 intc->irqs = irq_data;
554
555 if (parent)
556 intc->parent = parent;
557
558 /* select the correct data for the controller.
559 * Need to hard code the irq num start and offset
560 * to preserve the static mapping for now
561 */
562 switch (address) {
563 case 0x4a000000:
564 pr_debug("irq: found main intc\n");
565 intc->reg_pending = base;
566 intc->reg_mask = base + 0x08;
567 intc->reg_intpnd = base + 0x10;
568 irq_num = 32;
569 irq_start = S3C2410_IRQ(0);
570 break;
571 case 0x4a000018:
572 pr_debug("irq: found subintc\n");
573 intc->reg_pending = base + 0x18;
574 intc->reg_mask = base + 0x1c;
575 irq_num = 29;
576 irq_start = S3C2410_IRQSUB(0);
577 break;
578 case 0x4a000040:
579 pr_debug("irq: found intc2\n");
580 intc->reg_pending = base + 0x40;
581 intc->reg_mask = base + 0x48;
582 intc->reg_intpnd = base + 0x50;
583 irq_num = 8;
584 irq_start = S3C2416_IRQ(0);
585 break;
586 case 0x560000a4:
587 pr_debug("irq: found eintc\n");
588 base = (void *)0xfd000000;
589
590 intc->reg_mask = base + 0xa4;
591 intc->reg_pending = base + 0xa8;
592 irq_num = 24;
593 irq_start = S3C2410_IRQ(32);
594 break;
595 default:
596 pr_err("irq: unsupported controller address\n");
597 ret = -EINVAL;
598 goto err;
599 }
600
601 /* now that all the data is complete, init the irq-domain */
602 s3c24xx_clear_intc(intc);
603 intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
604 0, &s3c24xx_irq_ops,
605 intc);
606 if (!intc->domain) {
607 pr_err("irq: could not create irq-domain\n");
608 ret = -EINVAL;
609 goto err;
610 }
611
612 set_handle_irq(s3c24xx_handle_irq);
613
614 return intc;
615
616err:
617 kfree(intc);
618 return ERR_PTR(ret);
619}
620
621static struct s3c_irq_data init_eint[32] = {
622 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
623 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
624 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
625 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
626 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
627 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
628 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
629 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
630 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
631 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
632 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
633 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
634 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
635 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
636 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
637 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
638 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
639 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
640 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
641 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
642 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
643 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
644 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
645 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
646};
647
648#ifdef CONFIG_CPU_S3C2410
649static struct s3c_irq_data init_s3c2410base[32] = {
650 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
651 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
652 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
653 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
654 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
655 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
656 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
657 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
658 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
659 { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
660 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
661 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
662 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
663 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
664 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
665 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
666 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
667 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
668 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
669 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
670 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
671 { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
672 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
673 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
674 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
675 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
676 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
677 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
678 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
679 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
680 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
681 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
682};
683
684static struct s3c_irq_data init_s3c2410subint[32] = {
685 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
686 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
687 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
688 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
689 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
690 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
691 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
692 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
693 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
694 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
695 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
696};
697
698void __init s3c2410_init_irq(void)
699{
700#ifdef CONFIG_FIQ
701 init_FIQ(FIQ_START);
702#endif
703
704 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL,
705 0x4a000000);
706 if (IS_ERR(s3c_intc[0])) {
707 pr_err("irq: could not create main interrupt controller\n");
708 return;
709 }
710
711 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0],
712 s3c_intc[0], 0x4a000018);
713 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
714}
715#endif
716
717#ifdef CONFIG_CPU_S3C2412
718static struct s3c_irq_data init_s3c2412base[32] = {
719 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */
720 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */
721 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */
722 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */
723 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
724 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
725 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
726 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
727 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
728 { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
729 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
730 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
731 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
732 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
733 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
734 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
735 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
736 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
737 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
738 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
739 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
740 { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */
741 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
742 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
743 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
744 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
745 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
746 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
747 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
748 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
749 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
750 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
751};
752
753static struct s3c_irq_data init_s3c2412eint[32] = {
754 { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */
755 { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */
756 { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */
757 { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */
758 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
759 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
760 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
761 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
762 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
763 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
764 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
765 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
766 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
767 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
768 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
769 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
770 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
771 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
772 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
773 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
774 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
775 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
776 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
777 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
778};
779
780static struct s3c_irq_data init_s3c2412subint[32] = {
781 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
782 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
783 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
784 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
785 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
786 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
787 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
788 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
789 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
790 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
791 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
792 { .type = S3C_IRQTYPE_NONE, },
793 { .type = S3C_IRQTYPE_NONE, },
794 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */
795 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */
796};
797
798void __init s3c2412_init_irq(void)
799{
800 pr_info("S3C2412: IRQ Support\n");
801
802#ifdef CONFIG_FIQ
803 init_FIQ(FIQ_START);
804#endif
805
806 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL,
807 0x4a000000);
808 if (IS_ERR(s3c_intc[0])) {
809 pr_err("irq: could not create main interrupt controller\n");
810 return;
811 }
812
813 s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4);
814 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0],
815 s3c_intc[0], 0x4a000018);
816}
817#endif
818
819#ifdef CONFIG_CPU_S3C2416
820static struct s3c_irq_data init_s3c2416base[32] = {
821 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
822 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
823 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
824 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
825 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
826 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
827 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
828 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
829 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
830 { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
831 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
832 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
833 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
834 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
835 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
836 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
837 { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
838 { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
839 { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
840 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
841 { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
842 { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
843 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
844 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
845 { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
846 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
847 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
848 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
849 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
850 { .type = S3C_IRQTYPE_NONE, },
851 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
852 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
853};
854
855static struct s3c_irq_data init_s3c2416subint[32] = {
856 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
857 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
858 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
859 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
860 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
861 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
862 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
863 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
864 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
865 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
866 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
867 { .type = S3C_IRQTYPE_NONE }, /* reserved */
868 { .type = S3C_IRQTYPE_NONE }, /* reserved */
869 { .type = S3C_IRQTYPE_NONE }, /* reserved */
870 { .type = S3C_IRQTYPE_NONE }, /* reserved */
871 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
872 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
873 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
874 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
875 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
876 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
877 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
878 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
879 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
880 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
881 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
882 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
883 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
884 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
885};
886
887static struct s3c_irq_data init_s3c2416_second[32] = {
888 { .type = S3C_IRQTYPE_EDGE }, /* 2D */
889 { .type = S3C_IRQTYPE_NONE }, /* reserved */
890 { .type = S3C_IRQTYPE_NONE }, /* reserved */
891 { .type = S3C_IRQTYPE_NONE }, /* reserved */
892 { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
893 { .type = S3C_IRQTYPE_NONE }, /* reserved */
894 { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
895};
896
897void __init s3c2416_init_irq(void)
898{
899 pr_info("S3C2416: IRQ Support\n");
900
901#ifdef CONFIG_FIQ
902 init_FIQ(FIQ_START);
903#endif
904
905 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL,
906 0x4a000000);
907 if (IS_ERR(s3c_intc[0])) {
908 pr_err("irq: could not create main interrupt controller\n");
909 return;
910 }
911
912 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
913 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0],
914 s3c_intc[0], 0x4a000018);
915
916 s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0],
917 NULL, 0x4a000040);
918}
919
920#endif
921
922#ifdef CONFIG_CPU_S3C2440
923static struct s3c_irq_data init_s3c2440base[32] = {
924 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
925 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
926 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
927 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
928 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
929 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
930 { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
931 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
932 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
933 { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
934 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
935 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
936 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
937 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
938 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
939 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
940 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
941 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
942 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
943 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
944 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
945 { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
946 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
947 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
948 { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
949 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
950 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
951 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
952 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
953 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
954 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
955 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
956};
957
958static struct s3c_irq_data init_s3c2440subint[32] = {
959 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
960 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
961 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
962 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
963 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
964 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
965 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
966 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
967 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
968 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
969 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
970 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
971 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
972 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
973 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
974};
975
976void __init s3c2440_init_irq(void)
977{
978 pr_info("S3C2440: IRQ Support\n");
979
980#ifdef CONFIG_FIQ
981 init_FIQ(FIQ_START);
982#endif
983
984 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL,
985 0x4a000000);
986 if (IS_ERR(s3c_intc[0])) {
987 pr_err("irq: could not create main interrupt controller\n");
988 return;
989 }
990
991 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
992 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0],
993 s3c_intc[0], 0x4a000018);
994}
995#endif
996
997#ifdef CONFIG_CPU_S3C2442
998static struct s3c_irq_data init_s3c2442base[32] = {
999 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
1000 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
1001 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
1002 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
1003 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
1004 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
1005 { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
1006 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
1007 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
1008 { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
1009 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
1010 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
1011 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
1012 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
1013 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
1014 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
1015 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
1016 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
1017 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
1018 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
1019 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
1020 { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
1021 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
1022 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
1023 { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
1024 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
1025 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
1026 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
1027 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
1028 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
1029 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
1030 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
1031};
1032
1033static struct s3c_irq_data init_s3c2442subint[32] = {
1034 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
1035 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
1036 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
1037 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
1038 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
1039 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
1040 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
1041 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
1042 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
1043 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
1044 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
1045 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
1046 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
1047};
1048
1049void __init s3c2442_init_irq(void)
1050{
1051 pr_info("S3C2442: IRQ Support\n");
1052
1053#ifdef CONFIG_FIQ
1054 init_FIQ(FIQ_START);
1055#endif
1056
1057 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL,
1058 0x4a000000);
1059 if (IS_ERR(s3c_intc[0])) {
1060 pr_err("irq: could not create main interrupt controller\n");
1061 return;
1062 }
1063
1064 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
1065 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0],
1066 s3c_intc[0], 0x4a000018);
1067}
1068#endif
1069
1070#ifdef CONFIG_CPU_S3C2443
1071static struct s3c_irq_data init_s3c2443base[32] = {
1072 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
1073 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
1074 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
1075 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
1076 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
1077 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
1078 { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
1079 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
1080 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
1081 { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
1082 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
1083 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
1084 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
1085 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
1086 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
1087 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
1088 { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
1089 { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
1090 { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
1091 { .type = S3C_IRQTYPE_EDGE, }, /* CFON */
1092 { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
1093 { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
1094 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
1095 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
1096 { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
1097 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
1098 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
1099 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
1100 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
1101 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
1102 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
1103 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
1104};
1105
1106
1107static struct s3c_irq_data init_s3c2443subint[32] = {
1108 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
1109 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
1110 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
1111 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
1112 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
1113 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
1114 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
1115 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
1116 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
1117 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
1118 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
1119 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
1120 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
1121 { .type = S3C_IRQTYPE_NONE }, /* reserved */
1122 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
1123 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
1124 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
1125 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
1126 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
1127 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
1128 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
1129 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
1130 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
1131 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
1132 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
1133 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
1134 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
1135 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
1136 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
1137};
1138
1139void __init s3c2443_init_irq(void)
1140{
1141 pr_info("S3C2443: IRQ Support\n");
1142
1143#ifdef CONFIG_FIQ
1144 init_FIQ(FIQ_START);
1145#endif
1146
1147 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL,
1148 0x4a000000);
1149 if (IS_ERR(s3c_intc[0])) {
1150 pr_err("irq: could not create main interrupt controller\n");
1151 return;
1152 }
1153
1154 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
1155 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0],
1156 s3c_intc[0], 0x4a000018);
1157}
1158#endif
1159
1160#ifdef CONFIG_OF
1161static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq,
1162 irq_hw_number_t hw)
1163{
1164 unsigned int ctrl_num = hw / 32;
1165 unsigned int intc_hw = hw % 32;
1166 struct s3c_irq_intc *intc = s3c_intc[ctrl_num];
1167 struct s3c_irq_intc *parent_intc = intc->parent;
1168 struct s3c_irq_data *irq_data = &intc->irqs[intc_hw];
1169
1170 /* attach controller pointer to irq_data */
1171 irq_data->intc = intc;
1172 irq_data->offset = intc_hw;
1173
1174 if (!parent_intc)
1175 irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq);
1176 else
1177 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
1178 handle_edge_irq);
1179
1180 irq_set_chip_data(virq, irq_data);
1181
1182 set_irq_flags(virq, IRQF_VALID);
1183
1184 return 0;
1185}
1186
1187/* Translate our of irq notation
1188 * format: <ctrl_num ctrl_irq parent_irq type>
1189 */
1190static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,
1191 const u32 *intspec, unsigned int intsize,
1192 irq_hw_number_t *out_hwirq, unsigned int *out_type)
1193{
1194 struct s3c_irq_intc *intc;
1195 struct s3c_irq_intc *parent_intc;
1196 struct s3c_irq_data *irq_data;
1197 struct s3c_irq_data *parent_irq_data;
1198 int irqno;
1199
1200 if (WARN_ON(intsize < 4))
1201 return -EINVAL;
1202
1203 if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {
1204 pr_err("controller number %d invalid\n", intspec[0]);
1205 return -EINVAL;
1206 }
1207 intc = s3c_intc[intspec[0]];
1208
1209 *out_hwirq = intspec[0] * 32 + intspec[2];
1210 *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
1211
1212 parent_intc = intc->parent;
1213 if (parent_intc) {
1214 irq_data = &intc->irqs[intspec[2]];
1215 irq_data->parent_irq = intspec[1];
1216 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
1217 parent_irq_data->sub_intc = intc;
1218 parent_irq_data->sub_bits |= (1UL << intspec[2]);
1219
1220 /* parent_intc is always s3c_intc[0], so no offset */
1221 irqno = irq_create_mapping(parent_intc->domain, intspec[1]);
1222 if (irqno < 0) {
1223 pr_err("irq: could not map parent interrupt\n");
1224 return irqno;
1225 }
1226
1227 irq_set_chained_handler(irqno, s3c_irq_demux);
1228 }
1229
1230 return 0;
1231}
1232
1233static struct irq_domain_ops s3c24xx_irq_ops_of = {
1234 .map = s3c24xx_irq_map_of,
1235 .xlate = s3c24xx_irq_xlate_of,
1236};
1237
1238struct s3c24xx_irq_of_ctrl {
1239 char *name;
1240 unsigned long offset;
1241 struct s3c_irq_intc **handle;
1242 struct s3c_irq_intc **parent;
1243 struct irq_domain_ops *ops;
1244};
1245
1246static int __init s3c_init_intc_of(struct device_node *np,
1247 struct device_node *interrupt_parent,
1248 struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)
1249{
1250 struct s3c_irq_intc *intc;
1251 struct s3c24xx_irq_of_ctrl *ctrl;
1252 struct irq_domain *domain;
1253 void __iomem *reg_base;
1254 int i;
1255
1256 reg_base = of_iomap(np, 0);
1257 if (!reg_base) {
1258 pr_err("irq-s3c24xx: could not map irq registers\n");
1259 return -EINVAL;
1260 }
1261
1262 domain = irq_domain_add_linear(np, num_ctrl * 32,
1263 &s3c24xx_irq_ops_of, NULL);
1264 if (!domain) {
1265 pr_err("irq: could not create irq-domain\n");
1266 return -EINVAL;
1267 }
1268
1269 for (i = 0; i < num_ctrl; i++) {
1270 ctrl = &s3c_ctrl[i];
1271
1272 pr_debug("irq: found controller %s\n", ctrl->name);
1273
1274 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
1275 if (!intc)
1276 return -ENOMEM;
1277
1278 intc->domain = domain;
1279 intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32,
1280 GFP_KERNEL);
1281 if (!intc->irqs) {
1282 kfree(intc);
1283 return -ENOMEM;
1284 }
1285
1286 if (ctrl->parent) {
1287 intc->reg_pending = reg_base + ctrl->offset;
1288 intc->reg_mask = reg_base + ctrl->offset + 0x4;
1289
1290 if (*(ctrl->parent)) {
1291 intc->parent = *(ctrl->parent);
1292 } else {
1293 pr_warn("irq: parent of %s missing\n",
1294 ctrl->name);
1295 kfree(intc->irqs);
1296 kfree(intc);
1297 continue;
1298 }
1299 } else {
1300 intc->reg_pending = reg_base + ctrl->offset;
1301 intc->reg_mask = reg_base + ctrl->offset + 0x08;
1302 intc->reg_intpnd = reg_base + ctrl->offset + 0x10;
1303 }
1304
1305 s3c24xx_clear_intc(intc);
1306 s3c_intc[i] = intc;
1307 }
1308
1309 set_handle_irq(s3c24xx_handle_irq);
1310
1311 return 0;
1312}
1313
1314static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
1315 {
1316 .name = "intc",
1317 .offset = 0,
1318 }, {
1319 .name = "subintc",
1320 .offset = 0x18,
1321 .parent = &s3c_intc[0],
1322 }
1323};
1324
1325int __init s3c2410_init_intc_of(struct device_node *np,
1326 struct device_node *interrupt_parent,
1327 struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
1328{
1329 return s3c_init_intc_of(np, interrupt_parent,
1330 s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
1331}
1332IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
1333
1334static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
1335 {
1336 .name = "intc",
1337 .offset = 0,
1338 }, {
1339 .name = "subintc",
1340 .offset = 0x18,
1341 .parent = &s3c_intc[0],
1342 }, {
1343 .name = "intc2",
1344 .offset = 0x40,
1345 }
1346};
1347
1348int __init s3c2416_init_intc_of(struct device_node *np,
1349 struct device_node *interrupt_parent,
1350 struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
1351{
1352 return s3c_init_intc_of(np, interrupt_parent,
1353 s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
1354}
1355IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of);
1356#endif