blob: d70e5c8461b56e4b60c72c43ae9204c4b0637a8e [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*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/interrupt.h>
21#include <linux/init.h>
Paul Mundt082c44d2006-10-19 16:16:18 +090022#include <linux/io.h>
Paul Mundtadf18902006-09-27 17:17:27 +090023#include <asm/voyagergx.h>
Paul Mundt082c44d2006-10-19 16:16:18 +090024#include <asm/rts7751r2d.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26static void disable_voyagergx_irq(unsigned int irq)
27{
Paul Mundt8599cf02006-09-27 18:03:34 +090028 unsigned long val;
29 unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Paul Mundt63dfc3c2007-06-04 10:53:00 +090031 pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
Paul Mundt9c575482007-02-15 18:20:52 +090032 val = readl((void __iomem *)VOYAGER_INT_MASK);
33 val &= ~mask;
34 writel(val, (void __iomem *)VOYAGER_INT_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035}
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037static void enable_voyagergx_irq(unsigned int irq)
38{
Paul Mundt9c575482007-02-15 18:20:52 +090039 unsigned long val;
40 unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Paul Mundt63dfc3c2007-06-04 10:53:00 +090042 pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
Paul Mundt9c575482007-02-15 18:20:52 +090043 val = readl((void __iomem *)VOYAGER_INT_MASK);
44 val |= mask;
45 writel(val, (void __iomem *)VOYAGER_INT_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046}
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048static void mask_and_ack_voyagergx(unsigned int irq)
49{
50 disable_voyagergx_irq(irq);
51}
52
53static 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
59static unsigned int startup_voyagergx_irq(unsigned int irq)
60{
61 enable_voyagergx_irq(irq);
62 return 0;
63}
64
65static void shutdown_voyagergx_irq(unsigned int irq)
66{
67 disable_voyagergx_irq(irq);
68}
69
70static struct hw_interrupt_type voyagergx_irq_type = {
Paul Mundt9c575482007-02-15 18:20:52 +090071 .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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
Paul Mundt35f3c512006-10-06 15:31:16 +090080static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081{
82 printk(KERN_INFO
83 "VoyagerGX: spurious interrupt, status: 0x%x\n",
Paul Mundt9c575482007-02-15 18:20:52 +090084 (unsigned int)readl((void __iomem *)INT_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 return IRQ_HANDLED;
86}
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static struct {
89 int (*func)(int, void *);
90 void *dev;
91} voyagergx_demux[VOYAGER_IRQ_NUM];
92
93void voyagergx_register_irq_demux(int irq,
94 int (*demux)(int irq, void *dev), void *dev)
95{
Paul Mundt9c575482007-02-15 18:20:52 +090096 voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
97 voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100void voyagergx_unregister_irq_demux(int irq)
101{
Paul Mundt9c575482007-02-15 18:20:52 +0900102 voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105int voyagergx_irq_demux(int irq)
106{
107
108 if (irq == IRQ_VOYAGER ) {
109 unsigned long i = 0, bit __attribute__ ((unused));
Paul Mundt9c575482007-02-15 18:20:52 +0900110 unsigned long val = readl((void __iomem *)INT_STATUS);
111
112 if (val & (1 << 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 i = 1;
Paul Mundt9c575482007-02-15 18:20:52 +0900114 else if (val & (1 << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 i = 2;
Paul Mundt9c575482007-02-15 18:20:52 +0900116 else if (val & (1 << 6))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 i = 6;
Paul Mundt9c575482007-02-15 18:20:52 +0900118 else if (val & (1 << 10))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 i = 10;
Paul Mundt9c575482007-02-15 18:20:52 +0900120 else if (val & (1 << 11))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 i = 11;
Paul Mundt9c575482007-02-15 18:20:52 +0900122 else if (val & (1 << 12))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 i = 12;
Paul Mundt9c575482007-02-15 18:20:52 +0900124 else if (val & (1 << 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 i = 17;
Paul Mundt9c575482007-02-15 18:20:52 +0900126 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
Paul Mundt63dfc3c2007-06-04 10:53:00 +0900128 pr_debug("voyagergx_irq_demux %ld \n", i);
129 if (i < VOYAGER_IRQ_NUM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 irq = VOYAGER_IRQ_BASE + i;
Paul Mundt63dfc3c2007-06-04 10:53:00 +0900131 if (voyagergx_demux[i].func != 0)
132 irq = voyagergx_demux[i].func(irq,
133 voyagergx_demux[i].dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 }
135 }
136 return irq;
137}
138
Paul Mundt37cc7942006-02-01 03:06:05 -0800139static struct irqaction irq0 = {
140 .name = "voyagergx",
141 .handler = voyagergx_interrupt,
Thomas Gleixner6d208192006-07-01 19:29:25 -0700142 .flags = IRQF_DISABLED,
Paul Mundt37cc7942006-02-01 03:06:05 -0800143 .mask = CPU_MASK_NONE,
144};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146void __init setup_voyagergx_irq(void)
147{
148 int i, flag;
149
150 printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
151 VOYAGER_BASE,
152 IRQ_VOYAGER,
153 VOYAGER_IRQ_BASE,
154 VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
155
156 for (i=0; i<VOYAGER_IRQ_NUM; i++) {
157 flag = 0;
158 switch (VOYAGER_IRQ_BASE + i) {
159 case VOYAGER_USBH_IRQ:
160 case VOYAGER_8051_IRQ:
161 case VOYAGER_UART0_IRQ:
162 case VOYAGER_UART1_IRQ:
163 case VOYAGER_AC97_IRQ:
164 flag = 1;
165 }
166 if (flag == 1)
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700167 irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169
170 setup_irq(IRQ_VOYAGER, &irq0);
171}