nuke trailing whitespaces
[librecmc/librecmc.git] / target / linux / atheros / files / arch / mips / atheros / ar5315 / irq.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
7  * Copyright (C) 2006 FON Technology, SL.
8  * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
9  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
10  */
11
12 /*
13  * Platform devices for Atheros SoCs
14  */
15
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 #include <linux/kernel.h>
21 #include <linux/reboot.h>
22 #include <linux/interrupt.h>
23 #include <asm/bootinfo.h>
24 #include <asm/irq_cpu.h>
25 #include <asm/io.h>
26
27 #include <ar531x.h>
28 #include <gpio.h>
29
30 static u32 gpiointmask = 0, gpiointval = 0;
31
32 static inline void ar5315_gpio_irq(void)
33 {
34         u32 pend;
35         sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
36
37         /* only do one gpio interrupt at a time */
38         pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask;
39         if (!pend)
40                 return;
41
42         do_IRQ(AR531X_GPIO_IRQ_BASE + 31 - clz(pend));
43 }
44
45
46 /*
47  * Called when an interrupt is received, this function
48  * determines exactly which interrupt it was, and it
49  * invokes the appropriate handler.
50  *
51  * Implicitly, we also define interrupt priority by
52  * choosing which to dispatch first.
53  */
54 asmlinkage void ar5315_irq_dispatch(void)
55 {
56         int pending = read_c0_status() & read_c0_cause();
57
58         if (pending & CAUSEF_IP3)
59                 do_IRQ(AR5315_IRQ_WLAN0_INTRS);
60         else if (pending & CAUSEF_IP4)
61                 do_IRQ(AR5315_IRQ_ENET0_INTRS);
62         else if (pending & CAUSEF_IP2) {
63                 unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
64
65                 if (ar531x_misc_intrs & AR5315_ISR_SPI)
66                         do_IRQ(AR531X_MISC_IRQ_SPI);
67                 else if (ar531x_misc_intrs & AR5315_ISR_TIMER)
68                         do_IRQ(AR531X_MISC_IRQ_TIMER);
69                 else if (ar531x_misc_intrs & AR5315_ISR_AHB)
70                         do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
71                 else if (ar531x_misc_intrs & AR5315_ISR_GPIO)
72                         ar5315_gpio_irq();
73                 else if (ar531x_misc_intrs & AR5315_ISR_UART0)
74                         do_IRQ(AR531X_MISC_IRQ_UART0);
75                 else if (ar531x_misc_intrs & AR5315_ISR_WD)
76                         do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
77                 else
78                         do_IRQ(AR531X_MISC_IRQ_NONE);
79         } else if (pending & CAUSEF_IP7)
80                 do_IRQ(AR531X_IRQ_CPU_CLOCK);
81 }
82
83 static void ar5315_gpio_intr_enable(unsigned int irq)
84 {
85         u32 gpio, mask;
86         gpio = irq - AR531X_GPIO_IRQ_BASE;
87         mask = 1 << gpio;
88         gpiointmask |= mask;
89
90         /* reconfigure GPIO line as input */
91         sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio));
92
93         /* Enable interrupt with edge detection */
94         sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3));
95 }
96
97 static void ar5315_gpio_intr_disable(unsigned int irq)
98 {
99         u32 gpio, mask;
100         gpio = irq - AR531X_GPIO_IRQ_BASE;
101         mask = 1 << gpio;
102
103         gpiointmask &= ~mask;
104
105         /* Disable interrupt with edge detection */
106         sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0));
107 }
108
109 /* Turn on the specified AR531X_MISC_IRQ interrupt */
110 static unsigned int ar5315_gpio_intr_startup(unsigned int irq)
111 {
112         ar5315_gpio_intr_enable(irq);
113         return 0;
114 }
115
116 /* Turn off the specified AR531X_MISC_IRQ interrupt */
117 static void
118 ar5315_gpio_intr_shutdown(unsigned int irq)
119 {
120         ar5315_gpio_intr_disable(irq);
121 }
122
123 static void
124 ar5315_gpio_intr_ack(unsigned int irq)
125 {
126         ar5315_gpio_intr_disable(irq);
127 }
128
129 static void
130 ar5315_gpio_intr_end(unsigned int irq)
131 {
132         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
133                 ar5315_gpio_intr_enable(irq);
134 }
135
136 static struct irq_chip ar5315_gpio_intr_controller = {
137         .typename       = "AR5315 GPIO",
138         .startup        = ar5315_gpio_intr_startup,
139         .shutdown       = ar5315_gpio_intr_shutdown,
140         .enable         = ar5315_gpio_intr_enable,
141         .disable        = ar5315_gpio_intr_disable,
142         .ack            = ar5315_gpio_intr_ack,
143         .end            = ar5315_gpio_intr_end,
144 };
145
146
147 /* Enable the specified AR531X_MISC_IRQ interrupt */
148 static void
149 ar5315_misc_intr_enable(unsigned int irq)
150 {
151         unsigned int imr;
152
153         imr = sysRegRead(AR5315_IMR);
154         switch(irq)
155         {
156            case AR531X_MISC_IRQ_SPI:
157                  imr |= AR5315_ISR_SPI;
158                  break;
159
160            case AR531X_MISC_IRQ_TIMER:
161              imr |= AR5315_ISR_TIMER;
162              break;
163
164            case AR531X_MISC_IRQ_AHB_PROC:
165              imr |= AR5315_ISR_AHB;
166              break;
167
168            case AR531X_MISC_IRQ_AHB_DMA:
169              imr |= 0/* ?? */;
170              break;
171
172            case AR531X_MISC_IRQ_GPIO:
173              imr |= AR5315_ISR_GPIO;
174              break;
175
176            case AR531X_MISC_IRQ_UART0:
177              imr |= AR5315_ISR_UART0;
178              break;
179
180
181            case AR531X_MISC_IRQ_WATCHDOG:
182              imr |= AR5315_ISR_WD;
183              break;
184
185            case AR531X_MISC_IRQ_LOCAL:
186              imr |= 0/* ?? */;
187              break;
188
189         }
190         sysRegWrite(AR5315_IMR, imr);
191         imr=sysRegRead(AR5315_IMR); /* flush write buffer */
192 }
193
194 /* Disable the specified AR531X_MISC_IRQ interrupt */
195 static void
196 ar5315_misc_intr_disable(unsigned int irq)
197 {
198         unsigned int imr;
199
200         imr = sysRegRead(AR5315_IMR);
201         switch(irq)
202         {
203            case AR531X_MISC_IRQ_SPI:
204                  imr &= ~AR5315_ISR_SPI;
205                  break;
206
207            case AR531X_MISC_IRQ_TIMER:
208              imr &= (~AR5315_ISR_TIMER);
209              break;
210
211            case AR531X_MISC_IRQ_AHB_PROC:
212              imr &= (~AR5315_ISR_AHB);
213              break;
214
215            case AR531X_MISC_IRQ_AHB_DMA:
216              imr &= 0/* ?? */;
217              break;
218
219            case AR531X_MISC_IRQ_GPIO:
220              imr &= ~AR5315_ISR_GPIO;
221              break;
222
223            case AR531X_MISC_IRQ_UART0:
224              imr &= (~AR5315_ISR_UART0);
225              break;
226
227            case AR531X_MISC_IRQ_WATCHDOG:
228              imr &= (~AR5315_ISR_WD);
229              break;
230
231            case AR531X_MISC_IRQ_LOCAL:
232              imr &= ~0/* ?? */;
233              break;
234
235         }
236         sysRegWrite(AR5315_IMR, imr);
237         sysRegRead(AR5315_IMR); /* flush write buffer */
238 }
239
240 /* Turn on the specified AR531X_MISC_IRQ interrupt */
241 static unsigned int
242 ar5315_misc_intr_startup(unsigned int irq)
243 {
244         ar5315_misc_intr_enable(irq);
245         return 0;
246 }
247
248 /* Turn off the specified AR531X_MISC_IRQ interrupt */
249 static void
250 ar5315_misc_intr_shutdown(unsigned int irq)
251 {
252         ar5315_misc_intr_disable(irq);
253 }
254
255 static void
256 ar5315_misc_intr_ack(unsigned int irq)
257 {
258         ar5315_misc_intr_disable(irq);
259 }
260
261 static void
262 ar5315_misc_intr_end(unsigned int irq)
263 {
264         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
265                 ar5315_misc_intr_enable(irq);
266 }
267
268 static struct irq_chip ar5315_misc_intr_controller = {
269         .typename       = "AR5315 misc",
270         .startup        = ar5315_misc_intr_startup,
271         .shutdown       = ar5315_misc_intr_shutdown,
272         .enable         = ar5315_misc_intr_enable,
273         .disable        = ar5315_misc_intr_disable,
274         .ack            = ar5315_misc_intr_ack,
275         .end            = ar5315_misc_intr_end,
276 };
277
278 static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
279 {
280     sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
281     sysRegRead(AR5315_AHB_ERR1);
282
283     printk("AHB fatal error\n");
284     machine_restart("AHB error"); /* Catastrophic failure */
285
286     return IRQ_HANDLED;
287 }
288
289 static struct irqaction ar5315_ahb_proc_interrupt  = {
290         .handler        = ar5315_ahb_proc_handler,
291         .flags          = IRQF_DISABLED,
292         .name           = "ar5315_ahb_proc_interrupt",
293 };
294
295
296 static struct irqaction cascade  = {
297         .handler        = no_action,
298         .flags          = IRQF_DISABLED,
299         .name           = "cascade",
300 };
301
302 static void ar5315_gpio_intr_init(int irq_base)
303 {
304         int i;
305
306         for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
307                 irq_desc[i].status = IRQ_DISABLED;
308                 irq_desc[i].action = NULL;
309                 irq_desc[i].depth = 1;
310                 irq_desc[i].chip = &ar5315_gpio_intr_controller;
311         }
312         setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
313         gpiointval = sysRegRead(AR5315_GPIO_DI);
314 }
315
316 void ar5315_misc_intr_init(int irq_base)
317 {
318         int i;
319
320         for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
321                 irq_desc[i].status = IRQ_DISABLED;
322                 irq_desc[i].action = NULL;
323                 irq_desc[i].depth = 1;
324                 irq_desc[i].chip = &ar5315_misc_intr_controller;
325         }
326         setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
327         setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
328         ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
329 }
330