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