Merge ../linus
[pandora-kernel.git] / arch / arm / mach-lh7a40x / arch-lpd7a40x.c
1 /* arch/arm/mach-lh7a40x/arch-lpd7a40x.c
2  *
3  *  Copyright (C) 2004 Logic Product Development
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU General Public License
7  *  version 2 as published by the Free Software Foundation.
8  *
9  */
10
11 #include <linux/tty.h>
12 #include <linux/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/interrupt.h>
15
16 #include <asm/hardware.h>
17 #include <asm/setup.h>
18 #include <asm/mach-types.h>
19 #include <asm/mach/arch.h>
20 #include <asm/irq.h>
21 #include <asm/mach/irq.h>
22 #include <asm/mach/map.h>
23
24 #include "common.h"
25
26 #define CPLD_INT_NETHERNET      (1<<0)
27 #define CPLD_INTMASK_ETHERNET   (1<<2)
28 #if defined (CONFIG_MACH_LPD7A400)
29 # define CPLD_INT_NTOUCH                (1<<1)
30 # define CPLD_INTMASK_TOUCH     (1<<3)
31 # define CPLD_INT_PEN           (1<<4)
32 # define CPLD_INTMASK_PEN       (1<<4)
33 # define CPLD_INT_PIRQ          (1<<4)
34 #endif
35 #define CPLD_INTMASK_CPLD       (1<<7)
36 #define CPLD_INT_CPLD           (1<<6)
37
38 #define CPLD_CONTROL_SWINT              (1<<7) /* Disable all CPLD IRQs */
39 #define CPLD_CONTROL_OCMSK              (1<<6) /* Mask USB1 connect IRQ */
40 #define CPLD_CONTROL_PDRV               (1<<5) /* PCC_nDRV high */
41 #define CPLD_CONTROL_USB1C              (1<<4) /* USB1 connect IRQ active */
42 #define CPLD_CONTROL_USB1P              (1<<3) /* USB1 power disable */
43 #define CPLD_CONTROL_AWKP               (1<<2) /* Auto-wakeup disabled  */
44 #define CPLD_CONTROL_LCD_ENABLE         (1<<1) /* LCD Vee enable */
45 #define CPLD_CONTROL_WRLAN_NENABLE      (1<<0) /* SMC91x power disable */
46
47
48 static struct resource smc91x_resources[] = {
49         [0] = {
50                 .start  = CPLD00_PHYS,
51                 .end    = CPLD00_PHYS + CPLD00_SIZE - 1, /* Only needs 16B */
52                 .flags  = IORESOURCE_MEM,
53         },
54
55         [1] = {
56                 .start  = IRQ_LPD7A40X_ETH_INT,
57                 .end    = IRQ_LPD7A40X_ETH_INT,
58                 .flags  = IORESOURCE_IRQ,
59         },
60
61 };
62
63 static struct platform_device smc91x_device = {
64         .name           = "smc91x",
65         .id             = 0,
66         .num_resources  = ARRAY_SIZE(smc91x_resources),
67         .resource       = smc91x_resources,
68 };
69
70 static struct resource lh7a40x_usbclient_resources[] = {
71         [0] = {
72                 .start  = USB_PHYS,
73                 .end    = (USB_PHYS + PAGE_SIZE),
74                 .flags  = IORESOURCE_MEM,
75         },
76         [1] = {
77                 .start  = IRQ_USB,
78                 .end    = IRQ_USB,
79                 .flags  = IORESOURCE_IRQ,
80         },
81 };
82
83 static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL;
84
85 static struct platform_device lh7a40x_usbclient_device = {
86 //      .name           = "lh7a40x_udc",
87         .name           = "lh7-udc",
88         .id             = 0,
89         .dev            = {
90                 .dma_mask = &lh7a40x_usbclient_dma_mask,
91                 .coherent_dma_mask = 0xffffffffUL,
92         },
93         .num_resources  = ARRAY_SIZE (lh7a40x_usbclient_resources),
94         .resource       = lh7a40x_usbclient_resources,
95 };
96
97 #if defined (CONFIG_ARCH_LH7A404)
98
99 static struct resource lh7a404_usbhost_resources [] = {
100         [0] = {
101                 .start  = USBH_PHYS,
102                 .end    = (USBH_PHYS + 0xFF),
103                 .flags  = IORESOURCE_MEM,
104         },
105         [1] = {
106                 .start  = IRQ_USHINTR,
107                 .end    = IRQ_USHINTR,
108                 .flags  = IORESOURCE_IRQ,
109         },
110 };
111
112 static u64 lh7a404_usbhost_dma_mask = 0xffffffffUL;
113
114 static struct platform_device lh7a404_usbhost_device = {
115         .name           = "lh7a404-ohci",
116         .id             = 0,
117         .dev            = {
118                 .dma_mask = &lh7a404_usbhost_dma_mask,
119                 .coherent_dma_mask = 0xffffffffUL,
120         },
121         .num_resources  = ARRAY_SIZE (lh7a404_usbhost_resources),
122         .resource       = lh7a404_usbhost_resources,
123 };
124
125 #endif
126
127 static struct platform_device* lpd7a40x_devs[] __initdata = {
128         &smc91x_device,
129         &lh7a40x_usbclient_device,
130 #if defined (CONFIG_ARCH_LH7A404)
131         &lh7a404_usbhost_device,
132 #endif
133 };
134
135 extern void lpd7a400_map_io (void);
136
137 static void __init lpd7a40x_init (void)
138 {
139 #if defined (CONFIG_MACH_LPD7A400)
140         CPLD_CONTROL |= 0
141                 | CPLD_CONTROL_SWINT /* Disable software interrupt */
142                 | CPLD_CONTROL_OCMSK; /* Mask USB1 connection IRQ */
143         CPLD_CONTROL &= ~(0
144                           | CPLD_CONTROL_LCD_ENABLE     /* Disable LCD */
145                           | CPLD_CONTROL_WRLAN_NENABLE  /* Enable SMC91x */
146                 );
147 #endif
148
149 #if defined (CONFIG_MACH_LPD7A404)
150         CPLD_CONTROL &= ~(0
151                           | CPLD_CONTROL_WRLAN_NENABLE  /* Enable SMC91x */
152                 );
153 #endif
154
155         platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs));
156 #if defined (CONFIG_FB_ARMCLCD)
157         lh7a40x_clcd_init ();
158 #endif
159 }
160
161 static void lh7a40x_ack_cpld_irq (u32 irq)
162 {
163         /* CPLD doesn't have ack capability, but some devices may */
164
165 #if defined (CPLD_INTMASK_TOUCH)
166         /* The touch control *must* mask the the interrupt because the
167          * interrupt bit is read by the driver to determine if the pen
168          * is still down. */
169         if (irq == IRQ_TOUCH)
170                 CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
171 #endif
172 }
173
174 static void lh7a40x_mask_cpld_irq (u32 irq)
175 {
176         switch (irq) {
177         case IRQ_LPD7A40X_ETH_INT:
178                 CPLD_INTERRUPTS |= CPLD_INTMASK_ETHERNET;
179                 break;
180 #if defined (IRQ_TOUCH)
181         case IRQ_TOUCH:
182                 CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
183                 break;
184 #endif
185         }
186 }
187
188 static void lh7a40x_unmask_cpld_irq (u32 irq)
189 {
190         switch (irq) {
191         case IRQ_LPD7A40X_ETH_INT:
192                 CPLD_INTERRUPTS &= ~CPLD_INTMASK_ETHERNET;
193                 break;
194 #if defined (IRQ_TOUCH)
195         case IRQ_TOUCH:
196                 CPLD_INTERRUPTS &= ~CPLD_INTMASK_TOUCH;
197                 break;
198 #endif
199         }
200 }
201
202 static struct irqchip lpd7a40x_cpld_chip = {
203         .ack    = lh7a40x_ack_cpld_irq,
204         .mask   = lh7a40x_mask_cpld_irq,
205         .unmask = lh7a40x_unmask_cpld_irq,
206 };
207
208 static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
209                                   struct pt_regs *regs)
210 {
211         unsigned int mask = CPLD_INTERRUPTS;
212
213         desc->chip->ack (irq);
214
215         if ((mask & (1<<0)) == 0)       /* WLAN */
216                 IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
217
218 #if defined (IRQ_TOUCH)
219         if ((mask & (1<<1)) == 0)       /* Touch */
220                 IRQ_DISPATCH (IRQ_TOUCH);
221 #endif
222
223         desc->chip->unmask (irq); /* Level-triggered need this */
224 }
225
226
227 void __init lh7a40x_init_board_irq (void)
228 {
229         int irq;
230
231                 /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
232                                  PF7 supports the CPLD.
233                    Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
234                                  PF3 supports the CPLD.
235                    (Some) LPD7A404 prerelease boards report a version
236                    number of 0x16, but we force an override since the
237                    hardware is of the newer variety.
238                 */
239
240         unsigned char cpld_version = CPLD_REVISION;
241         int pinCPLD = (cpld_version == 0x28) ? 7 : 3;
242
243 #if defined CONFIG_MACH_LPD7A404
244         cpld_version = 0x34;    /* Coerce LPD7A404 to RevB */
245 #endif
246
247                 /* First, configure user controlled GPIOF interrupts  */
248
249         GPIO_PFDD       &= ~0x0f; /* PF0-3 are inputs */
250         GPIO_INTTYPE1   &= ~0x0f; /* PF0-3 are level triggered */
251         GPIO_INTTYPE2   &= ~0x0f; /* PF0-3 are active low */
252         barrier ();
253         GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */
254
255                 /* Then, configure CPLD interrupt */
256
257                         /* Disable all CPLD interrupts */
258 #if defined (CONFIG_MACH_LPD7A400)
259         CPLD_INTERRUPTS = CPLD_INTMASK_TOUCH | CPLD_INTMASK_PEN
260                 | CPLD_INTMASK_ETHERNET;
261         /* *** FIXME: don't know why we need 7 and 4. 7 is way wrong
262                and 4 is uncefined. */
263         // (1<<7)|(1<<4)|(1<<3)|(1<<2);
264 #endif
265 #if defined (CONFIG_MACH_LPD7A404)
266         CPLD_INTERRUPTS = CPLD_INTMASK_ETHERNET;
267         /* *** FIXME: don't know why we need 6 and 5, neither is defined. */
268         // (1<<6)|(1<<5)|(1<<3);
269 #endif
270         GPIO_PFDD       &= ~(1 << pinCPLD); /* Make input */
271         GPIO_INTTYPE1   &= ~(1 << pinCPLD); /* Level triggered */
272         GPIO_INTTYPE2   &= ~(1 << pinCPLD); /* Active low */
273         barrier ();
274         GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */
275
276                 /* Cascade CPLD interrupts */
277
278         for (irq = IRQ_BOARD_START;
279              irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
280                 set_irq_chip (irq, &lpd7a40x_cpld_chip);
281                 set_irq_handler (irq, do_level_IRQ);
282                 set_irq_flags (irq, IRQF_VALID);
283         }
284
285         set_irq_chained_handler ((cpld_version == 0x28)
286                                  ? IRQ_CPLD_V28
287                                  : IRQ_CPLD_V34,
288                                  lpd7a40x_cpld_handler);
289 }
290
291 static struct map_desc lpd7a40x_io_desc[] __initdata = {
292         {
293                 .virtual        = IO_VIRT,
294                 .pfn            = __phys_to_pfn(IO_PHYS),
295                 .length         = IO_SIZE,
296                 .type           = MT_DEVICE
297         },
298         {       /* Mapping added to work around chip select problems */
299                 .virtual        = IOBARRIER_VIRT,
300                 .pfn            = __phys_to_pfn(IOBARRIER_PHYS),
301                 .length         = IOBARRIER_SIZE,
302                 .type           = MT_DEVICE
303         },
304         {
305                 .virtual        = CF_VIRT,
306                 .pfn            = __phys_to_pfn(CF_PHYS),
307                 .length         = CF_SIZE,
308                 .type           = MT_DEVICE
309         },
310         {
311                 .virtual        = CPLD02_VIRT,
312                 .pfn            = __phys_to_pfn(CPLD02_PHYS),
313                 .length         = CPLD02_SIZE,
314                 .type           = MT_DEVICE
315         },
316         {
317                 .virtual        = CPLD06_VIRT,
318                 .pfn            = __phys_to_pfn(CPLD06_PHYS),
319                 .length         = CPLD06_SIZE,
320                 .type           = MT_DEVICE
321         },
322         {
323                 .virtual        = CPLD08_VIRT,
324                 .pfn            = __phys_to_pfn(CPLD08_PHYS),
325                 .length         = CPLD08_SIZE,
326                 .type           = MT_DEVICE
327         },
328         {
329                 .virtual        = CPLD08_VIRT,
330                 .pfn            = __phys_to_pfn(CPLD08_PHYS),
331                 .length         = CPLD08_SIZE,
332                 .type           = MT_DEVICE
333         },
334         {
335                 .virtual        = CPLD0A_VIRT,
336                 .pfn            = __phys_to_pfn(CPLD0A_PHYS),
337                 .length         = CPLD0A_SIZE,
338                 .type           = MT_DEVICE
339         },
340         {
341                 .virtual        = CPLD0C_VIRT,
342                 .pfn            = __phys_to_pfn(CPLD0C_PHYS),
343                 .length         = CPLD0C_SIZE,
344                 .type           = MT_DEVICE
345         },
346         {
347                 .virtual        = CPLD0E_VIRT,
348                 .pfn            = __phys_to_pfn(CPLD0E_PHYS),
349                 .length         = CPLD0E_SIZE,
350                 .type           = MT_DEVICE
351         },
352         {
353                 .virtual        = CPLD10_VIRT,
354                 .pfn            = __phys_to_pfn(CPLD10_PHYS),
355                 .length         = CPLD10_SIZE,
356                 .type           = MT_DEVICE
357         },
358         {
359                 .virtual        = CPLD12_VIRT,
360                 .pfn            = __phys_to_pfn(CPLD12_PHYS),
361                 .length         = CPLD12_SIZE,
362                 .type           = MT_DEVICE
363         },
364         {
365                 .virtual        = CPLD14_VIRT,
366                 .pfn            = __phys_to_pfn(CPLD14_PHYS),
367                 .length         = CPLD14_SIZE,
368                 .type           = MT_DEVICE
369         },
370         {
371                 .virtual        = CPLD16_VIRT,
372                 .pfn            = __phys_to_pfn(CPLD16_PHYS),
373                 .length         = CPLD16_SIZE,
374                 .type           = MT_DEVICE
375         },
376         {
377                 .virtual        = CPLD18_VIRT,
378                 .pfn            = __phys_to_pfn(CPLD18_PHYS),
379                 .length         = CPLD18_SIZE,
380                 .type           = MT_DEVICE
381         },
382         {
383                 .virtual        = CPLD1A_VIRT,
384                 .pfn            = __phys_to_pfn(CPLD1A_PHYS),
385                 .length         = CPLD1A_SIZE,
386                 .type           = MT_DEVICE
387         },
388 };
389
390 void __init
391 lpd7a40x_map_io(void)
392 {
393         iotable_init (lpd7a40x_io_desc, ARRAY_SIZE (lpd7a40x_io_desc));
394 }
395
396 #ifdef CONFIG_MACH_LPD7A400
397
398 MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
399         /* Maintainer: Marc Singer */
400         .phys_io        = 0x80000000,
401         .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
402         .boot_params    = 0xc0000100,
403         .map_io         = lpd7a40x_map_io,
404         .init_irq       = lh7a400_init_irq,
405         .timer          = &lh7a40x_timer,
406         .init_machine   = lpd7a40x_init,
407 MACHINE_END
408
409 #endif
410
411 #ifdef CONFIG_MACH_LPD7A404
412
413 MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
414         /* Maintainer: Marc Singer */
415         .phys_io        = 0x80000000,
416         .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
417         .boot_params    = 0xc0000100,
418         .map_io         = lpd7a40x_map_io,
419         .init_irq       = lh7a404_init_irq,
420         .timer          = &lh7a40x_timer,
421         .init_machine   = lpd7a40x_init,
422 MACHINE_END
423
424 #endif