Commit | Line | Data |
---|---|---|
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> | |
edbaa603 | 22 | #include <linux/device.h> |
7ec80ddf | 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 | ||
e5bc9e25 RK |
31 | #include "nuc9xx.h" |
32 | ||
19c0a728 | 33 | struct group_irq { |
34 | unsigned long gpen; | |
35 | unsigned int enabled; | |
36 | void (*enable)(struct group_irq *, int enable); | |
37 | }; | |
38 | ||
39 | static DEFINE_SPINLOCK(groupirq_lock); | |
40 | ||
35c9221a | 41 | #define DEFINE_GROUP(_name, _ctrlbit, _num) \ |
42 | struct group_irq group_##_name = { \ | |
43 | .enable = nuc900_group_enable, \ | |
44 | .gpen = ((1 << _num) - 1) << _ctrlbit, \ | |
19c0a728 | 45 | } |
46 | ||
35c9221a | 47 | static void nuc900_group_enable(struct group_irq *gpirq, int enable); |
19c0a728 | 48 | |
49 | static DEFINE_GROUP(nirq0, 0, 4); | |
50 | static DEFINE_GROUP(nirq1, 4, 4); | |
51 | static DEFINE_GROUP(usbh, 8, 2); | |
52 | static DEFINE_GROUP(ottimer, 16, 3); | |
53 | static DEFINE_GROUP(gdma, 20, 2); | |
54 | static DEFINE_GROUP(sc, 24, 2); | |
55 | static DEFINE_GROUP(i2c, 26, 2); | |
56 | static DEFINE_GROUP(ps2, 28, 2); | |
57 | ||
58 | static int group_irq_enable(struct group_irq *group_irq) | |
59 | { | |
60 | unsigned long flags; | |
61 | ||
62 | spin_lock_irqsave(&groupirq_lock, flags); | |
63 | if (group_irq->enabled++ == 0) | |
64 | (group_irq->enable)(group_irq, 1); | |
65 | spin_unlock_irqrestore(&groupirq_lock, flags); | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | static void group_irq_disable(struct group_irq *group_irq) | |
71 | { | |
72 | unsigned long flags; | |
73 | ||
74 | WARN_ON(group_irq->enabled == 0); | |
75 | ||
76 | spin_lock_irqsave(&groupirq_lock, flags); | |
77 | if (--group_irq->enabled == 0) | |
78 | (group_irq->enable)(group_irq, 0); | |
79 | spin_unlock_irqrestore(&groupirq_lock, flags); | |
80 | } | |
81 | ||
35c9221a | 82 | static void nuc900_group_enable(struct group_irq *gpirq, int enable) |
19c0a728 | 83 | { |
84 | unsigned int groupen = gpirq->gpen; | |
85 | unsigned long regval; | |
86 | ||
87 | regval = __raw_readl(REG_AIC_GEN); | |
88 | ||
89 | if (enable) | |
90 | regval |= groupen; | |
91 | else | |
92 | regval &= ~groupen; | |
93 | ||
94 | __raw_writel(regval, REG_AIC_GEN); | |
95 | } | |
96 | ||
b9858efa | 97 | static void nuc900_irq_mask(struct irq_data *d) |
7ec80ddf | 98 | { |
19c0a728 | 99 | struct group_irq *group_irq; |
100 | ||
101 | group_irq = NULL; | |
102 | ||
b9858efa | 103 | __raw_writel(1 << d->irq, REG_AIC_MDCR); |
19c0a728 | 104 | |
b9858efa | 105 | switch (d->irq) { |
19c0a728 | 106 | case IRQ_GROUP0: |
107 | group_irq = &group_nirq0; | |
108 | break; | |
109 | ||
110 | case IRQ_GROUP1: | |
111 | group_irq = &group_nirq1; | |
112 | break; | |
113 | ||
114 | case IRQ_USBH: | |
115 | group_irq = &group_usbh; | |
116 | break; | |
117 | ||
118 | case IRQ_T_INT_GROUP: | |
119 | group_irq = &group_ottimer; | |
120 | break; | |
121 | ||
122 | case IRQ_GDMAGROUP: | |
123 | group_irq = &group_gdma; | |
124 | break; | |
125 | ||
126 | case IRQ_SCGROUP: | |
127 | group_irq = &group_sc; | |
128 | break; | |
129 | ||
130 | case IRQ_I2CGROUP: | |
131 | group_irq = &group_i2c; | |
132 | break; | |
133 | ||
134 | case IRQ_P2SGROUP: | |
135 | group_irq = &group_ps2; | |
136 | break; | |
137 | } | |
138 | ||
139 | if (group_irq) | |
140 | group_irq_disable(group_irq); | |
7ec80ddf | 141 | } |
142 | ||
143 | /* | |
144 | * By the w90p910 spec,any irq,only write 1 | |
145 | * to REG_AIC_EOSCR for ACK | |
146 | */ | |
147 | ||
b9858efa | 148 | static void nuc900_irq_ack(struct irq_data *d) |
7ec80ddf | 149 | { |
150 | __raw_writel(0x01, REG_AIC_EOSCR); | |
151 | } | |
152 | ||
b9858efa | 153 | static void nuc900_irq_unmask(struct irq_data *d) |
7ec80ddf | 154 | { |
19c0a728 | 155 | struct group_irq *group_irq; |
156 | ||
157 | group_irq = NULL; | |
7ec80ddf | 158 | |
b9858efa | 159 | __raw_writel(1 << d->irq, REG_AIC_MECR); |
19c0a728 | 160 | |
b9858efa | 161 | switch (d->irq) { |
19c0a728 | 162 | case IRQ_GROUP0: |
163 | group_irq = &group_nirq0; | |
164 | break; | |
165 | ||
166 | case IRQ_GROUP1: | |
167 | group_irq = &group_nirq1; | |
168 | break; | |
169 | ||
170 | case IRQ_USBH: | |
171 | group_irq = &group_usbh; | |
172 | break; | |
173 | ||
174 | case IRQ_T_INT_GROUP: | |
175 | group_irq = &group_ottimer; | |
176 | break; | |
177 | ||
178 | case IRQ_GDMAGROUP: | |
179 | group_irq = &group_gdma; | |
180 | break; | |
181 | ||
182 | case IRQ_SCGROUP: | |
183 | group_irq = &group_sc; | |
184 | break; | |
185 | ||
186 | case IRQ_I2CGROUP: | |
187 | group_irq = &group_i2c; | |
188 | break; | |
189 | ||
190 | case IRQ_P2SGROUP: | |
191 | group_irq = &group_ps2; | |
192 | break; | |
193 | } | |
194 | ||
195 | if (group_irq) | |
196 | group_irq_enable(group_irq); | |
7ec80ddf | 197 | } |
198 | ||
35c9221a | 199 | static struct irq_chip nuc900_irq_chip = { |
b9858efa LB |
200 | .irq_ack = nuc900_irq_ack, |
201 | .irq_mask = nuc900_irq_mask, | |
202 | .irq_unmask = nuc900_irq_unmask, | |
7ec80ddf | 203 | }; |
204 | ||
35c9221a | 205 | void __init nuc900_init_irq(void) |
7ec80ddf | 206 | { |
207 | int irqno; | |
208 | ||
209 | __raw_writel(0xFFFFFFFE, REG_AIC_MDCR); | |
210 | ||
211 | for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) { | |
f38c02f3 TG |
212 | irq_set_chip_and_handler(irqno, &nuc900_irq_chip, |
213 | handle_level_irq); | |
7ec80ddf | 214 | set_irq_flags(irqno, IRQF_VALID); |
215 | } | |
216 | } |