blob: 1b6ac523b4584e7cf5518f992cb340d293859484 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* -------------------------------------------------------------------- */
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
39static 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
53static 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
67static void mask_and_ack_voyagergx(unsigned int irq)
68{
69 disable_voyagergx_irq(irq);
70}
71
72static 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
78static unsigned int startup_voyagergx_irq(unsigned int irq)
79{
80 enable_voyagergx_irq(irq);
81 return 0;
82}
83
84static void shutdown_voyagergx_irq(unsigned int irq)
85{
86 disable_voyagergx_irq(irq);
87}
88
89static struct hw_interrupt_type voyagergx_irq_type = {
Thomas Gleixner08d0fd02005-09-10 00:26:42 -070090 .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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
99static 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
110static struct {
111 int (*func)(int, void *);
112 void *dev;
113} voyagergx_demux[VOYAGER_IRQ_NUM];
114
115void 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
122void voyagergx_unregister_irq_demux(int irq)
123{
124 voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
125}
126
127int 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
166static struct irqaction irq0 = { voyagergx_interrupt, SA_INTERRUPT, 0, "VOYAGERGX", NULL, NULL};
167
168void __init setup_voyagergx_irq(void)
169{
170 int i, flag;
171
172 printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
173 VOYAGER_BASE,
174 IRQ_VOYAGER,
175 VOYAGER_IRQ_BASE,
176 VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
177
178 for (i=0; i<VOYAGER_IRQ_NUM; i++) {
179 flag = 0;
180 switch (VOYAGER_IRQ_BASE + i) {
181 case VOYAGER_USBH_IRQ:
182 case VOYAGER_8051_IRQ:
183 case VOYAGER_UART0_IRQ:
184 case VOYAGER_UART1_IRQ:
185 case VOYAGER_AC97_IRQ:
186 flag = 1;
187 }
188 if (flag == 1)
189 irq_desc[VOYAGER_IRQ_BASE + i].handler = &voyagergx_irq_type;
190 }
191
192 setup_irq(IRQ_VOYAGER, &irq0);
193}
194