2 * arch/arm/mach-pxa/eseries/angelx.c
4 * Support for the angelX ASIC in the Toshiba e800
6 * Author: Ian Molton and Sebastian Carlier
7 * Created: Sat 7 Aug 2004
8 * Copyright: Ian Molton and Sebastian Carlier
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/device.h>
19 #include <linux/major.h>
21 #include <linux/interrupt.h>
23 #include <asm/setup.h>
24 #include <asm/memory.h>
25 #include <asm/mach-types.h>
26 #include <asm/hardware.h>
29 #include <asm/mach/arch.h>
30 #include <asm/mach/map.h>
31 #include <asm/mach/irq.h>
33 #include <asm/arch/pxa-regs.h>
34 #include <asm/arch/eseries-irq.h>
35 #include <asm/arch/eseries-gpio.h>
43 12: slot 0 service request
44 13: slot 1 service request
46 write 0x3030 to ack interrupt
48 pcmcia slot 0 (add 0x100 for slot 1):
49 0x30c: Socket status (possibly not accessed by CE tho)
50 0: seems to correlate with event1 IRQs.
51 2: goes low on insert (later than 3: though) (used as CD)
53 4: acts like RDY - goes low if card present AND powered
55 0: EVENT0 service request
56 1: EVENT1 service request
57 7: EVENT7 service request
58 0x334: write to ack event
59 0: write with bit set to ack EVENT0
60 1: write with bit set to ack EVENT1
61 7: write with bit set to ack EVENT7
63 0: EVENT0 enabled if set
64 1: EVENT1 enabled if set
65 7: EVENT7 enabled if set
67 0: enable EVENT0 1: enable EVENT1 and EVENT7
69 EVENT0 is unknown EVENT1 is unknown
70 EVENT7 is card insert/eject
73 #define ANGELX_B(n) (*(unsigned char *)(angelx_base + (n)))
74 #define ANGELX_H(n) (*(unsigned short *)(angelx_base + (n)))
76 #define PCMCIA_SLOT_0 (1<<12)
77 #define PCMCIA_SLOT_1 (1<<13)
82 //FIXME - this ought to be dynamic like the rest...
83 static struct resource angelx_res
= {
85 .start
= PXA_CS5_PHYS
,
86 .end
= PXA_CS5_PHYS
+ 0xfff,
87 .flags
= IORESOURCE_IO
,
90 static void* angelx_base
;
91 static int angelx_host_irq
;
93 unsigned char angelx_get_state(int skt
) {
94 return ANGELX_B(0x30c+(skt
== 0 ? 0 : 0x100));
96 EXPORT_SYMBOL(angelx_get_state
);
98 static void angelx_ack_irq(unsigned int irq
)
100 int angelx_irq
= (irq
- ANGELX_IRQ_BASE
);
101 // printk("angelx: ack %d\n", angelx_irq);
103 case 0: ANGELX_H(0x334) = BIT_0
; break;
104 case 1: ANGELX_H(0x334) = BIT_1
; break;
105 case 2: ANGELX_H(0x334) = BIT_7
; break;
107 case 3: ANGELX_H(0x434) = BIT_0
; break;
108 case 4: ANGELX_H(0x434) = BIT_1
; break;
109 case 5: ANGELX_H(0x434) = BIT_7
; break;
113 static void angelx_mask_irq(unsigned int irq
)
115 int angelx_irq
= (irq
- ANGELX_IRQ_BASE
);
116 // printk("angelx: mask %d\n", angelx_irq);
119 case 0: ANGELX_H(0x32c) &= ~BIT_0
;
120 ANGELX_H(0x31c) &= ~BIT_0
; break;
121 case 1: ANGELX_H(0x32c) &= ~BIT_1
;
122 ANGELX_H(0x31c) &= ~BIT_1
; break;
123 case 2: ANGELX_H(0x32c) &= ~BIT_1
;
124 ANGELX_H(0x31c) &= ~BIT_7
; break;
126 case 3: ANGELX_H(0x42c) &= ~BIT_0
;
127 ANGELX_H(0x41c) &= ~BIT_0
; break;
128 case 4: ANGELX_H(0x42c) &= ~BIT_1
;
129 ANGELX_H(0x41c) &= ~BIT_1
; break;
130 case 5: ANGELX_H(0x42c) &= ~BIT_1
;
131 ANGELX_H(0x41c) &= ~BIT_7
; break;
135 static void angelx_unmask_irq(unsigned int irq
)
137 int angelx_irq
= (irq
- ANGELX_IRQ_BASE
);
138 // printk("angelx: unmask %d\n", angelx_irq);
141 case 0: ANGELX_H(0x32c) |= BIT_0
;
142 ANGELX_H(0x31c) |= BIT_0
; break;
143 case 1: ANGELX_H(0x32c) |= BIT_1
;
144 ANGELX_H(0x31c) |= BIT_1
; break;
145 case 2: ANGELX_H(0x32c) |= BIT_1
;
146 ANGELX_H(0x31c) |= BIT_7
; break;
148 case 3: ANGELX_H(0x42c) |= BIT_0
;
149 ANGELX_H(0x41c) |= BIT_0
; break;
150 case 4: ANGELX_H(0x42c) |= BIT_1
;
151 ANGELX_H(0x41c) |= BIT_1
; break;
152 case 5: ANGELX_H(0x42c) |= BIT_1
;
153 ANGELX_H(0x41c) |= BIT_7
; break;
157 static struct irqchip angelx_irq_chip
= {
158 .ack
= angelx_ack_irq
,
159 .mask
= angelx_mask_irq
,
160 .unmask
= angelx_unmask_irq
,
163 unsigned long angelx_get_pending(void){
164 unsigned long pending
= 0;
167 slot
= ANGELX_H(0x010);
169 if (slot
& PCMCIA_SLOT_0
) {
170 unsigned short event
= ANGELX_H(0x314);
173 else if (event
& BIT_1
)
175 else if (event
& BIT_7
)
178 else if(slot
& PCMCIA_SLOT_1
) {
179 unsigned short event
= ANGELX_H(0x414);
182 else if (event
& BIT_1
)
184 else if (event
& BIT_7
)
188 printk("unknown IRQ: slot = %04x\n", slot
);
193 static void angelx_irq_handler(unsigned int irq
, struct irqdesc
*desc
) {
194 unsigned long pending
;
196 ANGELX_H(0x0004) = 0x0200; // Disable AngelX IRQ
197 pending
= angelx_get_pending(); // FIXME - take account of the mask
199 GEDR(angelx_host_irq
) = GPIO_bit(angelx_host_irq
); /* clear our parent irq */
200 if (likely(pending
)) {
201 irq
= ANGELX_IRQ_BASE
+ __ffs(pending
);
202 if(irq
== 113 || irq
== 116 || irq
== 112 || irq
==115)
203 printk("IRQ: %d %02x %02x\n", irq
, angelx_get_state(0), angelx_get_state(1));
204 desc
= irq_desc
+ irq
;
205 desc
->handle_irq(irq
, desc
);
207 pending
&= ~(1<<__ffs(pending
));
209 ANGELX_H(0x018) = 0x3030;
210 ANGELX_H(0x0004) = 0x2222; // Enable AngelX IRQ
214 static irqreturn_t
e800_asic2_interrupt(int irq
, void *dev
, struct pt_regs
*regs
) {
216 ANGELX_H(0x004) = 0x0200;
217 slot
= ANGELX_H(0x010);
218 if (slot
& PCMCIA_SLOT_0
) {
219 unsigned short event
= ANGELX_H(0x314);
221 ANGELX_H(0x334) = BIT_0
;
222 ANGELX_H(0x32C) |= BIT_0
;
223 ANGELX_H(0x31C) |= BIT_0
;
224 printk("pcmcia[0]: event 0\n");
225 } else if (event
& BIT_1
) {
226 ANGELX_H(0x334) = BIT_1
;
227 ANGELX_H(0x32C) |= BIT_1
;
228 ANGELX_H(0x31C) |= BIT_1
;
229 printk("pcmcia[0]: event 1\n");
230 } else if (event
& BIT_7
) {
231 ANGELX_H(0x334) = BIT_7
;
232 ANGELX_H(0x32C) |= BIT_1
;
233 ANGELX_H(0x31C) |= BIT_7
;
234 printk("pcmcia[0]: status changed\n");
236 ANGELX_H(0x018) = 0x3030;
237 } else if (slot
& PCMCIA_SLOT_1
) {
238 unsigned short event
= ANGELX_H(0x414);
240 ANGELX_H(0x434) = BIT_0
;
241 ANGELX_H(0x42C) |= BIT_0
;
242 ANGELX_H(0x41C) |= BIT_0
;
243 printk("pcmcia[1]: event 0\n");
244 } else if (event
& BIT_1
) {
245 ANGELX_H(0x434) = BIT_1
;
246 ANGELX_H(0x42C) |= BIT_1
;
247 ANGELX_H(0x41C) |= BIT_1
;
248 printk("pcmcia[1]: event 1\n");
249 } else if (event
& BIT_7
) {
250 ANGELX_H(0x434) = BIT_7
;
251 ANGELX_H(0x42C) |= BIT_1
;
252 ANGELX_H(0x41C) |= BIT_7
;
253 printk("pcmcia[1]: event 2\n");
256 ANGELX_H(0x004) = 0x0202;
261 #define ASIC2_H ANGELX_H
263 void angelx_voodoo_b(void) {
264 ASIC2_H(0x004) = 0x0101;
265 ASIC2_H(0x008) = 0x1212;
266 ASIC2_H(0x300) = ((ASIC2_H(0x000) & 0x8000) ? 0x0401 : 0x0501);
267 ASIC2_H(0x338) = 0x0000;
268 ASIC2_H(0x33C) = 0x0000;
269 ASIC2_H(0x340) = 0x0700;
270 ASIC2_H(0x334) = 0x0080;
271 // while (BIT_7 & ASIC2_H(0x334));
272 ASIC2_H(0x31C) |= 0x0080;
274 ASIC2_H(0x004) = 0x2020;
275 ASIC2_H(0x004) = 0x4000;
276 ASIC2_H(0x008) = 0x1212;
278 ASIC2_H(0x004) = 0x0101;
279 ASIC2_H(0x008) = 0x2222;
280 ASIC2_H(0x400) = (ASIC2_H(0x000) & 0x8000) ? 0x0401 : 0x0501;
281 ASIC2_H(0x438) = 0x0000;
282 ASIC2_H(0x43C) = 0x0000;
283 ASIC2_H(0x440) = 0x0300;
284 ASIC2_H(0x434) = 0x0080;
285 // while (BIT_7 & ASIC2_H(0x434));
286 ASIC2_H(0x41C) |= 0x0080;
288 ASIC2_H(0x004) = 0x2020;
289 ASIC2_H(0x004) = 0x4000;
290 ASIC2_H(0x008) = 0x1212;
292 ASIC2_H(0x008) = 0x2020;
295 void angelx_voodoo(void) {
297 ASIC2_H(0x204) = 0x0000;
298 ASIC2_H(0x238) = 0x0000;
299 voodoo_int
= ASIC2_H(0x018);
300 printk("angelx: voodoo_int = %08x\n", voodoo_int
);
301 ASIC2_H(0x004) = 0x8000;
302 ASIC2_H(0x004) = 0x4040;
303 ASIC2_H(0x004) = 0x2000;
304 ASIC2_H(0x008) = 0x3A00;
306 ASIC2_H(0x004) = 0x0101;
307 ASIC2_H(0x008) = 0x0202;
308 ASIC2_H(0x200) = 0x0000;
309 ASIC2_H(0x208) = 0x0000;
310 ASIC2_H(0x018) = 0xFF00;
311 ASIC2_H(0x004) = 0x2222;
313 ASIC2_H(0x004) = 0x0101;
314 ASIC2_H(0x008) = 0x1212;
315 ASIC2_H(0x300) = ((ASIC2_H(0x000) & 0x8000) ? 0x0401 : 0x0501);
316 ASIC2_H(0x338) = 0x0000;
317 ASIC2_H(0x33C) = 0x0000;
318 ASIC2_H(0x340) = 0x0700;
319 ASIC2_H(0x334) = 0x0080;
320 // while (BIT_7 & ASIC2_H(0x334));
321 ASIC2_H(0x31C) |= 0x0080;
323 ASIC2_H(0x004) = 0x0101;
324 ASIC2_H(0x008) = 0x2222;
325 ASIC2_H(0x400) = (ASIC2_H(0x000) & 0x8000) ? 0x0401 : 0x0501;
326 ASIC2_H(0x438) = 0x0000;
327 ASIC2_H(0x43C) = 0x0000;
328 ASIC2_H(0x440) = 0x0300;
329 ASIC2_H(0x434) = 0x0080;
330 // while (BIT_7 & ASIC2_H(0x434));
331 ASIC2_H(0x41C) |= 0x0080;
333 ASIC2_H(0x204) = 0x0008;
334 ASIC2_H(0x2A0) = 0x0092;
335 ASIC2_H(0x018) = (voodoo_int
<< 8) | (voodoo_int
& 0xFF);
339 void __init
angelx_init_irq(int h_irq
, unsigned int phys_base
) {
342 ret
= request_resource(&iomem_resource
, &angelx_res
);
346 angelx_base
= ioremap(phys_base
, 0x1000);
349 angelx_host_irq
= h_irq
;
351 // Now initialize the hardware
353 if(ANGELX_H(0) != 0x8215){
354 printk("This appears to be an unknown AngelX variant. Please contact us with details of your hardware.\n");
357 set_irq_type(angelx_host_irq
, IRQT_NOEDGE
);
358 // A bit of voodoo...
359 // angelx_voodoo_b();
361 ANGELX_H(0x004) = 0x0101;
362 ANGELX_H(0x008) = 0x1212;
363 ANGELX_H(0x018) = 0xFF00;
364 ANGELX_H(0x004) = 0x2222;
366 ANGELX_H(0x004) = 0x0101;
367 ANGELX_H(0x008) = 0x0202;
368 ANGELX_H(0x018) = 0xFF00;
369 ANGELX_H(0x004) = 0x2222;
371 // Clear pending socket 0 requests
372 ANGELX_H(0x334) |= BIT_0
| BIT_1
| BIT_7
;
373 ANGELX_H(0x31C) |= BIT_0
| BIT_1
| BIT_7
;
374 ANGELX_H(0x32C) |= BIT_1
;
375 ANGELX_H(0x434) |= BIT_0
| BIT_1
| BIT_7
;
376 ANGELX_H(0x41C) |= BIT_0
| BIT_1
| BIT_7
;
377 ANGELX_H(0x42C) |= BIT_1
;
378 ANGELX_H(0x018) = 0x3030;
380 printk("angelx: initialised.\n");
382 /* setup extra lubbock irqs */
383 for (irq
= ANGELX_IRQ_BASE
; irq
< ANGELX_IRQ_BASE
+6; irq
++) {
384 set_irq_chip(irq
, &angelx_irq_chip
);
385 set_irq_handler(irq
, do_edge_IRQ
);
386 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
389 set_irq_chained_handler(angelx_host_irq
, angelx_irq_handler
);
391 // Re-enable interrupt
392 set_irq_type(angelx_host_irq
, IRQT_RISING
);
395 EXPORT_SYMBOL(angelx_init_irq
);