hh.org updates
[hh.org.git] / arch / arm / mach-pxa / eseries / angelx.c
blobb01577b90a8287d077f5be481968279e145f63f2
1 /*
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>
20 #include <linux/fb.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>
27 #include <asm/irq.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>
38 common:
39 0x004:
40 1: interrupt enable
41 9: must be set (?)
42 0x010:
43 12: slot 0 service request
44 13: slot 1 service request
45 0x018:
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)
52 3: goes low on insert
53 4: acts like RDY - goes low if card present AND powered
54 0x314: event source
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
62 0x31C: event enable
63 0: EVENT0 enabled if set
64 1: EVENT1 enabled if set
65 7: EVENT7 enabled if set
66 0x32C: event enable 2
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)
78 #define BIT_0 1
79 #define BIT_1 2
80 #define BIT_7 0x80
82 //FIXME - this ought to be dynamic like the rest...
83 static struct resource angelx_res = {
84 .name = "AngelX",
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);
102 switch(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);
118 switch(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);
140 switch(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;
165 unsigned short slot;
167 slot = ANGELX_H(0x010);
169 if (slot & PCMCIA_SLOT_0) {
170 unsigned short event = ANGELX_H(0x314);
171 if(event & BIT_0)
172 pending |= 0x1;
173 else if (event & BIT_1)
174 pending |= 0x2;
175 else if (event & BIT_7)
176 pending |= 0x4;
178 else if(slot & PCMCIA_SLOT_1) {
179 unsigned short event = ANGELX_H(0x414);
180 if(event & BIT_0)
181 pending |= 0x8;
182 else if (event & BIT_1)
183 pending |= 0x10;
184 else if (event & BIT_7)
185 pending |= 0x20;
187 else
188 printk("unknown IRQ: slot = %04x\n", slot);
190 return pending;
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
198 while(pending) {
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
213 #if 0
214 static irqreturn_t e800_asic2_interrupt(int irq, void *dev, struct pt_regs *regs) {
215 unsigned short slot;
216 ANGELX_H(0x004) = 0x0200;
217 slot = ANGELX_H(0x010);
218 if (slot & PCMCIA_SLOT_0) {
219 unsigned short event = ANGELX_H(0x314);
220 if (event & BIT_0) {
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);
239 if (event & BIT_0) {
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;
257 return IRQ_HANDLED;
259 #endif
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) {
296 int voodoo_int;
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) {
340 int ret, irq;
342 ret = request_resource(&iomem_resource, &angelx_res);
343 if (ret)
344 return;
346 angelx_base = ioremap(phys_base, 0x1000);
347 if (!angelx_base)
348 return;
349 angelx_host_irq = h_irq;
351 // Now initialize the hardware
352 // Test Chip ID
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");
355 return;
357 set_irq_type(angelx_host_irq, IRQT_NOEDGE);
358 // A bit of voodoo...
359 // angelx_voodoo_b();
360 #if 0
361 ANGELX_H(0x004) = 0x0101;
362 ANGELX_H(0x008) = 0x1212;
363 ANGELX_H(0x018) = 0xFF00;
364 ANGELX_H(0x004) = 0x2222;
365 #endif
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);