bf1b28feca06d7222ca5c5f53e272b753a0d6a3f
[safe/jmp/linux-2.6] / arch / sh / cchips / voyagergx / irq.c
1 /* -------------------------------------------------------------------- */
2 /* setup_voyagergx.c:                                                     */
3 /* -------------------------------------------------------------------- */
4 /*  This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     Copyright 2003 (c) Lineo uSolutions,Inc.
19 */
20 /* -------------------------------------------------------------------- */
21
22 #undef DEBUG
23
24 #include <linux/sched.h>
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/param.h>
28 #include <linux/ioport.h>
29 #include <linux/interrupt.h>
30 #include <linux/init.h>
31 #include <linux/irq.h>
32
33 #include <asm/io.h>
34 #include <asm/irq.h>
35 #include <asm/voyagergx.h>
36
37 static void disable_voyagergx_irq(unsigned int irq)
38 {
39         unsigned long val;
40         unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
41
42         pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
43         val = inl(VOYAGER_INT_MASK);
44         val &= ~mask;
45         outl(val, VOYAGER_INT_MASK);
46 }
47
48 static void enable_voyagergx_irq(unsigned int irq)
49 {
50         unsigned long val;
51         unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
52
53         pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
54         val = inl(VOYAGER_INT_MASK);
55         val |= mask;
56         outl(val, VOYAGER_INT_MASK);
57 }
58
59 static void mask_and_ack_voyagergx(unsigned int irq)
60 {
61         disable_voyagergx_irq(irq);
62 }
63
64 static void end_voyagergx_irq(unsigned int irq)
65 {
66         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
67                 enable_voyagergx_irq(irq);
68 }
69
70 static unsigned int startup_voyagergx_irq(unsigned int irq)
71 {
72         enable_voyagergx_irq(irq);
73         return 0;
74 }
75
76 static void shutdown_voyagergx_irq(unsigned int irq)
77 {
78         disable_voyagergx_irq(irq);
79 }
80
81 static struct hw_interrupt_type voyagergx_irq_type = {
82         .typename = "VOYAGERGX-IRQ",
83         .startup = startup_voyagergx_irq,
84         .shutdown = shutdown_voyagergx_irq,
85         .enable = enable_voyagergx_irq,
86         .disable = disable_voyagergx_irq,
87         .ack = mask_and_ack_voyagergx,
88         .end = end_voyagergx_irq,
89 };
90
91 static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
92 {
93         printk(KERN_INFO
94                "VoyagerGX: spurious interrupt, status: 0x%x\n",
95                         inl(INT_STATUS));
96         return IRQ_HANDLED;
97 }
98
99 static struct {
100         int (*func)(int, void *);
101         void *dev;
102 } voyagergx_demux[VOYAGER_IRQ_NUM];
103
104 void voyagergx_register_irq_demux(int irq,
105                 int (*demux)(int irq, void *dev), void *dev)
106 {
107         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
108         voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
109 }
110
111 void voyagergx_unregister_irq_demux(int irq)
112 {
113         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
114 }
115
116 int voyagergx_irq_demux(int irq)
117 {
118
119         if (irq == IRQ_VOYAGER ) {
120                 unsigned long i = 0, bit __attribute__ ((unused));
121                 unsigned long val  = inl(INT_STATUS);
122 #if 1
123                 if ( val & ( 1 << 1 )){
124                         i = 1;
125                 } else if ( val & ( 1 << 2 )){
126                         i = 2;
127                 } else if ( val & ( 1 << 6 )){
128                         i = 6;
129                 } else if( val & ( 1 << 10 )){
130                         i = 10;
131                 } else if( val & ( 1 << 11 )){
132                         i = 11;
133                 } else if( val & ( 1 << 12 )){
134                         i = 12;
135                 } else if( val & ( 1 << 17 )){
136                         i = 17;
137                 } else {
138                         printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
139                 }
140                 pr_debug("voyagergx_irq_demux %d \n", i);
141 #else
142                 for (bit = 1, i = 0 ; i < VOYAGER_IRQ_NUM ; bit <<= 1, i++)
143                         if (val & bit)
144                                 break;
145 #endif
146                 if (i < VOYAGER_IRQ_NUM) {
147                         irq = VOYAGER_IRQ_BASE + i;
148                         if (voyagergx_demux[i].func != 0)
149                                 irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev);
150                 }
151         }
152         return irq;
153 }
154
155 static struct irqaction irq0  = {
156         .name           = "voyagergx",
157         .handler        = voyagergx_interrupt,
158         .flags          = IRQF_DISABLED,
159         .mask           = CPU_MASK_NONE,
160 };
161
162 void __init setup_voyagergx_irq(void)
163 {
164         int i, flag;
165
166         printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
167                VOYAGER_BASE,
168                IRQ_VOYAGER,
169                VOYAGER_IRQ_BASE,
170                VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
171
172         for (i=0; i<VOYAGER_IRQ_NUM; i++) {
173                 flag = 0;
174                 switch (VOYAGER_IRQ_BASE + i) {
175                 case VOYAGER_USBH_IRQ:
176                 case VOYAGER_8051_IRQ:
177                 case VOYAGER_UART0_IRQ:
178                 case VOYAGER_UART1_IRQ:
179                 case VOYAGER_AC97_IRQ:
180                         flag = 1;
181                 }
182                 if (flag == 1)
183                         irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
184         }
185
186         setup_irq(IRQ_VOYAGER, &irq0);
187 }
188