hwmon/vt1211: Add probing of alternate config index port
[pandora-kernel.git] / arch / sh / boards / ec3104 / irq.c
1 /*
2  * linux/arch/sh/boards/ec3104/irq.c
3  * EC3104 companion chip support
4  *
5  * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
6  *
7  */
8
9 #include <asm/io.h>
10 #include <asm/irq.h>
11 #include <asm/ec3104/ec3104.h>
12
13 /* This is for debugging mostly;  here's the table that I intend to keep
14  * in here:
15  *
16  *   index      function        base addr       power           interrupt bit
17  *       0      power           b0ec0000        ---             00000001 (unused)
18  *       1      irqs            b0ec1000        ---             00000002 (unused)
19  *       2      ??              b0ec2000        b0ec0008        00000004
20  *       3      PS2 (1)         b0ec3000        b0ec000c        00000008
21  *       4      PS2 (2)         b0ec4000        b0ec0010        00000010
22  *       5      ??              b0ec5000        b0ec0014        00000020
23  *       6      I2C             b0ec6000        b0ec0018        00000040
24  *       7      serial (1)      b0ec7000        b0ec001c        00000080
25  *       8      serial (2)      b0ec8000        b0ec0020        00000100
26  *       9      serial (3)      b0ec9000        b0ec0024        00000200
27  *      10      serial (4)      b0eca000        b0ec0028        00000400
28  *      12      GPIO (1)        b0ecc000        b0ec0030
29  *      13      GPIO (2)        b0ecc000        b0ec0030
30  *      16      pcmcia (1)      b0ed0000        b0ec0040        00010000
31  *      17      pcmcia (2)      b0ed1000        b0ec0044        00020000
32  */
33
34 /* I used the register names from another interrupt controller I worked with,
35  * since it seems to be identical to the ec3104 except that all bits are
36  * inverted:
37  *
38  * IRR: Interrupt Request Register (pending and enabled interrupts)
39  * IMR: Interrupt Mask Register (which interrupts are enabled)
40  * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
41  *
42  * 0 bits mean pending or enabled, 1 bits mean not pending or disabled.  all
43  * IRQs seem to be level-triggered.
44  */
45
46 #define EC3104_IRR (EC3104_BASE + 0x1000)
47 #define EC3104_IMR (EC3104_BASE + 0x1004)
48 #define EC3104_IPR (EC3104_BASE + 0x1008)
49
50 #define ctrl_readl(addr) (*(volatile u32 *)(addr))
51 #define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
52 #define ctrl_readb(addr) (*(volatile u8 *)(addr))
53
54 static char *ec3104_name(unsigned index)
55 {
56         switch(index) {
57         case 0:
58                 return "power management";
59         case 1:
60                 return "interrupts";
61         case 3:
62                 return "PS2 (1)";
63         case 4:
64                 return "PS2 (2)";
65         case 5:
66                 return "I2C (1)";
67         case 6:
68                 return "I2C (2)";
69         case 7:
70                 return "serial (1)";
71         case 8:
72                 return "serial (2)";
73         case 9:
74                 return "serial (3)";
75         case 10:
76                 return "serial (4)";
77         case 16:
78                 return "pcmcia (1)";
79         case 17:
80                 return "pcmcia (2)";
81         default: {
82                 static char buf[32];
83
84                 sprintf(buf, "unknown (%d)", index);
85
86                 return buf;
87                 }
88         }
89 }
90
91 int get_pending_interrupts(char *buf)
92 {
93         u32 ipr;
94         u32 bit;
95         char *p = buf;
96
97         p += sprintf(p, "pending: (");
98
99         ipr = ctrl_inl(EC3104_IPR);
100
101         for (bit = 1; bit < 32; bit++)
102                 if (!(ipr & (1<<bit)))
103                         p += sprintf(p, "%s ", ec3104_name(bit));
104
105         p += sprintf(p, ")\n");
106
107         return p - buf;
108 }
109
110 static inline u32 ec3104_irq2mask(unsigned int irq)
111 {
112         return (1 << (irq - EC3104_IRQBASE));
113 }
114
115 static inline void mask_ec3104_irq(unsigned int irq)
116 {
117         u32 mask;
118
119         mask = ctrl_readl(EC3104_IMR);
120
121         mask |= ec3104_irq2mask(irq);
122
123         ctrl_writel(mask, EC3104_IMR);
124 }
125
126 static inline void unmask_ec3104_irq(unsigned int irq)
127 {
128         u32 mask;
129
130         mask = ctrl_readl(EC3104_IMR);
131
132         mask &= ~ec3104_irq2mask(irq);
133
134         ctrl_writel(mask, EC3104_IMR);
135 }
136
137 static void disable_ec3104_irq(unsigned int irq)
138 {
139         mask_ec3104_irq(irq);
140 }
141
142 static void enable_ec3104_irq(unsigned int irq)
143 {
144         unmask_ec3104_irq(irq);
145 }
146
147 static void mask_and_ack_ec3104_irq(unsigned int irq)
148 {
149         mask_ec3104_irq(irq);
150 }
151
152 static void end_ec3104_irq(unsigned int irq)
153 {
154         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
155                 unmask_ec3104_irq(irq);
156 }
157
158 static unsigned int startup_ec3104_irq(unsigned int irq)
159 {
160         unmask_ec3104_irq(irq);
161
162         return 0;
163 }
164
165 static void shutdown_ec3104_irq(unsigned int irq)
166 {
167         mask_ec3104_irq(irq);
168
169 }
170
171 static struct hw_interrupt_type ec3104_int = {
172         .typename       = "EC3104",
173         .enable         = enable_ec3104_irq,
174         .disable        = disable_ec3104_irq,
175         .ack            = mask_and_ack_ec3104_irq,
176         .end            = end_ec3104_irq,
177         .startup        = startup_ec3104_irq,
178         .shutdown       = shutdown_ec3104_irq,
179 };
180
181 /* Yuck.  the _demux API is ugly */
182 int ec3104_irq_demux(int irq)
183 {
184         if (irq == EC3104_IRQ) {
185                 unsigned int mask;
186
187                 mask = ctrl_readl(EC3104_IRR);
188
189                 if (mask == 0xffffffff)
190                         return EC3104_IRQ;
191                 else
192                         return EC3104_IRQBASE + ffz(mask);
193         }
194
195         return irq;
196 }