sh: rts7751r2d board updates.
[linux-2.6.git] / 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 #include <linux/interrupt.h>
21 #include <linux/init.h>
22 #include <linux/io.h>
23 #include <asm/voyagergx.h>
24 #include <asm/rts7751r2d.h>
25
26 static void disable_voyagergx_irq(unsigned int irq)
27 {
28         unsigned long val;
29         unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
30
31         pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
32         val = readl((void __iomem *)VOYAGER_INT_MASK);
33         val &= ~mask;
34         writel(val, (void __iomem *)VOYAGER_INT_MASK);
35 }
36
37 static void enable_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 = readl((void __iomem *)VOYAGER_INT_MASK);
44         val |= mask;
45         writel(val, (void __iomem *)VOYAGER_INT_MASK);
46 }
47
48 static void mask_and_ack_voyagergx(unsigned int irq)
49 {
50         disable_voyagergx_irq(irq);
51 }
52
53 static void end_voyagergx_irq(unsigned int irq)
54 {
55         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
56                 enable_voyagergx_irq(irq);
57 }
58
59 static unsigned int startup_voyagergx_irq(unsigned int irq)
60 {
61         enable_voyagergx_irq(irq);
62         return 0;
63 }
64
65 static void shutdown_voyagergx_irq(unsigned int irq)
66 {
67         disable_voyagergx_irq(irq);
68 }
69
70 static struct hw_interrupt_type voyagergx_irq_type = {
71         .typename       = "VOYAGERGX-IRQ",
72         .startup        = startup_voyagergx_irq,
73         .shutdown       = shutdown_voyagergx_irq,
74         .enable         = enable_voyagergx_irq,
75         .disable        = disable_voyagergx_irq,
76         .ack            = mask_and_ack_voyagergx,
77         .end            = end_voyagergx_irq,
78 };
79
80 static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
81 {
82         printk(KERN_INFO
83                "VoyagerGX: spurious interrupt, status: 0x%x\n",
84                         (unsigned int)readl((void __iomem *)INT_STATUS));
85         return IRQ_HANDLED;
86 }
87
88 static struct {
89         int (*func)(int, void *);
90         void *dev;
91 } voyagergx_demux[VOYAGER_IRQ_NUM];
92
93 void voyagergx_register_irq_demux(int irq,
94                 int (*demux)(int irq, void *dev), void *dev)
95 {
96         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
97         voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
98 }
99
100 void voyagergx_unregister_irq_demux(int irq)
101 {
102         voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
103 }
104
105 int voyagergx_irq_demux(int irq)
106 {
107
108         if (irq == IRQ_VOYAGER ) {
109                 unsigned long i = 0, bit __attribute__ ((unused));
110                 unsigned long val  = readl((void __iomem *)INT_STATUS);
111
112                 if (val & (1 << 1))
113                         i = 1;
114                 else if (val & (1 << 2))
115                         i = 2;
116                 else if (val & (1 << 6))
117                         i = 6;
118                 else if (val & (1 << 10))
119                         i = 10;
120                 else if (val & (1 << 11))
121                         i = 11;
122                 else if (val & (1 << 12))
123                         i = 12;
124                 else if (val & (1 << 17))
125                         i = 17;
126                 else
127                         printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
128                 pr_debug("voyagergx_irq_demux %d \n", i);
129                 if (i < VOYAGER_IRQ_NUM) {
130                         irq = VOYAGER_IRQ_BASE + i;
131                         if (voyagergx_demux[i].func != 0)
132                                 irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev);
133                 }
134         }
135         return irq;
136 }
137
138 static struct irqaction irq0  = {
139         .name           = "voyagergx",
140         .handler        = voyagergx_interrupt,
141         .flags          = IRQF_DISABLED,
142         .mask           = CPU_MASK_NONE,
143 };
144
145 void __init setup_voyagergx_irq(void)
146 {
147         int i, flag;
148
149         printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
150                VOYAGER_BASE,
151                IRQ_VOYAGER,
152                VOYAGER_IRQ_BASE,
153                VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
154
155         for (i=0; i<VOYAGER_IRQ_NUM; i++) {
156                 flag = 0;
157                 switch (VOYAGER_IRQ_BASE + i) {
158                 case VOYAGER_USBH_IRQ:
159                 case VOYAGER_8051_IRQ:
160                 case VOYAGER_UART0_IRQ:
161                 case VOYAGER_UART1_IRQ:
162                 case VOYAGER_AC97_IRQ:
163                         flag = 1;
164                 }
165                 if (flag == 1)
166                         irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
167         }
168
169         setup_irq(IRQ_VOYAGER, &irq0);
170 }