Linux-2.6.12-rc2
[GitHub/mt8127/android_kernel_alcatel_ttab.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 }