ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / vr41xx / nec-eagle / irq.c
1 /*
2  *  irq.c,  Interrupt routines for the NEC Eagle/Hawk board.
3  *
4  *  Copyright (C) 2002  MontaVista Software, Inc.
5  *    Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
6  *  Copyright (C) 2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /*
23  * Changes:
24  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
25  *  - New creation, NEC Eagle is supported.
26  *  - Added support for NEC Hawk.
27  *
28  *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
29  *  - Changed from board_irq_init to driver module.
30  */
31 #include <linux/config.h>
32 #include <linux/init.h>
33 #include <linux/interrupt.h>
34 #include <linux/module.h>
35 #include <linux/types.h>
36
37 #include <asm/io.h>
38 #include <asm/vr41xx/eagle.h>
39
40 MODULE_DESCRIPTION("IRQ module driver for NEC Eagle/Hawk");
41 MODULE_AUTHOR("Yoichi Yuasa <yyuasa@mvista.com>");
42 MODULE_LICENSE("GPL");
43
44 static void enable_pciint_irq(unsigned int irq)
45 {
46         uint8_t val;
47
48         val = readb(NEC_EAGLE_PCIINTMSKREG);
49         val |= (uint8_t)1 << (irq - PCIINT_IRQ_BASE);
50         writeb(val, NEC_EAGLE_PCIINTMSKREG);
51 }
52
53 static void disable_pciint_irq(unsigned int irq)
54 {
55         uint8_t val;
56
57         val = readb(NEC_EAGLE_PCIINTMSKREG);
58         val &= ~((uint8_t)1 << (irq - PCIINT_IRQ_BASE));
59         writeb(val, NEC_EAGLE_PCIINTMSKREG);
60 }
61
62 static unsigned int startup_pciint_irq(unsigned int irq)
63 {
64         enable_pciint_irq(irq);
65         return 0; /* never anything pending */
66 }
67
68 #define shutdown_pciint_irq     disable_pciint_irq
69 #define ack_pciint_irq          disable_pciint_irq
70
71 static void end_pciint_irq(unsigned int irq)
72 {
73         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
74                 enable_pciint_irq(irq);
75 }
76
77 static struct hw_interrupt_type pciint_irq_type = {
78         .typename       = "PCIINT",
79         .startup        = startup_pciint_irq,
80         .shutdown       = shutdown_pciint_irq,
81         .enable         = enable_pciint_irq,
82         .disable        = disable_pciint_irq,
83         .ack            = ack_pciint_irq,
84         .end            = end_pciint_irq,
85 };
86
87 static void enable_sdbint_irq(unsigned int irq)
88 {
89         uint8_t val;
90
91         val = readb(NEC_EAGLE_SDBINTMSK);
92         val |= (uint8_t)1 << (irq - SDBINT_IRQ_BASE);
93         writeb(val, NEC_EAGLE_SDBINTMSK);
94 }
95
96 static void disable_sdbint_irq(unsigned int irq)
97 {
98         uint8_t val;
99
100         val = readb(NEC_EAGLE_SDBINTMSK);
101         val &= ~((uint8_t)1 << (irq - SDBINT_IRQ_BASE));
102         writeb(val, NEC_EAGLE_SDBINTMSK);
103 }
104
105 static unsigned int startup_sdbint_irq(unsigned int irq)
106 {
107         enable_sdbint_irq(irq);
108         return 0; /* never anything pending */
109 }
110
111 #define shutdown_sdbint_irq     disable_sdbint_irq
112 #define ack_sdbint_irq          disable_sdbint_irq
113
114 static void end_sdbint_irq(unsigned int irq)
115 {
116         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
117                 enable_sdbint_irq(irq);
118 }
119
120 static struct hw_interrupt_type sdbint_irq_type = {
121         .typename       = "SDBINT",
122         .startup        = startup_sdbint_irq,
123         .shutdown       = shutdown_sdbint_irq,
124         .enable         = enable_sdbint_irq,
125         .disable        = disable_sdbint_irq,
126         .ack            = ack_sdbint_irq,
127         .end            = end_sdbint_irq,
128 };
129
130 static int eagle_get_irq_number(int irq)
131 {
132         uint8_t sdbint, pciint;
133         int i;
134
135         sdbint = readb(NEC_EAGLE_SDBINT);
136         sdbint &= (NEC_EAGLE_SDBINT_DEG | NEC_EAGLE_SDBINT_ENUM |
137                    NEC_EAGLE_SDBINT_SIO1INT | NEC_EAGLE_SDBINT_SIO2INT |
138                    NEC_EAGLE_SDBINT_PARINT);
139         pciint = readb(NEC_EAGLE_PCIINTREG);
140         pciint &= (NEC_EAGLE_PCIINT_CP_INTA | NEC_EAGLE_PCIINT_CP_INTB |
141                    NEC_EAGLE_PCIINT_CP_INTC | NEC_EAGLE_PCIINT_CP_INTD |
142                    NEC_EAGLE_PCIINT_LANINT);
143
144         for (i = 1; i < 6; i++)
145                 if (sdbint & (0x01 << i))
146                         return SDBINT_IRQ_BASE + i;
147
148         for (i = 0; i < 5; i++)
149                 if (pciint & (0x01 << i))
150                         return PCIINT_IRQ_BASE + i;
151
152         return -EINVAL;
153 }
154
155 static int __devinit eagle_irq_init(void)
156 {
157         int i, retval;
158
159         writeb(0, NEC_EAGLE_SDBINTMSK);
160         writeb(0, NEC_EAGLE_PCIINTMSKREG);
161
162         vr41xx_set_irq_trigger(PCISLOT_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
163         vr41xx_set_irq_level(PCISLOT_PIN, LEVEL_HIGH);
164
165         vr41xx_set_irq_trigger(FPGA_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
166         vr41xx_set_irq_level(FPGA_PIN, LEVEL_HIGH);
167
168         vr41xx_set_irq_trigger(DCD_PIN, TRIGGER_EDGE, SIGNAL_HOLD);
169         vr41xx_set_irq_level(DCD_PIN, LEVEL_LOW);
170
171         for (i = SDBINT_IRQ_BASE; i <= SDBINT_IRQ_LAST; i++)
172                 irq_desc[i].handler = &sdbint_irq_type;
173
174         for (i = PCIINT_IRQ_BASE; i <= PCIINT_IRQ_LAST; i++)
175                 irq_desc[i].handler = &pciint_irq_type;
176
177         retval = vr41xx_cascade_irq(FPGA_CASCADE_IRQ, eagle_get_irq_number);
178         if (retval != 0)
179                 printk(KERN_ERR "eagle: Cannot cascade IRQ %d\n", FPGA_CASCADE_IRQ);
180
181         return retval;
182 }
183
184 static void __devexit eagle_irq_exit(void)
185 {
186         free_irq(FPGA_CASCADE_IRQ, NULL);
187 }
188
189 module_init(eagle_irq_init);
190 module_exit(eagle_irq_exit);