Linux-2.6.12-rc2
[linux-2.6.git] / 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 static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
59                                   struct pt_regs *regs)
60 {
61         unsigned int mask = CPLD_INTERRUPTS;
62
63         desc->chip->ack (irq);
64
65         if ((mask & 0x1) == 0)  /* WLAN */
66                 IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
67
68         if ((mask & 0x2) == 0)  /* Touch */
69                 IRQ_DISPATCH (IRQ_LPD7A400_TS);
70
71         desc->chip->unmask (irq); /* Level-triggered need this */
72 }
73
74
75   /* IRQ initialization */
76
77 void __init lh7a40x_init_board_irq (void)
78 {
79         int irq;
80
81                 /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
82                                  PF7 supports the CPLD.
83                    Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
84                                  PF3 supports the CPLD.
85                    (Some) LPD7A404 prerelease boards report a version
86                    number of 0x16, but we force an override since the
87                    hardware is of the newer variety.
88                 */
89
90         unsigned char cpld_version = CPLD_REVISION;
91         int pinCPLD;
92
93 #if defined CONFIG_MACH_LPD7A404
94         cpld_version = 0x34;    /* Override, for now */
95 #endif
96         pinCPLD = (cpld_version == 0x28) ? 7 : 3;
97
98                 /* First, configure user controlled GPIOF interrupts  */
99
100         GPIO_PFDD       &= ~0x0f; /* PF0-3 are inputs */
101         GPIO_INTTYPE1   &= ~0x0f; /* PF0-3 are level triggered */
102         GPIO_INTTYPE2   &= ~0x0f; /* PF0-3 are active low */
103         barrier ();
104         GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */
105
106                 /* Then, configure CPLD interrupt */
107
108         CPLD_INTERRUPTS =   0x0c; /* Disable all CPLD interrupts */
109         GPIO_PFDD       &= ~(1 << pinCPLD); /* Make input */
110         GPIO_INTTYPE1   |=  (1 << pinCPLD); /* Edge triggered */
111         GPIO_INTTYPE2   &= ~(1 << pinCPLD); /* Active low */
112         barrier ();
113         GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */
114
115                 /* Cascade CPLD interrupts */
116
117         for (irq = IRQ_BOARD_START;
118              irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
119                 set_irq_chip (irq, &lh7a40x_cpld_chip);
120                 set_irq_handler (irq, do_edge_IRQ);
121                 set_irq_flags (irq, IRQF_VALID);
122         }
123
124         set_irq_chained_handler ((cpld_version == 0x28)
125                                  ? IRQ_CPLD_V28
126                                  : IRQ_CPLD_V34,
127                                  lh7a40x_cpld_handler);
128 }