Merge branch 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block
[linux-2.6] / 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 #include "common.h"
23
24 static void lh7a40x_ack_cpld_irq (u32 irq)
25 {
26         /* CPLD doesn't have ack capability */
27 }
28
29 static void lh7a40x_mask_cpld_irq (u32 irq)
30 {
31         switch (irq) {
32         case IRQ_LPD7A40X_ETH_INT:
33                 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4;
34                 break;
35         case IRQ_LPD7A400_TS:
36                 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8;
37                 break;
38         }
39 }
40
41 static void lh7a40x_unmask_cpld_irq (u32 irq)
42 {
43         switch (irq) {
44         case IRQ_LPD7A40X_ETH_INT:
45                 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4;
46                 break;
47         case IRQ_LPD7A400_TS:
48                 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8;
49                 break;
50         }
51 }
52
53 static struct irqchip lh7a40x_cpld_chip = {
54         .ack    = lh7a40x_ack_cpld_irq,
55         .mask   = lh7a40x_mask_cpld_irq,
56         .unmask = lh7a40x_unmask_cpld_irq,
57 };
58
59 static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
60                                   struct pt_regs *regs)
61 {
62         unsigned int mask = CPLD_INTERRUPTS;
63
64         desc->chip->ack (irq);
65
66         if ((mask & 0x1) == 0)  /* WLAN */
67                 IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
68
69         if ((mask & 0x2) == 0)  /* Touch */
70                 IRQ_DISPATCH (IRQ_LPD7A400_TS);
71
72         desc->chip->unmask (irq); /* Level-triggered need this */
73 }
74
75
76   /* IRQ initialization */
77
78 void __init lh7a40x_init_board_irq (void)
79 {
80         int irq;
81
82                 /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
83                                  PF7 supports the CPLD.
84                    Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
85                                  PF3 supports the CPLD.
86                    (Some) LPD7A404 prerelease boards report a version
87                    number of 0x16, but we force an override since the
88                    hardware is of the newer variety.
89                 */
90
91         unsigned char cpld_version = CPLD_REVISION;
92         int pinCPLD;
93
94 #if defined CONFIG_MACH_LPD7A404
95         cpld_version = 0x34;    /* Override, for now */
96 #endif
97         pinCPLD = (cpld_version == 0x28) ? 7 : 3;
98
99                 /* First, configure user controlled GPIOF interrupts  */
100
101         GPIO_PFDD       &= ~0x0f; /* PF0-3 are inputs */
102         GPIO_INTTYPE1   &= ~0x0f; /* PF0-3 are level triggered */
103         GPIO_INTTYPE2   &= ~0x0f; /* PF0-3 are active low */
104         barrier ();
105         GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */
106
107                 /* Then, configure CPLD interrupt */
108
109         CPLD_INTERRUPTS =   0x0c; /* Disable all CPLD interrupts */
110         GPIO_PFDD       &= ~(1 << pinCPLD); /* Make input */
111         GPIO_INTTYPE1   |=  (1 << pinCPLD); /* Edge triggered */
112         GPIO_INTTYPE2   &= ~(1 << pinCPLD); /* Active low */
113         barrier ();
114         GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */
115
116                 /* Cascade CPLD interrupts */
117
118         for (irq = IRQ_BOARD_START;
119              irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
120                 set_irq_chip (irq, &lh7a40x_cpld_chip);
121                 set_irq_handler (irq, do_edge_IRQ);
122                 set_irq_flags (irq, IRQF_VALID);
123         }
124
125         set_irq_chained_handler ((cpld_version == 0x28)
126                                  ? IRQ_CPLD_V28
127                                  : IRQ_CPLD_V34,
128                                  lh7a40x_cpld_handler);
129 }