MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / arm / mach-s3c24a0 / irq.c
blob37a40ec52eb4802519144b271d7264097373d902
1 /*\e$)C
2 * arch/arm/mach-s3c24a0/irq.c
4 * Generic S3C24A0 IRQ handling.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/sched.h>
15 #include <linux/interrupt.h>
17 #include <asm/hardware.h>
18 #include <asm/irq.h>
19 #include <asm/mach/irq.h>
20 #include <linux/sysdev.h>
22 /* Pendng registers
24 * INTPND 0x40200010
25 * SUBINTPND 0x40200018
26 * EINTPND 0x44800038
28 static const unsigned long p_regs[3] = { 0x40200010, 0x40200018, 0x44800038 };
30 /* Mask registers
32 * INTMSK 0x40200008
33 * SUBINTMSK 0x4020001c
34 * EINTMSK 0x44800034
37 static const unsigned long m_regs[3] = { 0x40200008, 0x4020001c, 0x44800034 };
40 * Interrupt table
42 static const int r_irqs[NR_IRQS] = {
43 96, 96, 96, 96, 96, 5, 6, 7, 8, 9, 10, 11, 12, 96, 96, 15,
44 96, 96, 18, 19, 96, 21, 22, 96, 96, 25, 26, 27, 96, 29, 30, 96,
45 17, 17, 17, 23, 23, 23, 28, 28, 96, 96, 96, 13, 13, 16, 16, 14,
46 14, 31, 31, 31, 14, 24, 24, 29, 29, 20, 20, 20, 20, 96, 96, 96,
47 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4,
48 4, 4, 4, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96
51 static inline void clear_pending(int irq)
53 int i = r_irqs[irq];
54 if (i == NR_IRQS)
55 return;
57 *(volatile unsigned long *)(io_p2v(p_regs[irq >> 5])) = (1 << (irq % 32));
58 SRCPND = (1 << i);
59 INTPND = INTPND;
60 INTPND;
63 static inline int read_pending(int irq)
65 return ((*(volatile unsigned long *)(io_p2v(p_regs[irq >> 5]))) & (1 << (irq % 32)));
68 static inline void mask_irq(int irq)
70 *(volatile unsigned long *)(io_p2v(m_regs[irq >> 5])) |= (1 << (irq % 32));
73 static inline void unmask_irq(int irq)
75 *(volatile unsigned long *)(io_p2v(m_regs[irq >> 5])) &= ~(1 << (irq % 32));
78 //#define DEBUG // hcyun
79 #undef DEBUG
81 static inline int find_irq(int irq)
83 int i;
85 #ifdef DEBUG
86 if ( irq == 4 || irq == 3 ) printk("find_irq: irq=%d\n", irq);
87 #endif
89 for (i = IRQ_GRP1_START; i < NR_IRQS; i++) {
90 if (r_irqs[i] == irq) {
91 #ifdef DEBUG
92 if ( i >= 64 ) printk("Externel IRQ %d\n", i);
93 else if ( i >= 32 ) printk("Sub IRQ %d\n", i);
94 #endif
96 if (read_pending(i)) {
97 #ifdef DEBUG
98 if ( i >= 64 ) printk("OK there's external pending IRQ %d\n", i);
99 else if ( i >= 32 ) printk("OK there's sub pending IRQ %d\n", i);
100 #endif
101 return i;
105 return NR_IRQS;
108 int fixup_irq(int irq)
110 int retval = NR_IRQS;
112 if (irq >= IRQ_GRP1_START)
113 return retval;
115 if ((r_irqs[irq]) == NR_IRQS) {
116 retval = find_irq(irq);
117 } else {
118 retval = irq;
121 return retval;
124 static void elfin_mask_ack_irq(unsigned int irq)
126 mask_irq(irq);
127 clear_pending(irq);
130 static void elfin_ack_irq(unsigned int irq)
132 clear_pending(irq);
135 static void elfin_mask_irq(unsigned int irq)
137 mask_irq(irq);
140 static void elfin_unmask_irq(unsigned int irq)
142 unmask_irq(irq);
145 static struct irqchip s3c24a0_irq_chip = {
146 .ack = elfin_ack_irq, // irq_ack
147 .mask = elfin_mask_irq, // irq_mask
148 .unmask = elfin_unmask_irq // irq_unmak
153 #ifdef CONFIG_PM
154 static unsigned long ic_irq_enable;
156 static int irq_suspend(struct sys_device *dev, u32 state)
158 return 0;
161 static int irq_resume(struct sys_device *dev)
163 /* disable all irq sources */
164 return 0;
166 #else
167 #define irq_suspend NULL
168 #define irq_resume NULL
169 #endif
171 static struct sysdev_class irq_class = {
172 set_kset_name("irq"),
173 .suspend = irq_suspend,
174 .resume = irq_resume,
177 static struct sys_device irq_device = {
178 .id = 0,
179 .cls = &irq_class,
182 static int __init irq_init_sysfs(void)
184 int ret = sysdev_class_register(&irq_class);
185 if (ret == 0)
186 ret = sysdev_register(&irq_device);
187 return ret;
190 device_initcall(irq_init_sysfs);
192 void __init elfin_init_irq(void)
194 int irq;
196 unsigned int flags;
198 /* disable all interrupts */
199 INTSUBMSK = 0xffffffff;
200 EINTMASK = 0xffffffff;
201 INTMSK = 0xffffffff;
203 /* clear status registers */
204 EINTPEND = EINTPEND;
205 SUBSRCPND = SUBSRCPND;
206 SRCPND = SRCPND;
207 INTPND = INTPND;
209 /* all interrupts set as IRQ */
210 INTMOD = 0x00000000;
212 /* we have three groups */
213 for (irq = 0; irq < NR_IRQS; irq++) {
214 flags = IRQF_PROBE;
216 /* external IRQ */
217 if ((r_irqs[irq]) == NR_IRQS) {
218 if (irq < IRQ_GRP1_START)
219 INTMSK &= ~(1 << irq);
221 /* main IRQ */
222 else if ( irq < IRQ_GRP2_START )
223 flags |= IRQF_VALID;
225 set_irq_chip(irq, &s3c24a0_irq_chip);
226 set_irq_handler(irq, do_edge_IRQ);
227 set_irq_flags(irq, flags);
232 * S3C24A0 , External Interrupt setting interface
234 * 1) GPIO\e-A\x0e8\x0f: external irq\e$)C
235 * 2) Edge setting
236 * |<--ECTRL-->|<--GPIO--->|
237 * bit reg bit reg
238 * ofs ofs ofs ofs
239 * +-----+-----+-----+-----+-----+-----+-----+-----+
240 * |4-bit|4-bit|4-bit|4-bit|4-bit|4-bit|4-bit|4-bit|
241 * +-----+-----+-----+-----+-----+-----+-----+-----+
244 static const unsigned long garbage[] = {
245 0xffff0000, /* EINT 0 */
246 0xffff1010, /* EINT 1 */
247 0xffff2020, /* EINT 2 */
248 0xffff0130, /* EINT 3 */
249 0xffff1140, /* EINT 4 */
250 0xffff2150, /* EINT 5 */
251 0xffff3160, /* EINT 6 */
252 0xffff4170, /* EINT 7 */
253 0xffff5180, /* EINT 8 */
254 0xffff6190, /* EINT 9 */
255 0xffff71a0, /* EINT 10 */
256 0xffff0201, /* EINT 11 */
257 0xffff1211, /* EINT 12 */
258 0xffff2221, /* EINT 13 */
259 0xffff3231, /* EINT 14 */
260 0xffff4241, /* EINT 15 */
261 0xffff5251, /* EINT 16 */
262 0xffff6261, /* EINT 17 */
263 0xffff7271, /* EINT 18 */
266 int set_external_irq(int irq, int edge, int pullup)
268 int phy_irq = EINTIRQ_DEC(irq); /* physical irq number */
269 unsigned long g;
270 struct irqdesc *desc;
273 if (phy_irq > 18)
274 return -EINVAL;
276 g = garbage[phy_irq];
278 /* GPIO setting */
279 *(volatile unsigned long *)(io_p2v(0x44800008 - (0x4 * (g & 0x0000000f)))) &= ~(0x3 << (((g & 0x000000f0) >> 0x4) * 0x2));
280 *(volatile unsigned long *)(io_p2v(0x44800008 - (0x4 * (g & 0x0000000f)))) |= (0x2 << (((g & 0x000000f0) >> 0x4) * 0x2));
282 #if 0
283 printk("GPIO(0x%x) = 0x%x\n", io_p2v(0x44800008), *(volatile unsigned long *)io_p2v(0x44800008));
284 printk("GPIO(0x%x) = 0x%x\n", io_p2v(0x44800004), *(volatile unsigned long *)io_p2v(0x44800004));
285 #endif
287 /* edge setting */
288 *(volatile unsigned long *)(io_p2v(0x44800018 + (0x4 * ((g & 0x00000f00) >> 0x8)))) &= ~(0x7 << (((g & 0x0000f000) >> 0xc) * 0x4));
289 *(volatile unsigned long *)(io_p2v(0x44800018 + (0x4 * ((g & 0x00000f00) >> 0x8)))) |= (edge << (((g & 0x0000f000) >> 0xc) * 0x4));
291 /* Set pullup */
292 GPUP &= ~(1 << phy_irq);
293 GPUP |= pullup;
295 desc = irq_desc + irq;
296 desc->valid = 1;
298 switch ( edge ) {
299 case EINT_FALLING_EDGE:
300 case EINT_RISING_EDGE:
301 case EINT_BOTH_EDGES:
302 set_irq_handler(irq, do_edge_IRQ);
303 break;
304 case EINT_LOW_LEVEL:
305 case EINT_HIGH_LEVEL:
306 set_irq_handler(irq, do_level_IRQ);
307 break;
309 clear_pending(irq);
310 return 0;
313 EXPORT_SYMBOL(set_external_irq);