Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[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/config.h>
25 #include <linux/sched.h>
26 #include <linux/module.h>
27 #include <linux/kernel.h>
28 #include <linux/param.h>
29 #include <linux/ioport.h>
30 #include <linux/interrupt.h>
31 #include <linux/init.h>
32 #include <linux/irq.h>
33
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/rts7751r2d/rts7751r2d.h>
37 #include <asm/rts7751r2d/voyagergx_reg.h>
38
39 static void disable_voyagergx_irq(unsigned int irq)
40 {
41         unsigned long flags, val;
42         unsigned long  mask = 1 << (irq - VOYAGER_IRQ_BASE);
43
44         pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
45         local_irq_save(flags);
46         val = inl(VOYAGER_INT_MASK);
47         val &= ~mask;
48         outl(val, VOYAGER_INT_MASK);
49         local_irq_restore(flags);
50 }
51
52
53 static void enable_voyagergx_irq(unsigned int irq)
54 {
55         unsigned long flags, val;
56         unsigned long  mask = 1 << (irq - VOYAGER_IRQ_BASE);
57
58         pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
59         local_irq_save(flags);
60         val = inl(VOYAGER_INT_MASK);
61         val |= mask;
62         outl(val, VOYAGER_INT_MASK);
63         local_irq_restore(flags);
64 }
65
66
67 static void mask_and_ack_voyagergx(unsigned int irq)
68 {
69         disable_voyagergx_irq(irq);
70 }
71
72 static void end_voyagergx_irq(unsigned int irq)
73 {
74         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
75                 enable_voyagergx_irq(irq);
76 }
77
78 static unsigned int startup_voyagergx_irq(unsigned int irq)
79 {
80         enable_voyagergx_irq(irq);
81         return 0;
82 }
83
84 static void shutdown_voyagergx_irq(unsigned int irq)
85 {
86         disable_voyagergx_irq(irq);
87 }
88
89 static struct hw_interrupt_type voyagergx_irq_type = {
90         .typename = "VOYAGERGX-IRQ",
91         .startup = startup_voyagergx_irq,
92         .shutdown = shutdown_voyagergx_irq,
93         .enable = enable_voyagergx_irq,
94         .disable = disable_voyagergx_irq,
95         .ack = mask_and_ack_voyagergx,
96         .end = end_voyagergx_irq,
97 };
98
99 static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
100 {
101         printk(KERN_INFO
102                "VoyagerGX: spurious interrupt, status: 0x%x\n",
103                         inl(INT_STATUS));
104         return IRQ_HANDLED;
105 }
106
107
108 /*====================================================*/
109
110 static struct {
111         int (*func)(int, void *);
112         void *dev;
113 } voyagergx_demux[VOYAGER_IRQ_NUM];
114
115 void voyagergx_register_irq_demux(int irq,
116                 int (*demux)(int irq, void *dev), void *dev)
117 {
118         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
119         voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
120 }
121
122 void voyagergx_unregister_irq_demux(int irq)
123 {
124         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
125 }
126
127 int voyagergx_irq_demux(int irq)
128 {
129
130         if (irq == IRQ_VOYAGER ) {
131                 unsigned long i = 0, bit __attribute__ ((unused));
132                 unsigned long val  = inl(INT_STATUS);
133 #if 1
134                 if ( val & ( 1 << 1 )){
135                         i = 1;
136                 } else if ( val & ( 1 << 2 )){
137                         i = 2;
138                 } else if ( val & ( 1 << 6 )){
139                         i = 6;
140                 } else if( val & ( 1 << 10 )){
141                         i = 10;
142                 } else if( val & ( 1 << 11 )){
143                         i = 11;
144                 } else if( val & ( 1 << 12 )){
145                         i = 12;
146                 } else if( val & ( 1 << 17 )){
147                         i = 17;
148                 } else {
149                         printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
150                 }
151                 pr_debug("voyagergx_irq_demux %d \n", i);
152 #else
153                 for (bit = 1, i = 0 ; i < VOYAGER_IRQ_NUM ; bit <<= 1, i++)
154                         if (val & bit)
155                                 break;
156 #endif
157                 if (i < VOYAGER_IRQ_NUM) {
158                         irq = VOYAGER_IRQ_BASE + i;
159                         if (voyagergx_demux[i].func != 0)
160                                 irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev);
161                 }
162         }
163         return irq;
164 }
165
166 static struct irqaction irq0  = {
167         .name           = "voyagergx",
168         .handler        = voyagergx_interrupt,
169         .flags          = SA_INTERRUPT,
170         .mask           = CPU_MASK_NONE,
171 };
172
173 void __init setup_voyagergx_irq(void)
174 {
175         int i, flag;
176
177         printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
178                VOYAGER_BASE,
179                IRQ_VOYAGER,
180                VOYAGER_IRQ_BASE,
181                VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
182
183         for (i=0; i<VOYAGER_IRQ_NUM; i++) {
184                 flag = 0;
185                 switch (VOYAGER_IRQ_BASE + i) {
186                 case VOYAGER_USBH_IRQ:
187                 case VOYAGER_8051_IRQ:
188                 case VOYAGER_UART0_IRQ:
189                 case VOYAGER_UART1_IRQ:
190                 case VOYAGER_AC97_IRQ:
191                         flag = 1;
192                 }
193                 if (flag == 1)
194                         irq_desc[VOYAGER_IRQ_BASE + i].handler = &voyagergx_irq_type;
195         }
196
197         setup_irq(IRQ_VOYAGER, &irq0);
198 }
199