Merge ../linux-2.6
[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 irq_chip lh7a40x_cpld_chip = {
54         .name   = "CPLD",
55         .ack    = lh7a40x_ack_cpld_irq,
56         .mask   = lh7a40x_mask_cpld_irq,
57         .unmask = lh7a40x_unmask_cpld_irq,
58 };
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 }