blob: bf1b28feca06d7222ca5c5f53e272b753a0d6a3f [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#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>
Paul Mundtadf18902006-09-27 17:17:27 +090035#include <asm/voyagergx.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37static void disable_voyagergx_irq(unsigned int irq)
38{
Paul Mundt8599cf02006-09-27 18:03:34 +090039 unsigned long val;
40 unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42 pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 val = inl(VOYAGER_INT_MASK);
44 val &= ~mask;
45 outl(val, VOYAGER_INT_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046}
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048static void enable_voyagergx_irq(unsigned int irq)
49{
Paul Mundt8599cf02006-09-27 18:03:34 +090050 unsigned long val;
51 unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53 pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 val = inl(VOYAGER_INT_MASK);
55 val |= mask;
56 outl(val, VOYAGER_INT_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057}
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static void mask_and_ack_voyagergx(unsigned int irq)
60{
61 disable_voyagergx_irq(irq);
62}
63
64static 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
70static unsigned int startup_voyagergx_irq(unsigned int irq)
71{
72 enable_voyagergx_irq(irq);
73 return 0;
74}
75
76static void shutdown_voyagergx_irq(unsigned int irq)
77{
78 disable_voyagergx_irq(irq);
79}
80
81static struct hw_interrupt_type voyagergx_irq_type = {
Thomas Gleixner08d0fd02005-09-10 00:26:42 -070082 .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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070089};
90
Paul Mundt35f3c512006-10-06 15:31:16 +090091static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
93 printk(KERN_INFO
94 "VoyagerGX: spurious interrupt, status: 0x%x\n",
95 inl(INT_STATUS));
96 return IRQ_HANDLED;
97}
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099static struct {
100 int (*func)(int, void *);
101 void *dev;
102} voyagergx_demux[VOYAGER_IRQ_NUM];
103
104void 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
111void voyagergx_unregister_irq_demux(int irq)
112{
113 voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
114}
115
116int 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
Paul Mundt37cc7942006-02-01 03:06:05 -0800155static struct irqaction irq0 = {
156 .name = "voyagergx",
157 .handler = voyagergx_interrupt,
Thomas Gleixner6d208192006-07-01 19:29:25 -0700158 .flags = IRQF_DISABLED,
Paul Mundt37cc7942006-02-01 03:06:05 -0800159 .mask = CPU_MASK_NONE,
160};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162void __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)
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700183 irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 }
185
186 setup_irq(IRQ_VOYAGER, &irq0);
187}
188