7ec80ddf |
1 | /* |
2 | * linux/arch/arm/mach-w90x900/irq.c |
3 | * |
4 | * based on linux/arch/arm/plat-s3c24xx/irq.c by Ben Dooks |
5 | * |
6 | * Copyright (c) 2008 Nuvoton technology corporation |
7 | * All rights reserved. |
8 | * |
9 | * Wan ZongShun <mcuos.com@gmail.com> |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by |
19c0a728 |
13 | * the Free Software Foundation;version 2 of the License. |
7ec80ddf |
14 | * |
15 | */ |
16 | |
17 | #include <linux/init.h> |
18 | #include <linux/module.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/ioport.h> |
21 | #include <linux/ptrace.h> |
22 | #include <linux/sysdev.h> |
23 | #include <linux/io.h> |
24 | |
25 | #include <asm/irq.h> |
26 | #include <asm/mach/irq.h> |
27 | |
28 | #include <mach/hardware.h> |
29 | #include <mach/regs-irq.h> |
30 | |
19c0a728 |
31 | struct group_irq { |
32 | unsigned long gpen; |
33 | unsigned int enabled; |
34 | void (*enable)(struct group_irq *, int enable); |
35 | }; |
36 | |
37 | static DEFINE_SPINLOCK(groupirq_lock); |
38 | |
39 | #define DEFINE_GROUP(_name, _ctrlbit, _num) \ |
40 | struct group_irq group_##_name = { \ |
41 | .enable = w90x900_group_enable, \ |
42 | .gpen = ((2 ^ _num) - 1) << _ctrlbit, \ |
43 | } |
44 | |
45 | static void w90x900_group_enable(struct group_irq *gpirq, int enable); |
46 | |
47 | static DEFINE_GROUP(nirq0, 0, 4); |
48 | static DEFINE_GROUP(nirq1, 4, 4); |
49 | static DEFINE_GROUP(usbh, 8, 2); |
50 | static DEFINE_GROUP(ottimer, 16, 3); |
51 | static DEFINE_GROUP(gdma, 20, 2); |
52 | static DEFINE_GROUP(sc, 24, 2); |
53 | static DEFINE_GROUP(i2c, 26, 2); |
54 | static DEFINE_GROUP(ps2, 28, 2); |
55 | |
56 | static int group_irq_enable(struct group_irq *group_irq) |
57 | { |
58 | unsigned long flags; |
59 | |
60 | spin_lock_irqsave(&groupirq_lock, flags); |
61 | if (group_irq->enabled++ == 0) |
62 | (group_irq->enable)(group_irq, 1); |
63 | spin_unlock_irqrestore(&groupirq_lock, flags); |
64 | |
65 | return 0; |
66 | } |
67 | |
68 | static void group_irq_disable(struct group_irq *group_irq) |
69 | { |
70 | unsigned long flags; |
71 | |
72 | WARN_ON(group_irq->enabled == 0); |
73 | |
74 | spin_lock_irqsave(&groupirq_lock, flags); |
75 | if (--group_irq->enabled == 0) |
76 | (group_irq->enable)(group_irq, 0); |
77 | spin_unlock_irqrestore(&groupirq_lock, flags); |
78 | } |
79 | |
80 | static void w90x900_group_enable(struct group_irq *gpirq, int enable) |
81 | { |
82 | unsigned int groupen = gpirq->gpen; |
83 | unsigned long regval; |
84 | |
85 | regval = __raw_readl(REG_AIC_GEN); |
86 | |
87 | if (enable) |
88 | regval |= groupen; |
89 | else |
90 | regval &= ~groupen; |
91 | |
92 | __raw_writel(regval, REG_AIC_GEN); |
93 | } |
94 | |
7ec80ddf |
95 | static void w90x900_irq_mask(unsigned int irq) |
96 | { |
19c0a728 |
97 | struct group_irq *group_irq; |
98 | |
99 | group_irq = NULL; |
100 | |
7ec80ddf |
101 | __raw_writel(1 << irq, REG_AIC_MDCR); |
19c0a728 |
102 | |
103 | switch (irq) { |
104 | case IRQ_GROUP0: |
105 | group_irq = &group_nirq0; |
106 | break; |
107 | |
108 | case IRQ_GROUP1: |
109 | group_irq = &group_nirq1; |
110 | break; |
111 | |
112 | case IRQ_USBH: |
113 | group_irq = &group_usbh; |
114 | break; |
115 | |
116 | case IRQ_T_INT_GROUP: |
117 | group_irq = &group_ottimer; |
118 | break; |
119 | |
120 | case IRQ_GDMAGROUP: |
121 | group_irq = &group_gdma; |
122 | break; |
123 | |
124 | case IRQ_SCGROUP: |
125 | group_irq = &group_sc; |
126 | break; |
127 | |
128 | case IRQ_I2CGROUP: |
129 | group_irq = &group_i2c; |
130 | break; |
131 | |
132 | case IRQ_P2SGROUP: |
133 | group_irq = &group_ps2; |
134 | break; |
135 | } |
136 | |
137 | if (group_irq) |
138 | group_irq_disable(group_irq); |
7ec80ddf |
139 | } |
140 | |
141 | /* |
142 | * By the w90p910 spec,any irq,only write 1 |
143 | * to REG_AIC_EOSCR for ACK |
144 | */ |
145 | |
146 | static void w90x900_irq_ack(unsigned int irq) |
147 | { |
148 | __raw_writel(0x01, REG_AIC_EOSCR); |
149 | } |
150 | |
151 | static void w90x900_irq_unmask(unsigned int irq) |
152 | { |
19c0a728 |
153 | struct group_irq *group_irq; |
154 | |
155 | group_irq = NULL; |
7ec80ddf |
156 | |
7ec80ddf |
157 | __raw_writel(1 << irq, REG_AIC_MECR); |
19c0a728 |
158 | |
159 | switch (irq) { |
160 | case IRQ_GROUP0: |
161 | group_irq = &group_nirq0; |
162 | break; |
163 | |
164 | case IRQ_GROUP1: |
165 | group_irq = &group_nirq1; |
166 | break; |
167 | |
168 | case IRQ_USBH: |
169 | group_irq = &group_usbh; |
170 | break; |
171 | |
172 | case IRQ_T_INT_GROUP: |
173 | group_irq = &group_ottimer; |
174 | break; |
175 | |
176 | case IRQ_GDMAGROUP: |
177 | group_irq = &group_gdma; |
178 | break; |
179 | |
180 | case IRQ_SCGROUP: |
181 | group_irq = &group_sc; |
182 | break; |
183 | |
184 | case IRQ_I2CGROUP: |
185 | group_irq = &group_i2c; |
186 | break; |
187 | |
188 | case IRQ_P2SGROUP: |
189 | group_irq = &group_ps2; |
190 | break; |
191 | } |
192 | |
193 | if (group_irq) |
194 | group_irq_enable(group_irq); |
7ec80ddf |
195 | } |
196 | |
197 | static struct irq_chip w90x900_irq_chip = { |
198 | .ack = w90x900_irq_ack, |
199 | .mask = w90x900_irq_mask, |
200 | .unmask = w90x900_irq_unmask, |
201 | }; |
202 | |
203 | void __init w90x900_init_irq(void) |
204 | { |
205 | int irqno; |
206 | |
207 | __raw_writel(0xFFFFFFFE, REG_AIC_MDCR); |
208 | |
209 | for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) { |
210 | set_irq_chip(irqno, &w90x900_irq_chip); |
211 | set_irq_handler(irqno, handle_level_irq); |
212 | set_irq_flags(irqno, IRQF_VALID); |
213 | } |
214 | } |