http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / kernel / linux / arch / arm / mach-lh7a40x / irq-lpd7a40x.c
1 /* arch/arm/mach-lh7a40x/irq-lpd7a40x.c
2  *
3  *  Copyright (C) 2004 Coastal Environmental Systems
4  *  Copyright (C) 2004 Logic Product Development
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  version 2 as published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/interrupt.h>
15 #include <linux/ptrace.h>
16
17 #include <asm/hardware.h>
18 #include <asm/irq.h>
19 #include <asm/mach/irq.h>
20 #include <asm/arch/irqs.h>
21
22
23 static void lh7a40x_ack_cpld_irq (u32 irq)
24 {
25         /* CPLD doesn't have ack capability */
26 }
27
28 static void lh7a40x_mask_cpld_irq (u32 irq)
29 {
30         switch (irq) {
31         case IRQ_LPD7A40X_ETH_INT:
32                 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4;
33                 break;
34         case IRQ_LPD7A400_TS:
35                 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8;
36                 break;
37         }
38 }
39
40 static void lh7a40x_unmask_cpld_irq (u32 irq)
41 {
42         switch (irq) {
43         case IRQ_LPD7A40X_ETH_INT:
44                 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4;
45                 break;
46         case IRQ_LPD7A400_TS:
47                 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8;
48                 break;
49         }
50 }
51
52 static struct irqchip lh7a40x_cpld_chip = {
53         .ack    = lh7a40x_ack_cpld_irq,
54         .mask   = lh7a40x_mask_cpld_irq,
55         .unmask = lh7a40x_unmask_cpld_irq,
56 };
57
58 #define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
59
60 static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
61                                   struct pt_regs *regs)
62 {
63         unsigned int mask = CPLD_INTERRUPTS;
64
65         desc->chip->ack (irq);
66
67         if ((mask & 0x1) == 0)  /* WLAN */
68                 IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
69
70         if ((mask & 0x2) == 0)  /* Touch */
71                 IRQ_DISPATCH (IRQ_LPD7A400_TS);
72
73         desc->chip->unmask (irq); /* Level-triggered need this */
74 }
75
76
77   /* IRQ initialization */
78
79 void __init lh7a40x_init_board_irq (void)
80 {
81         int irq;
82
83                 /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
84                                  PF7 supports the CPLD.
85                    Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
86                                  PF3 supports the CPLD.
87                    (Some) LPD7A404 prerelease boards report a version
88                    number of 0x16, but we force an override since the
89                    hardware is of the newer variety.
90                 */
91
92         unsigned char cpld_version = CPLD_REVISION;
93         int pinCPLD;
94
95 #if defined CONFIG_MACH_LPD7A404
96         cpld_version = 0x34;    /* Override, for now */
97 #endif
98         pinCPLD = (cpld_version == 0x28) ? 7 : 3;
99
100                 /* First, configure user controlled GPIOF interrupts  */
101
102         GPIO_PFDD       &= ~0x0f; /* PF0-3 are inputs */
103         GPIO_INTTYPE1   &= ~0x0f; /* PF0-3 are level triggered */
104         GPIO_INTTYPE2   &= ~0x0f; /* PF0-3 are active low */
105         barrier ();
106         GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */
107
108                 /* Then, configure CPLD interrupt */
109
110         CPLD_INTERRUPTS =   0x0c; /* Disable all CPLD interrupts */
111         GPIO_PFDD       &= ~(1 << pinCPLD); /* Make input */
112         GPIO_INTTYPE1   |=  (1 << pinCPLD); /* Edge triggered */
113         GPIO_INTTYPE2   &= ~(1 << pinCPLD); /* Active low */
114         barrier ();
115         GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */
116
117                 /* Cascade CPLD interrupts */
118
119         for (irq = IRQ_BOARD_START;
120              irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
121                 set_irq_chip (irq, &lh7a40x_cpld_chip);
122                 set_irq_handler (irq, do_edge_IRQ);
123                 set_irq_flags (irq, IRQF_VALID);
124         }
125
126         set_irq_chained_handler ((cpld_version == 0x28)
127                                  ? IRQ_CPLD_V28
128                                  : IRQ_CPLD_V34,
129                                  lh7a40x_cpld_handler);
130 }