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