]> git.neil.brown.name Git - history.git/commitdiff
[ARM] Update SA1111 core and related drivers for LDM.
authorRussell King <rmk@flint.arm.linux.org.uk>
Mon, 30 Sep 2002 21:23:43 +0000 (22:23 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Mon, 30 Sep 2002 21:23:43 +0000 (22:23 +0100)
This cset updates the SA1111 core, PCMCIA, OHCI and keyboard drivers,
allowing them to take advantage of the Linux device manager code;
this implements initial suspend/resume support for the SA1111 in the
core.  Many existing drivers currently rely on the old PM-based
interface for suspend/resume support.

16 files changed:
arch/arm/mach-sa1100/sa1111.c
drivers/input/serio/sa1111ps2.c
drivers/pcmcia/Config.in
drivers/pcmcia/Makefile
drivers/pcmcia/sa1100_adsbitsy.c
drivers/pcmcia/sa1100_badge4.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/sa1100_graphicsmaster.c
drivers/pcmcia/sa1100_jornada720.c
drivers/pcmcia/sa1100_neponset.c
drivers/pcmcia/sa1100_pfs168.c
drivers/pcmcia/sa1100_system3.c
drivers/pcmcia/sa1100_xp860.c
drivers/pcmcia/sa1111_generic.c
drivers/usb/host/ohci-sa1111.c
include/asm-arm/hardware/sa1111.h

index 244dfdc35c591785d94c3eb6544e652bc374944b..8d796a67622a790184258e3ab9b286bc00693574 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 
 #include <asm/hardware/sa1111.h>
 
-#include "sa1111.h"
+/*
+ * We keep the following data for the overall SA1111.  Note that the
+ * struct device and struct resource are "fake"; they should be supplied
+ * by the bus above us.  However, in the interests of getting all SA1111
+ * drivers converted over to the device model, we provide this as an
+ * anchor point for all the other drivers.
+ */
+struct sa1111 {
+       struct device   dev;
+       struct resource res;
+       int             irq;
+       spinlock_t      lock;
+       void            *base;
+};
+
+/*
+ * We _really_ need to eliminate this.  Its only users
+ * are the PWM and DMA checking code.
+ */
+static struct sa1111 *g_sa1111;
+
+static struct sa1111_dev usb_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [USB Controller]",
+       },
+       .skpcr_mask     = SKPCR_UCLKEN,
+       .devid          = SA1111_DEVID_USB,
+       .irq = {
+               USBPWR
+               NIRQHCIM,
+               HCIBUFFACC,
+               HCIRMTWKP,
+               NHCIMFCIR,
+               USB_PORT_RESUME
+       },
+};
+
+static struct sa1111_dev sac_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [Audio Controller]",
+       },
+       .skpcr_mask     = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+       .devid          = SA1111_DEVID_SAC,
+       .irq = {
+               AUDXMTDMADONEA,
+               AUDXMTDMADONEB,
+               AUDRCVDMADONEA,
+               AUDRCVDMADONEB
+       },
+};
+
+static struct sa1111_dev ssp_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [SSP Controller]",
+       },
+       .skpcr_mask     = SKPCR_SCLKEN,
+       .devid          = SA1111_DEVID_SSP,
+};
+
+static struct sa1111_dev kbd_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [PS2]",
+       },
+       .skpcr_mask     = SKPCR_PTCLKEN,
+       .devid          = SA1111_DEVID_PS2,
+       .irq = {
+               IRQ_TPRXINT,
+               IRQ_TPTXINT
+       },
+};
+
+static struct sa1111_dev mse_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [PS2]",
+       },
+       .skpcr_mask     = SKPCR_PMCLKEN,
+       .devid          = SA1111_DEVID_PS2,
+       .irq = {
+               IRQ_MSRXINT,
+               IRQ_MSTXINT
+       },
+};
+
+static struct sa1111_dev int_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [Interrupt Controller]",
+       },
+       .skpcr_mask     = 0,
+       .devid          = SA1111_DEVID_INT,
+};
 
-struct sa1111_device *sa1111;
+static struct sa1111_dev pcmcia_dev = {
+       .dev = {
+               .name   = "Intel Corporation SA1111 [PCMCIA Controller]",
+       },
+       .skpcr_mask     = 0,
+       .devid          = SA1111_DEVID_PCMCIA,
+       .irq = {
+               S0_READY_NINT,
+               S0_CD_VALID,
+               S0_BVD1_STSCHG,
+               S1_READY_NINT,
+               S1_CD_VALID,
+               S1_BVD1_STSCHG,
+       },
+};
 
-EXPORT_SYMBOL(sa1111);
+static struct sa1111_dev *devs[] = {
+       &usb_dev,
+       &sac_dev,
+       &ssp_dev,
+       &kbd_dev,
+       &mse_dev,
+       &int_dev,
+       &pcmcia_dev,
+};
+
+static unsigned int dev_offset[] = {
+       SA1111_USB,
+       0x0600,
+       0x0800,
+       SA1111_KBD,
+       SA1111_MSE,
+       SA1111_INTC,
+       0x1800,
+};
 
 /*
  * SA1111 interrupt support.  Since clearing an IRQ while there are
@@ -205,27 +327,33 @@ static struct irqchip sa1111_high_chip = {
        .type           = sa1111_type_highirq,
 };
 
-static void __init sa1111_init_irq(int irq_nr)
+static void __init sa1111_init_irq(struct sa1111_dev *sadev)
 {
        unsigned int irq;
 
-       request_mem_region(_INTTEST0, 512, "irqs");
+       /*
+        * We're guaranteed that this region hasn't been taken.
+        */
+       request_mem_region(sadev->res.start, 512, "irqs");
 
        /* disable all IRQs */
-       INTEN0 = 0;
-       INTEN1 = 0;
+       sa1111_writel(0, sadev->mapbase + SA1111_INTEN0);
+       sa1111_writel(0, sadev->mapbase + SA1111_INTEN1);
+       sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0);
+       sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1);
 
        /*
         * detect on rising edge.  Note: Feb 2001 Errata for SA1111
         * specifies that S0ReadyInt and S1ReadyInt should be '1'.
         */
-       INTPOL0 = 0;
-       INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) |
-                 SA1111_IRQMASK_HI(S1_READY_NINT);
+       sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0);
+       sa1111_writel(SA1111_IRQMASK_HI(S0_READY_NINT) |
+                     SA1111_IRQMASK_HI(S1_READY_NINT),
+                     sadev->mapbase + SA1111_INTPOL1);
 
        /* clear all IRQs */
-       INTSTATCLR0 = ~0;
-       INTSTATCLR1 = ~0;
+       sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0);
+       sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1);
 
        for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
                set_irq_chip(irq, &sa1111_low_chip);
@@ -242,24 +370,11 @@ static void __init sa1111_init_irq(int irq_nr)
        /*
         * Register SA1111 interrupt
         */
-       set_irq_type(irq_nr, IRQT_RISING);
-       set_irq_chained_handler(irq_nr, sa1111_irq_handler);
+       set_irq_type(sadev->irq[0], IRQT_RISING);
+       set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler);
 }
 
-static int sa1111_suspend(struct device *dev, u32 state, u32 level)
-{
-       return 0;
-}
-
-static int sa1111_resume(struct device *dev, u32 level)
-{
-       return 0;
-}
-
-static struct device_driver sa1111_device_driver = {
-       .suspend        = sa1111_suspend,
-       .resume         = sa1111_resume,
-};
+static struct device_driver sa1111_device_driver;
 
 /**
  *     sa1111_probe - probe for a single SA1111 chip.
@@ -274,30 +389,38 @@ static struct device_driver sa1111_device_driver = {
  *     %0              successful.
  */
 static int __init
-sa1111_probe(struct device *parent, unsigned long phys_addr)
+sa1111_probe(unsigned long phys_addr, int irq)
 {
-       struct sa1111_device *sa;
+       struct sa1111 *sachip;
        unsigned long id;
-       int ret = -ENODEV;
+       unsigned int has_devs;
+       int i, ret = -ENODEV;
 
-       sa = kmalloc(sizeof(struct sa1111_device), GFP_KERNEL);
-       if (!sa)
+       sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL);
+       if (!sachip)
                return -ENOMEM;
 
-       memset(sa, 0, sizeof(struct sa1111_device));
+       memset(sachip, 0, sizeof(struct sa1111));
+
+       spin_lock_init(&sachip->lock);
+
+       strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name));
+       snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr);
+       sachip->dev.driver = &sa1111_device_driver;
+       sachip->dev.driver_data = sachip;
 
-       sa->resource.name  = "SA1111";
-       sa->resource.start = phys_addr;
-       sa->resource.end   = phys_addr + 0x2000;
+       sachip->res.name  = sachip->dev.name;
+       sachip->res.start = phys_addr;
+       sachip->res.end   = phys_addr + 0x2000;
+       sachip->irq = irq;
 
-       if (request_resource(&iomem_resource, &sa->resource)) {
+       if (request_resource(&iomem_resource, &sachip->res)) {
                ret = -EBUSY;
                goto out;
        }
 
-       /* eventually ioremap... */
-       sa->base = (void *)0xf4000000;
-       if (!sa->base) {
+       sachip->base = ioremap(phys_addr, PAGE_SIZE * 2);
+       if (!sachip->base) {
                ret = -ENOMEM;
                goto release;
        }
@@ -305,7 +428,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
        /*
         * Probe for the chip.  Only touch the SBI registers.
         */
-       id = sa1111_readl(sa->base + SA1111_SKID);
+       id = sa1111_readl(sachip->base + SA1111_SKID);
        if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
                printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
                ret = -ENODEV;
@@ -315,12 +438,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
        /*
         * We found the chip.
         */
-       strcpy(sa->dev.name, "SA1111");
-       sprintf(sa->dev.bus_id, "%8.8lx", phys_addr);
-       sa->dev.parent = parent;
-       sa->dev.driver = &sa1111_device_driver;
-
-       ret = device_register(&sa->dev);
+       ret = register_sys_device(&sachip->dev);
        if (ret)
                printk("sa1111 device_register failed: %d\n", ret);
 
@@ -328,19 +446,64 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
                "silicon revision %lx, metal revision %lx\n",
                (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
 
-       sa1111 = sa;
+       g_sa1111 = sachip;
+
+       has_devs = ~0;
+       if (machine_is_assabet() || machine_is_jornada720() ||
+           machine_is_badge4())
+               has_devs &= ~(1 << 4);
+       else
+               has_devs &= ~(1 << 1);
+
+       for (i = 0; i < ARRAY_SIZE(devs); i++) {
+               if (!(has_devs & (1 << i)))
+                       continue;
+
+               snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id),
+                        "%4.4x", dev_offset[i]);
+
+               devs[i]->dev.parent = &sachip->dev;
+               devs[i]->dev.bus    = &sa1111_bus_type;
+               devs[i]->res.start  = sachip->res.start + dev_offset[i];
+               devs[i]->res.end    = devs[i]->res.start + 511;
+               devs[i]->res.name   = devs[i]->dev.name;
+               devs[i]->res.flags  = IORESOURCE_MEM;
+               devs[i]->mapbase    = sachip->base + dev_offset[i];
+
+               if (request_resource(&sachip->res, &devs[i]->res)) {
+                       printk("SA1111: failed to allocate resource for %s\n",
+                               devs[i]->res.name);
+                       continue;
+               }
+
+               device_register(&devs[i]->dev);
+       }
 
        return 0;
 
  unmap:
-//     iounmap(sa->base);
+       iounmap(sachip->base);
  release:
-       release_resource(&sa->resource);
+       release_resource(&sachip->res);
  out:
-       kfree(sa);
+       kfree(sachip);
        return ret;
 }
 
+static void __sa1111_remove(struct sa1111 *sachip)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(devs); i++) {
+               put_device(&devs[i]->dev);
+               release_resource(&devs[i]->res);
+       }
+
+       iounmap(sachip->base);
+       release_resource(&sachip->res);
+       kfree(sachip);
+}
+
 /*
  * Bring the SA1111 out of reset.  This requires a set procedure:
  *  1. nRESET asserted (by hardware)
@@ -355,12 +518,11 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
  *   SBI_SMCR
  *   SBI_SKID
  */
-void sa1111_wake(void)
+static void sa1111_wake(struct sa1111 *sachip)
 {
-       struct sa1111_device *sa = sa1111;
        unsigned long flags, r;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&sachip->lock, flags);
 
        /*
         * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
@@ -373,11 +535,11 @@ void sa1111_wake(void)
        /*
         * Turn VCO on, and disable PLL Bypass.
         */
-       r = sa1111_readl(sa->base + SA1111_SKCR);
+       r = sa1111_readl(sachip->base + SA1111_SKCR);
        r &= ~SKCR_VCO_OFF;
-       sa1111_writel(r, sa->base + SA1111_SKCR);
+       sa1111_writel(r, sachip->base + SA1111_SKCR);
        r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
-       sa1111_writel(r, sa->base + SA1111_SKCR);
+       sa1111_writel(r, sachip->base + SA1111_SKCR);
 
        /*
         * Wait lock time.  SA1111 manual _doesn't_
@@ -389,7 +551,7 @@ void sa1111_wake(void)
         * Enable RCLK.  We also ensure that RDYEN is set.
         */
        r |= SKCR_RCLKEN | SKCR_RDYEN;
-       sa1111_writel(r, sa->base + SA1111_SKCR);
+       sa1111_writel(r, sachip->base + SA1111_SKCR);
 
        /*
         * Wait 14 RCLK cycles for the chip to finish coming out
@@ -400,76 +562,31 @@ void sa1111_wake(void)
        /*
         * Ensure all clocks are initially off.
         */
-       sa1111_writel(0, sa->base + SA1111_SKPCR);
+       sa1111_writel(0, sachip->base + SA1111_SKPCR);
 
-       local_irq_restore(flags);
-}
-
-void sa1111_doze(void)
-{
-       struct sa1111_device *sa = sa1111;
-       unsigned long flags;
-       unsigned int val;
-
-       local_irq_save(flags);
-
-       if (sa1111_readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
-               local_irq_restore(flags);
-               printk("SA1111 doze mode refused\n");
-               return;
-       }
-
-       val = sa1111_readl(sa->base + SA1111_SKCR);
-       sa1111_writel(val & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&sachip->lock, flags);
 }
 
 /*
  * Configure the SA1111 shared memory controller.
  */
-void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency)
+void
+sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
+                    unsigned int cas_latency)
 {
-       struct sa1111_device *sa = sa1111;
        unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
 
        if (cas_latency == 3)
                smcr |= SMCR_CLAT;
 
-       sa1111_writel(smcr, sa->base + SA1111_SMCR);
-}
-
-EXPORT_SYMBOL(sa1111_wake);
-EXPORT_SYMBOL(sa1111_doze);
-
-void sa1111_enable_device(unsigned int mask)
-{
-       struct sa1111_device *sa = sa1111;
-       unsigned int val;
-
-       preempt_disable();
-       val = sa1111_readl(sa->base + SA1111_SKPCR);
-       sa1111_writel(val | mask, sa->base + SA1111_SKPCR);
-       preempt_enable();
+       sa1111_writel(smcr, sachip->base + SA1111_SMCR);
 }
 
-void sa1111_disable_device(unsigned int mask)
-{
-       struct sa1111_device *sa = sa1111;
-       unsigned int val;
-
-       preempt_disable();
-       val = sa1111_readl(sa->base + SA1111_SKPCR);
-       sa1111_writel(val & ~mask, sa->base + SA1111_SKPCR);
-       preempt_enable();
-}
-
-EXPORT_SYMBOL(sa1111_enable_device);
-EXPORT_SYMBOL(sa1111_disable_device);
-
-/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
  * Chip Specification Update" (June 2000), erratum #7, there is a
- * significant bug in Serial Audio Controller DMA. If the SAC is
- * accessing a region of memory above 1MB relative to the bank base,
+ * significant bug in the SA1111 SDRAM shared memory controller.  If
+ * an access to a region of memory above 1MB relative to the bank base,
  * it is important that address bit 10 _NOT_ be asserted. Depending
  * on the configuration of the RAM, bit 10 may correspond to one
  * of several different (processor-relative) address bits.
@@ -479,7 +596,9 @@ EXPORT_SYMBOL(sa1111_disable_device);
  */
 int sa1111_check_dma_bug(dma_addr_t addr)
 {
-       unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr);
+       struct sa1111 *sachip = g_sa1111;
+       unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
+       unsigned int smcr;
 
        /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
         * User's Guide" mentions that jumpers R51 and R52 control the
@@ -494,9 +613,10 @@ int sa1111_check_dma_bug(dma_addr_t addr)
         * above the start of the target bank:
         */
        if (physaddr<(1<<20))
-               return 0;
+               return 0;
 
-       switch (FExtr(SBI_SMCR, SMCR_DRAC)) {
+       smcr = sa1111_readl(sachip->base + SA1111_SMCR);
+       switch (FExtr(smcr, SMCR_DRAC)) {
        case 01: /* 10 row + bank address bits, A<20> must not be set */
                if (physaddr & (1<<20))
                        return -1;
@@ -523,27 +643,26 @@ int sa1111_check_dma_bug(dma_addr_t addr)
                break;
        default:
                printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
-                      __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC));
+                      __FUNCTION__, FExtr(smcr, SMCR_DRAC));
                return -1;
        }
 
        return 0;
 }
 
-EXPORT_SYMBOL(sa1111_check_dma_bug);
-
 int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
 {
+       unsigned int val;
        int ret;
 
-       ret = sa1111_probe(parent, phys);
+       ret = sa1111_probe(phys, irq);
        if (ret < 0)
                return ret;
 
        /*
         * We found it.  Wake the chip up.
         */
-       sa1111_wake();
+       sa1111_wake(g_sa1111);
 
        /*
         * The SDRAM configuration of the SA1110 and the SA1111 must
@@ -552,7 +671,7 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
         * MBGNT signal, so we must have called sa1110_mb_disable()
         * beforehand.
         */
-       sa1111_configure_smc(1,
+       sa1111_configure_smc(g_sa1111, 1,
                             FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
                             FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
 
@@ -560,7 +679,8 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
         * We only need to turn on DCLK whenever we want to use the
         * DMA.  It can otherwise be held firmly in the off position.
         */
-       sa1111_enable_device(SKPCR_DCLKEN);
+       val = sa1111_readl(g_sa1111->base + SA1111_SKPCR);
+       sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR);
 
        /*
         * Enable the SA1110 memory bus request and grant signals.
@@ -570,7 +690,341 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
        /*
         * Initialise SA1111 IRQs
         */
-       sa1111_init_irq(irq);
+       int_dev.irq[0] = irq;
+       sa1111_init_irq(&int_dev);
+
+       return 0;
+}
+
+struct sa1111_save_data {
+       unsigned int    skcr;
+       unsigned int    skpcr;
+       unsigned int    skcdr;
+       unsigned char   skaud;
+       unsigned char   skpwm0;
+       unsigned char   skpwm1;
+
+       /*
+        * Interrupt controller
+        */
+       unsigned int    intpol0;
+       unsigned int    intpol1;
+       unsigned int    inten0;
+       unsigned int    inten1;
+       unsigned int    wakepol0;
+       unsigned int    wakepol1;
+       unsigned int    wakeen0;
+       unsigned int    wakeen1;
+};
+
+static int sa1111_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct sa1111 *sachip = dev->driver_data;
+       unsigned long flags;
+       char *base;
+
+       /*
+        * Save state.
+        */
+       if (level == SUSPEND_SAVE_STATE ||
+           level == SUSPEND_DISABLE ||
+           level == SUSPEND_POWER_DOWN) {
+               struct sa1111_save_data *save;
+
+               if (!dev->saved_state)
+                       dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
+               if (!dev->saved_state)
+                       return -ENOMEM;
+
+               save = (struct sa1111_save_data *)dev->saved_state;
+
+               spin_lock_irqsave(&sachip->lock, flags);
+               base = sachip->base;
+               save->skcr     = sa1111_readl(base + SA1111_SKCR);
+               save->skpcr    = sa1111_readl(base + SA1111_SKPCR);
+               save->skcdr    = sa1111_readl(base + SA1111_SKCDR);
+               save->skaud    = sa1111_readl(base + SA1111_SKAUD);
+               save->skpwm0   = sa1111_readl(base + SA1111_SKPWM0);
+               save->skpwm1   = sa1111_readl(base + SA1111_SKPWM1);
+
+               base = sachip->base + SA1111_INTC;
+               save->intpol0  = sa1111_readl(base + SA1111_INTPOL0);
+               save->intpol1  = sa1111_readl(base + SA1111_INTPOL1);
+               save->inten0   = sa1111_readl(base + SA1111_INTEN0);
+               save->inten1   = sa1111_readl(base + SA1111_INTEN1);
+               save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0);
+               save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
+               save->wakeen0  = sa1111_readl(base + SA1111_WAKEEN0);
+               save->wakeen1  = sa1111_readl(base + SA1111_WAKEEN1);
+               spin_unlock_irqrestore(&sachip->lock, flags);
+       }
+
+       /*
+        * Disable.
+        */
+       if (level == SUSPEND_DISABLE && state == 4) {
+               unsigned int val;
+
+               spin_lock_irqsave(&sachip->lock, flags);
+               base = sachip->base;
+
+               sa1111_writel(0, base + SA1111_SKPWM0);
+               sa1111_writel(0, base + SA1111_SKPWM1);
+               val = sa1111_readl(base + SA1111_SKCR);
+               sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
+
+               spin_unlock_irqrestore(&sachip->lock, flags);
+       }
+
+       return 0;
+}
+
+/*
+ *     sa1111_resume - Restore the SA1111 device state.
+ *     @dev: device to restore
+ *     @level: resume level
+ *
+ *     Restore the general state of the SA1111; clock control and
+ *     interrupt controller.  Other parts of the SA1111 must be
+ *     restored by their respective drivers, and must be called
+ *     via LDM after this function.
+ */
+static int sa1111_resume(struct device *dev, u32 level)
+{
+       struct sa1111 *sachip = dev->driver_data;
+       struct sa1111_save_data *save;
+       unsigned long flags, id;
+       char *base;
+
+       if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
+               return 0;
+
+       save = (struct sa1111_save_data *)dev->saved_state;
+       if (!save)
+               return 0;
+
+       dev->saved_state = NULL;
+
+       /*
+        * Ensure that the SA1111 is still here.
+        */
+       id = sa1111_readl(sachip->base + SA1111_SKID);
+       if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
+               __sa1111_remove(sachip);
+               kfree(save);
+               return 0;
+       }
+
+       spin_lock_irqsave(&sachip->lock, flags);
+       sa1111_wake(sachip);
+
+       base = sachip->base;
+       sa1111_writel(save->skcr,     base + SA1111_SKCR);
+       sa1111_writel(save->skpcr,    base + SA1111_SKPCR);
+       sa1111_writel(save->skcdr,    base + SA1111_SKCDR);
+       sa1111_writel(save->skaud,    base + SA1111_SKAUD);
+       sa1111_writel(save->skpwm0,   base + SA1111_SKPWM0);
+       sa1111_writel(save->skpwm1,   base + SA1111_SKPWM1);
+
+       base = sachip->base + SA1111_INTC;
+       sa1111_writel(save->intpol0,  base + SA1111_INTPOL0);
+       sa1111_writel(save->intpol1,  base + SA1111_INTPOL1);
+       sa1111_writel(save->inten0,   base + SA1111_INTEN0);
+       sa1111_writel(save->inten1,   base + SA1111_INTEN1);
+       sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
+       sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
+       sa1111_writel(save->wakeen0,  base + SA1111_WAKEEN0);
+       sa1111_writel(save->wakeen1,  base + SA1111_WAKEEN1);
+       spin_unlock_irqrestore(&sachip->lock, flags);
+
+       kfree(save);
 
        return 0;
 }
+
+static struct device_driver sa1111_device_driver = {
+       .suspend        = sa1111_suspend,
+       .resume         = sa1111_resume,
+};
+
+/*
+ *     Get the parent device driver (us) structure
+ *     from a child function device
+ */
+static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
+{
+       return (struct sa1111 *)sadev->dev.parent->driver_data;
+}
+
+/*
+ * The bits in the opdiv field are non-linear.
+ */
+static unsigned char opdiv_table[] = { 1, 4, 2, 8 };
+
+static unsigned int __sa1111_pll_clock(struct sa1111 *sachip)
+{
+       unsigned int skcdr, fbdiv, ipdiv, opdiv;
+
+       skcdr = sa1111_readl(sachip->base + SA1111_SKCDR);
+
+       fbdiv = (skcdr & 0x007f) + 2;
+       ipdiv = ((skcdr & 0x0f80) >> 7) + 2;
+       opdiv = opdiv_table[(skcdr & 0x3000) >> 12];
+
+       return 3686400 * fbdiv / (ipdiv * opdiv);
+}
+
+/**
+ *     sa1111_pll_clock - return the current PLL clock frequency.
+ *     @sadev: SA1111 function block
+ *
+ *     BUG: we should look at SKCR.  We also blindly believe that
+ *     the chip is being fed with the 3.6864MHz clock.
+ *
+ *     Returns the PLL clock in Hz.
+ */
+unsigned int sa1111_pll_clock(struct sa1111_dev *sadev)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+
+       return __sa1111_pll_clock(sachip);
+}
+
+/**
+ *     sa1111_select_audio_mode - select I2S or AC link mode
+ *     @sadev: SA1111 function block
+ *     @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S
+ *
+ *     Frob the SKCR to select AC Link mode or I2S mode for
+ *     the audio block.
+ */
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&sachip->lock, flags);
+
+       val = sa1111_readl(sachip->base + SA1111_SKCR);
+       if (mode == SA1111_AUDIO_I2S) {
+               val &= ~SKCR_SELAC;
+       } else {
+               val |= SKCR_SELAC;
+       }
+       sa1111_writel(val, sachip->base + SA1111_SKCR);
+
+       spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/**
+ *     sa1111_set_audio_rate - set the audio sample rate
+ *     @sadev: SA1111 SAC function block
+ *     @rate: sample rate to select
+ */
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+       unsigned int div;
+
+       if (sadev->devid != SA1111_DEVID_SAC)
+               return -EINVAL;
+
+       div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate;
+       if (div == 0)
+               div = 1;
+       if (div > 128)
+               div = 128;
+
+       sa1111_writel(div - 1, sachip->base + SA1111_SKAUD);
+
+       return 0;
+}
+
+/**
+ *     sa1111_get_audio_rate - get the audio sample rate
+ *     @sadev: SA1111 SAC function block device
+ */
+int sa1111_get_audio_rate(struct sa1111_dev *sadev)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+       unsigned long div;
+
+       if (sadev->devid != SA1111_DEVID_SAC)
+               return -EINVAL;
+
+       div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1;
+
+       return __sa1111_pll_clock(sachip) / (256 * div);
+}
+
+/*
+ * Individual device operations.
+ */
+
+/**
+ *     sa1111_enable_device - enable an on-chip SA1111 function block
+ *     @sadev: SA1111 function block device to enable
+ */
+void sa1111_enable_device(struct sa1111_dev *sadev)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&sachip->lock, flags);
+       val = sa1111_readl(sachip->base + SA1111_SKPCR);
+       sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+       spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/**
+ *     sa1111_disable_device - disable an on-chip SA1111 function block
+ *     @sadev: SA1111 function block device to disable
+ */
+void sa1111_disable_device(struct sa1111_dev *sadev)
+{
+       struct sa1111 *sachip = sa1111_chip_driver(sadev);
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&sachip->lock, flags);
+       val = sa1111_readl(sachip->base + SA1111_SKPCR);
+       sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+       spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/*
+ *     SA1111 "Register Access Bus."
+ *
+ *     We model this as a regular bus type, and hang devices directly
+ *     off this.
+ */
+static int sa1111_match(struct device *_dev, struct device_driver *_drv)
+{
+       struct sa1111_dev *dev = SA1111_DEV(_dev);
+       struct sa1111_driver *drv = SA1111_DRV(_drv);
+
+       return dev->devid == drv->devid;
+}
+
+struct bus_type sa1111_bus_type = {
+       .name   = "RAB",
+       .match  = sa1111_match,
+};
+
+static int sa1111_rab_bus_init(void)
+{
+       return bus_register(&sa1111_bus_type);
+}
+
+postcore_initcall(sa1111_rab_bus_init);
+
+EXPORT_SYMBOL(sa1111_check_dma_bug);
+EXPORT_SYMBOL(sa1111_select_audio_mode);
+EXPORT_SYMBOL(sa1111_set_audio_rate);
+EXPORT_SYMBOL(sa1111_get_audio_rate);
+EXPORT_SYMBOL(sa1111_enable_device);
+EXPORT_SYMBOL(sa1111_disable_device);
+EXPORT_SYMBOL(sa1111_pll_clock);
+EXPORT_SYMBOL(sa1111_bus_type);
index da568810512865ed2d2fade7fedc5758e2423840..502d3c90b86428d150e53b57abc0ea590c664e69 100644 (file)
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 
-#include <asm/hardware/sa1111.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
+#include <asm/hardware/sa1111.h>
+
 extern struct pt_regs *kbd_pt_regs;
 
 struct ps2if {
-       struct serio    io;
-       struct resource *res;
-       unsigned long   base;
-       unsigned int    irq;
-       unsigned int    skpcr_mask;
+       struct serio            io;
+       struct sa1111_dev       *dev;
+       unsigned long           base;
+       unsigned int            open;
+       spinlock_t              lock;
+       unsigned int            head;
+       unsigned int            tail;
+       unsigned char           buf[4];
 };
 
 /*
@@ -36,104 +42,150 @@ struct ps2if {
  * at the most one, but we loop for safety.  If there was a
  * framing error, we have to manually clear the status.
  */
-static void ps2_int(int irq, void *dev_id, struct pt_regs *regs)
+static void ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct ps2if *sa = dev_id;
+       struct ps2if *ps2if = dev_id;
        unsigned int scancode, flag, status;
 
        kbd_pt_regs = regs;
 
-       status = sa1111_readl(sa->base + SA1111_PS2STAT);
+       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
        while (status & PS2STAT_RXF) {
                if (status & PS2STAT_STP)
-                       sa1111_writel(PS2STAT_STP, sa->base + SA1111_PS2STAT);
+                       sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
 
                flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
                       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
-               scancode = sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff;
+               scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
 
                if (hweight8(scancode) & 1)
                        flag ^= SERIO_PARITY;
 
-               serio_interrupt(&sa->io, scancode, flag);
+               serio_interrupt(&ps2if->io, scancode, flag);
 
-                       status = sa1111_readl(sa->base + SA1111_PS2STAT);
+                       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
         }
 }
 
+/*
+ * Completion of ps2 write
+ */
+static void ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct ps2if *ps2if = dev_id;
+       unsigned int status;
+
+       spin_lock(&ps2if->lock);
+       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       if (ps2if->head == ps2if->tail) {
+               disable_irq(irq);
+               /* done */
+       } else if (status & PS2STAT_TXE) {
+               sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+               ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
+       }
+       spin_unlock(&ps2if->lock);
+}
+
 /*
  * Write a byte to the PS2 port.  We have to wait for the
  * port to indicate that the transmitter is empty.
  */
 static int ps2_write(struct serio *io, unsigned char val)
 {
-       struct ps2if *sa = io->driver;
-       unsigned int timeleft = 10000; /* timeout in 100ms */
+       struct ps2if *ps2if = io->driver;
+       unsigned long flags;
+       unsigned int head;
 
-       while ((sa1111_readl(sa->base + SA1111_PS2STAT) & PS2STAT_TXE) == 0 &&
-              timeleft--)
-               udelay(10);
+       spin_lock_irqsave(&ps2if->lock, flags);
 
-       if (timeleft)
-               sa1111_writel(val, sa->base + SA1111_PS2DATA);
+       /*
+        * If the TX register is empty, we can go straight out.
+        */
+       if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
+               sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
+       } else {
+               if (ps2if->head == ps2if->tail)
+                       enable_irq(ps2if->dev->irq[1]);
+               head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
+               if (head != ps2if->tail) {
+                       ps2if->buf[ps2if->head] = val;
+                       ps2if->head = head;
+               }
+       }
 
-       return timeleft ? 0 : SERIO_TIMEOUT;
+       spin_unlock_irqrestore(&ps2if->lock, flags);
+       return 0;
 }
 
 static int ps2_open(struct serio *io)
 {
-       struct ps2if *sa = io->driver;
+       struct ps2if *ps2if = io->driver;
        int ret;
 
-       sa1111_enable_device(sa->skpcr_mask);
+       sa1111_enable_device(ps2if->dev);
 
-       ret = request_irq(sa->irq, ps2_int, 0, "ps2", sa);
+       ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
+                         SA1111_DRIVER_NAME(ps2if->dev), ps2if);
        if (ret) {
                printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
-                       sa->irq, ret);
+                       ps2if->dev->irq[0], ret);
                return ret;
        }
 
-       sa1111_writel(PS2CR_ENA, sa->base + SA1111_PS2CR);
+       ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
+                         SA1111_DRIVER_NAME(ps2if->dev), ps2if);
+       if (ret) {
+               printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
+                       ps2if->dev->irq[1], ret);
+               free_irq(ps2if->dev->irq[0], ps2if);
+               return ret;
+       }
 
+       ps2if->open = 1;
+
+       sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
        return 0;
 }
 
 static void ps2_close(struct serio *io)
 {
-       struct ps2if *sa = io->driver;
+       struct ps2if *ps2if = io->driver;
+
+       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
 
-       sa1111_writel(0, sa->base + SA1111_PS2CR);
+       ps2if->open = 0;
 
-       free_irq(sa->irq, sa);
+       free_irq(ps2if->dev->irq[1], ps2if);
+       free_irq(ps2if->dev->irq[0], ps2if);
 
-       sa1111_disable_device(sa->skpcr_mask);
+       sa1111_disable_device(ps2if->dev);
 }
 
 /*
  * Clear the input buffer.
  */
-static void __init ps2_clear_input(struct ps2if *sa)
+static void __init ps2_clear_input(struct ps2if *ps2if)
 {
        int maxread = 100;
 
        while (maxread--) {
-               if ((sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff) == 0xff)
+               if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
                        break;
        }
 }
 
 static inline unsigned int
-ps2_test_one(struct ps2if *sa, unsigned int mask)
+ps2_test_one(struct ps2if *ps2if, unsigned int mask)
 {
        unsigned int val;
 
-       sa1111_writel(PS2CR_ENA | mask, sa->base + SA1111_PS2CR);
+       sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
 
        udelay(2);
 
-       val = sa1111_readl(sa->base + SA1111_PS2STAT);
+       val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
        return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 
@@ -141,141 +193,168 @@ ps2_test_one(struct ps2if *sa, unsigned int mask)
  * Test the keyboard interface.  We basically check to make sure that
  * we can drive each line to the keyboard independently of each other.
  */
-static int __init ps2_test(struct ps2if *sa)
+static int __init ps2_test(struct ps2if *ps2if)
 {
        unsigned int stat;
        int ret = 0;
 
-       stat = ps2_test_one(sa, PS2CR_FKC);
+       stat = ps2_test_one(ps2if, PS2CR_FKC);
        if (stat != PS2STAT_KBD) {
-               printk("Keyboard interface test failed[1]: %02x\n", stat);
+               printk("PS/2 interface test failed[1]: %02x\n", stat);
                ret = -ENODEV;
        }
 
-       stat = ps2_test_one(sa, 0);
+       stat = ps2_test_one(ps2if, 0);
        if (stat != (PS2STAT_KBC | PS2STAT_KBD)) {
-               printk("Keyboard interface test failed[2]: %02x\n", stat);
+               printk("PS/2 interface test failed[2]: %02x\n", stat);
                ret = -ENODEV;
        }
 
-       stat = ps2_test_one(sa, PS2CR_FKD);
+       stat = ps2_test_one(ps2if, PS2CR_FKD);
        if (stat != PS2STAT_KBC) {
-               printk("Keyboard interface test failed[3]: %02x\n", stat);
+               printk("PS/2 interface test failed[3]: %02x\n", stat);
                ret = -ENODEV;
        }
 
-       sa1111_writel(0, sa->base + SA1111_PS2CR);
+       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
 
        return ret;
 }
 
 /*
- * Initialise one PS/2 port.
+ * Add one device to this driver.
  */
-static int __init ps2_init_one(struct sa1111_device *dev, struct ps2if *sa)
+static int ps2_probe(struct device *dev)
 {
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+       struct ps2if *ps2if;
        int ret;
 
+       ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
+       if (!ps2if) {
+               return -ENOMEM;
+       }
+
+       memset(ps2if, 0, sizeof(struct ps2if));
+
+       ps2if->io.type          = SERIO_8042;
+       ps2if->io.write         = ps2_write;
+       ps2if->io.open          = ps2_open;
+       ps2if->io.close         = ps2_close;
+       ps2if->io.name          = dev->name;
+       ps2if->io.phys          = dev->bus_id;
+       ps2if->io.driver        = ps2if;
+       ps2if->dev              = sadev;
+       dev->driver_data        = ps2if;
+
+       spin_lock_init(&ps2if->lock);
+
        /*
         * Request the physical region for this PS2 port.
         */
-       sa->res = request_mem_region(_SA1111(sa->base), 512, "ps2");
-       if (!sa->res)
-               return -EBUSY;
+       if (!request_mem_region(sadev->res.start,
+                               sadev->res.end - sadev->res.start + 1,
+                               SA1111_DRIVER_NAME(sadev))) {
+               ret = -EBUSY;
+               goto free;
+       }
 
        /*
-        * Convert the chip offset to virtual address.
+        * Our parent device has already mapped the region.
         */
-       sa->base += (unsigned long)dev->base;
+       ps2if->base = (unsigned long)sadev->mapbase;
 
-       sa1111_enable_device(sa->skpcr_mask);
+       sa1111_enable_device(ps2if->dev);
 
        /* Incoming clock is 8MHz */
-       sa1111_writel(0, sa->base + SA1111_PS2CLKDIV);
-       sa1111_writel(127, sa->base + SA1111_PS2PRECNT);
+       sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
+       sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
 
        /*
         * Flush any pending input.
         */
-       ps2_clear_input(sa);
+       ps2_clear_input(ps2if);
 
        /*
         * Test the keyboard interface.
         */
-       ret = ps2_test(sa);
+       ret = ps2_test(ps2if);
        if (ret)
                goto out;
 
        /*
         * Flush any pending input.
         */
-       ps2_clear_input(sa);
-       sa1111_disable_device(sa->skpcr_mask);
+       ps2_clear_input(ps2if);
 
-       serio_register_port(&sa->io);
+       sa1111_disable_device(ps2if->dev);
+       serio_register_port(&ps2if->io);
        return 0;
 
  out:
-       sa1111_disable_device(sa->skpcr_mask);
-       release_resource(sa->res);
+       sa1111_disable_device(ps2if->dev);
+       release_mem_region(sadev->res.start,
+                          sadev->res.end - sadev->res.start + 1);
+ free:
+       dev->driver_data = NULL;
+       kfree(ps2if);
        return ret;
 }
 
 /*
- * Remove one PS/2 port.
+ * Remove one device from this driver.
  */
-static void __exit ps2_remove_one(struct ps2if *sa)
+static int ps2_remove(struct device *dev)
 {
-       serio_unregister_port(&sa->io);
-       release_resource(sa->res);
+       struct ps2if *ps2if = dev->driver_data;
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+       serio_unregister_port(&ps2if->io);
+       release_mem_region(sadev->res.start,
+                          sadev->res.end - sadev->res.start + 1);
+       kfree(ps2if);
+
+       dev->driver_data = NULL;
+
+       return 0;
 }
 
-static struct ps2if ps2_kbd_port =
+/*
+ * We should probably do something here, but what?
+ */
+static int ps2_suspend(struct device *dev, u32 state, u32 level)
 {
-       io: {
-               type:           SERIO_8042,
-               write:          ps2_write,
-               open:           ps2_open,
-               close:          ps2_close,
-               name:           "SA1111 PS/2 kbd port",
-               phys:           "sa1111/serio0",
-               driver:         &ps2_kbd_port,
-       },
-       base:           SA1111_KBD,
-       irq:            IRQ_TPRXINT,
-       skpcr_mask:     SKPCR_PTCLKEN,
-};
+       return 0;
+}
 
-static struct ps2if ps2_mse_port =
+static int ps2_resume(struct device *dev, u32 level)
 {
-       io: {
-               type:           SERIO_8042,
-               write:          ps2_write,
-               open:           ps2_open,
-               close:          ps2_close,
-               name:           "SA1111 PS/2 mouse port",
-               phys:           "sa1111/serio1",
-               driver:         &ps2_mse_port,
+       return 0;
+}
+
+/*
+ * Our device driver structure
+ */
+static struct sa1111_driver ps2_driver = {
+       .drv = {
+               .name           = "SA1111 PS2",
+               .bus            = &sa1111_bus_type,
+               .probe          = ps2_probe,
+               .remove         = ps2_remove,
+               .suspend        = ps2_suspend,
+               .resume         = ps2_resume,
        },
-       base:           SA1111_MSE,
-       irq:            IRQ_MSRXINT,
-       skpcr_mask:     SKPCR_PMCLKEN,
+       .devid                  = SA1111_DEVID_PS2,
 };
 
 static int __init ps2_init(void)
 {
-       int ret = -ENODEV;
-
-       if (sa1111) {
-               ret = ps2_init_one(sa1111, &ps2_kbd_port);
-       }
-
-       return ret;
+       return driver_register(&ps2_driver.drv);
 }
 
 static void __exit ps2_exit(void)
 {
-       ps2_remove_one(&ps2_kbd_port);
+       remove_driver(&ps2_driver.drv);
 }
 
 module_init(ps2_init);
index 56866d225c48eeba30dd8b6b71ee7ff3710748a0..4f8bfb54642450cf9e0c19f66bb815568616c3d5 100644 (file)
@@ -20,6 +20,7 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
    fi
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+      dep_tristate '  SA1111 support' CONFIG_PCMCIA_SA1111 $CONFIG_PCMCIA_SA1100 $CONFIG_SA1111 $CONFIG_PCMCIA
    fi
 fi
 
index 497523e5f7b1c6743f7d71322311435bebfcb04f..734b5a5cec438bae5d710dd16a2df275a9371fbc 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_I82092)                  += i82092.o
 obj-$(CONFIG_TCIC)                     += tcic.o
 obj-$(CONFIG_HD64465_PCMCIA)           += hd64465_ss.o
 obj-$(CONFIG_PCMCIA_SA1100)            += sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)            += sa1111_cs.o
 
 yenta_socket-objs                              := pci_socket.o yenta.o
 
@@ -21,26 +22,29 @@ pcmcia_core-objs-y                          := cistpl.o rsrc_mgr.o bulkmem.o cs.o
 pcmcia_core-objs-$(CONFIG_CARDBUS)             += cardbus.o
 pcmcia_core-objs                               := $(pcmcia_core-objs-y)
 
+sa1111_cs-objs-y                               := sa1111_generic.o
+sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY)       += sa1100_adsbitsy.o
+sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET)      += sa1100_neponset.o
+sa1111_cs-objs-$(CONFIG_SA1100_BADGE4)         += sa1100_badge4.o
+sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o
+sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720)     += sa1100_jornada720.o
+sa1111_cs-objs-$(CONFIG_SA1100_PFS168)         += sa1100_pfs168.o
+sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)     += sa1100_system3.o
+sa1111_cs-objs-$(CONFIG_SA1100_XP860)          += sa1100_xp860.o
+sa1111_cs-objs                                 := $(sa1111_cs-objs-y)
+
 sa1100_cs-objs-y                               := sa1100_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)       += sa1100_adsbitsy.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)                += sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)      += sa1100_neponset.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_BADGE4)         += sa1100_badge4.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_CERF)           += sa1100_cerf.o
 sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)       += sa1100_flexanet.o
 sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)       += sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o
 sa1100_cs-objs-$(CONFIG_SA1100_H3600)          += sa1100_h3600.o
-sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)     += sa1100_jornada720.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)       += sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_PFS168)         += sa1100_pfs168.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)     += sa1100_system3.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_SHANNON)                += sa1100_shannon.o
 sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)         += sa1100_simpad.o
 sa1100_cs-objs-$(CONFIG_SA1100_STORK)          += sa1100_stork.o
 sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS)        += sa1100_trizeps.o
-sa1100_cs-objs-$(CONFIG_SA1100_XP860)          += sa1100_xp860.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_YOPY)           += sa1100_yopy.o
 sa1100_cs-objs                                 := $(sa1100_cs-objs-y)
 
index 17d87ab2e2a4ca7e14f582d2bf212040723715f4..202524e4c354d9328c095557cc753836b2195eba 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
index 546ec5d95102725062d5907780177f3f4339594d..77174645d6c1155d38d6478624d3e30f0758f0ae 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/arch/badge4.h>
 #include <asm/hardware/sa1111.h>
 
index 12dc9270e402757e05189c7748cf9b19229e1ff4..efc91296002808463054bc05a7da03a4e84d3d8a 100644 (file)
@@ -1135,15 +1135,9 @@ static int __init sa1100_pcmcia_init(void)
        }
 #endif
 
-#ifdef CONFIG_SA1100_ADSBITSY
-       pcmcia_adsbitsy_init();
-#endif
 #ifdef CONFIG_SA1100_ASSABET
        pcmcia_assabet_init();
 #endif
-#ifdef CONFIG_SA1100_BADGE4
-       pcmcia_badge4_init();
-#endif
 #ifdef CONFIG_SA1100_CERF
        pcmcia_cerf_init();
 #endif
@@ -1156,24 +1150,9 @@ static int __init sa1100_pcmcia_init(void)
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
        pcmcia_gcplus_init();
 #endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-       pcmcia_graphicsmaster_init();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-       pcmcia_jornada720_init();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
-       pcmcia_neponset_init();
-#endif
 #ifdef CONFIG_SA1100_PANGOLIN
        pcmcia_pangolin_init();
 #endif
-#ifdef CONFIG_SA1100_PFS168
-       pcmcia_pfs_init();
-#endif
-#ifdef CONFIG_SA1100_PT_SYSTEM3
-       pcmcia_system3_init();
-#endif
 #ifdef CONFIG_SA1100_SHANNON
        pcmcia_shannon_init();
 #endif
@@ -1186,9 +1165,6 @@ static int __init sa1100_pcmcia_init(void)
 #ifdef CONFIG_SA1100_TRIZEPS
        pcmcia_trizeps_init();
 #endif
-#ifdef CONFIG_SA1100_XP860
-       pcmcia_xp860_init();
-#endif
 #ifdef CONFIG_SA1100_YOPY
        pcmcia_yopy_init();
 #endif
@@ -1203,15 +1179,9 @@ static int __init sa1100_pcmcia_init(void)
  */
 static void __exit sa1100_pcmcia_exit(void)
 {
-#ifdef CONFIG_SA1100_ADSBITSY
-       pcmcia_adsbitsy_exit();
-#endif
 #ifdef CONFIG_SA1100_ASSABET
        pcmcia_assabet_exit();
 #endif
-#ifdef CONFIG_SA1100_BADGE4
-       pcmcia_badge4_exit();
-#endif
 #ifdef CONFIG_SA1100_CERF
        pcmcia_cerf_exit();
 #endif
@@ -1224,21 +1194,9 @@ static void __exit sa1100_pcmcia_exit(void)
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
        pcmcia_gcplus_exit();
 #endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-       pcmcia_graphicsmaster_exit();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-       pcmcia_jornada720_exit();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
-       pcmcia_neponset_exit();
-#endif
 #ifdef CONFIG_SA1100_PANGOLIN
        pcmcia_pangolin_exit();
 #endif
-#ifdef CONFIG_SA1100_PFS168
-       pcmcia_pfs_exit();
-#endif
 #ifdef CONFIG_SA1100_SHANNON
        pcmcia_shannon_exit();
 #endif
@@ -1248,9 +1206,6 @@ static void __exit sa1100_pcmcia_exit(void)
 #ifdef CONFIG_SA1100_STORK
        pcmcia_stork_exit();
 #endif
-#ifdef CONFIG_SA1100_XP860
-       pcmcia_xp860_exit();
-#endif
 #ifdef CONFIG_SA1100_YOPY
        pcmcia_yopy_exit();
 #endif
index 8aeafa167cffa12ee6136612fd43024f776ef43e..9552dfa55816753ff20d1f0571df12cf1f438035 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
index a5d07781929a5b27b2659b5f4bc1fee5d3d038f6..d15f51eedba68bbfda2a974b4b9f76ced133fc5c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
index d8e09192bacc15116532dead9eee20cf64a4c068..12d6c5c662f967f3d9431970ee92a64477c1cb91 100644 (file)
 #include <linux/init.h>
 
 #include <asm/hardware.h>
-#include <asm/arch/assabet.h>
+#include <asm/mach-types.h>
+#include <asm/arch/neponset.h>
 #include <asm/hardware/sa1111.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ *   MAX1600      Neponset
+ *
+ *    A0VCC        SA-1111 GPIO A<1>
+ *    A1VCC        SA-1111 GPIO A<0>
+ *    A0VPP        CPLD NCR A0VPP
+ *    A1VPP        CPLD NCR A1VPP
+ *    B0VCC        SA-1111 GPIO A<2>
+ *    B1VCC        SA-1111 GPIO A<3>
+ *    B0VPP        ground (slot B is CF)
+ *    B1VPP        ground (slot B is CF)
+ *
+ *     VX          VCC (5V)
+ *     VY          VCC3_3 (3.3V)
+ *     12INA       12V
+ *     12INB       ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in 
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
 static int neponset_pcmcia_init(struct pcmcia_init *init)
 {
-       /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
-       PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-
-       /* MAX1600 to standby mode: */
-       PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
        NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
 
+       /*
+        * Set GPIO_A<3:0> to be outputs for the MAX1600,
+        * and switch to standby mode.
+        */
+       PA_DDR = 0;
+       PA_SDR = 0;
+       PA_DWR = 0;
+       PA_SSR = 0;
+
        return sa1111_pcmcia_init(init);
 }
 
@@ -35,29 +64,6 @@ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
        unsigned int ncr_set, pa_dwr_set;
        int ret;
 
-       /* Neponset uses the Maxim MAX1600, with the following connections:
-
-        *   MAX1600      Neponset
-        *
-        *    A0VCC        SA-1111 GPIO A<1>
-        *    A1VCC        SA-1111 GPIO A<0>
-        *    A0VPP        CPLD NCR A0VPP
-        *    A1VPP        CPLD NCR A1VPP
-        *    B0VCC        SA-1111 GPIO A<2>
-        *    B1VCC        SA-1111 GPIO A<3>
-        *    B0VPP        ground (slot B is CF)
-        *    B1VPP        ground (slot B is CF)
-        *
-        *     VX          VCC (5V)
-        *     VY          VCC3_3 (3.3V)
-        *     12INA       12V
-        *     12INB       ground (slot B is CF)
-        *
-        * The MAX1600 CODE pin is tied to ground, placing the device in 
-        * "Standard Intel code" mode. Refer to the Maxim data sheet for
-        * the corresponding truth table.
-        */
-
        switch (conf->sock) {
        case 0:
                pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
@@ -135,13 +141,13 @@ int __init pcmcia_neponset_init(void)
 {
        int ret = -ENODEV;
 
-       if (machine_is_assabet() && sa1111)
+       if (machine_is_assabet())
                ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
 
        return ret;
 }
 
-void __exit pcmcia_neponset_exit(void)
+void __devexit pcmcia_neponset_exit(void)
 {
        sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
 }
index af028d61b6822fb40494c3cac5450e00299eceb4..511afebb38a38dad07d00e47cd92829bbcbcf134 100644 (file)
@@ -7,10 +7,11 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 
 #include "sa1100_generic.h"
index fc4bed07c4a32747acc3c3f3723a8b422b36f54c..2ab0d4537d0dcd8227dd6e8e73e3bd050a156cfa 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ioport.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include <asm/hardware/sa1111.h>
 
index 84c315a97cdd82fd45d997f4943f947dc24d6208..69d3f3ddaaccefb7f43bab5d4e257ad83d3c2b74 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
index ef5a8b0bf153a1e1d906895f91443aa4cfd8256f..9bf1a6c392d46bf3e48e9d9d8ef99a59b3af5b57 100644 (file)
@@ -5,10 +5,12 @@
  * basically means we handle everything except controlling the
  * power.  Power is machine specific...
  */
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/hardware/sa1111.h>
@@ -21,19 +23,18 @@ static struct irqs {
        int irq;
        const char *str;
 } irqs[] = {
-       { S0_CD_VALID,    "SA1111 PCMCIA card detect" },
-       { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
-       { S1_CD_VALID,    "SA1111 CF card detect"     },
-       { S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
+       { IRQ_S0_CD_VALID,    "SA1111 PCMCIA card detect" },
+       { IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
+       { IRQ_S1_CD_VALID,    "SA1111 CF card detect"     },
+       { IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
 };
 
+static struct sa1111_dev *pcmcia;
+
 int sa1111_pcmcia_init(struct pcmcia_init *init)
 {
        int i, ret;
 
-       if (!request_mem_region(_PCCR, 512, "PCMCIA"))
-               return -1;
-
        for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
                set_irq_type(irqs[i].irq, IRQT_FALLING);
                ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
@@ -47,8 +48,6 @@ int sa1111_pcmcia_init(struct pcmcia_init *init)
                        irqs[i].irq, ret);
                while (i--)
                        free_irq(irqs[i].irq, NULL);
-
-               release_mem_region(_PCCR, 16);
        }
 
        return ret ? -1 : 2;
@@ -61,8 +60,6 @@ int sa1111_pcmcia_shutdown(void)
        for (i = 0; i < ARRAY_SIZE(irqs); i++)
                free_irq(irqs[i].irq, NULL);
 
-       release_mem_region(_PCCR, 512);
-
        return 0;
 }
 
@@ -73,7 +70,7 @@ int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state)
        if (state->size < 2)
                return -1;
 
-       status = PCSR;
+       status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR);
 
        state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
        state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
@@ -99,8 +96,8 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
        int ret = 0;
 
        switch (info->sock) {
-       case 0: info->irq = S0_READY_NINT;      break;
-       case 1: info->irq = S1_READY_NINT;      break;
+       case 0: info->irq = IRQ_S0_READY_NINT;  break;
+       case 1: info->irq = IRQ_S1_READY_NINT;  break;
        default: ret = 1;
        }
 
@@ -109,7 +106,7 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
 
 int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-       unsigned int rst, flt, wait, pse, irq, pccr_mask;
+       unsigned int rst, flt, wait, pse, irq, pccr_mask, val;
        unsigned long flags;
 
        switch (conf->sock) {
@@ -118,7 +115,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
                flt = PCCR_S0_FLT;
                wait = PCCR_S0_PWAITEN;
                pse = PCCR_S0_PSE;
-               irq = S0_READY_NINT;
+               irq = IRQ_S0_READY_NINT;
                break;
 
        case 1:
@@ -126,7 +123,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
                flt = PCCR_S1_FLT;
                wait = PCCR_S1_PWAITEN;
                pse = PCCR_S1_PSE;
-               irq = S1_READY_NINT;
+               irq = IRQ_S1_READY_NINT;
                break;
 
        default:
@@ -159,7 +156,9 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
                pccr_mask |= flt;
 
        local_irq_save(flags);
-       PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask;
+       val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR);
+       val = (val & ~(pse | flt | wait | rst)) | pccr_mask;
+       sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR);
        local_irq_restore(flags);
 
        if (conf->irq)
@@ -179,3 +178,130 @@ int sa1111_pcmcia_socket_suspend(int sock)
 {
        return 0;
 }
+
+static int pcmcia_probe(struct device *dev)
+{
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+       unsigned long flags;
+       char *base;
+
+       local_irq_save(flags);
+       if (pcmcia) {
+               local_irq_restore(flags);
+               return -EBUSY;
+       }
+
+       pcmcia = sadev;
+       local_irq_restore(flags);
+
+       if (!request_mem_region(sadev->res.start, 512,
+                               SA1111_DRIVER_NAME(sadev)))
+               return -EBUSY;
+
+       base = sadev->mapbase;
+
+       /*
+        * Initialise the suspend state.
+        */
+       sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
+       sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+       pcmcia_adsbitsy_init();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+       pcmcia_badge4_init();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+       pcmcia_graphicsmaster_init();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+       pcmcia_jornada720_init();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+       pcmcia_neponset_init();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+       pcmcia_pfs_init();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+       pcmcia_system3_init();
+#endif
+#ifdef CONFIG_SA1100_XP860
+       pcmcia_xp860_init();
+#endif
+       return 0;
+}
+
+static int __devexit pcmcia_remove(struct device *dev)
+{
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+       pcmcia_adsbitsy_exit();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+       pcmcia_badge4_exit();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+       pcmcia_graphicsmaster_exit();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+       pcmcia_jornada720_exit();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+       pcmcia_neponset_exit();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+       pcmcia_pfs_exit();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+       pcmcia_system3_exit();
+#endif
+#ifdef CONFIG_SA1100_XP860
+       pcmcia_xp860_exit();
+#endif
+
+       release_mem_region(sadev->res.start, 512);
+       pcmcia = NULL;
+
+       return 0;
+}
+
+static int pcmcia_suspend(struct device *dev, u32 state, u32 level)
+{
+       return 0;
+}
+
+static int pcmcia_resume(struct device *dev, u32 level)
+{
+       return 0;
+}
+
+static struct sa1111_driver pcmcia_driver = {
+       .drv = {
+               .name           = "SA1111 PCMCIA",
+               .bus            = &sa1111_bus_type,
+               .probe          = pcmcia_probe,
+               .remove         = __devexit_p(pcmcia_remove),
+               .suspend        = pcmcia_suspend,
+               .resume         = pcmcia_resume,
+       },
+       .devid                  = SA1111_DEVID_PCMCIA,
+};
+
+static int __init sa1111_drv_pcmcia_init(void)
+{
+       return driver_register(&pcmcia_driver.drv);
+}
+
+static void __exit sa1111_drv_pcmcia_exit(void)
+{
+       remove_driver(&pcmcia_driver.drv);
+}
+
+module_init(sa1111_drv_pcmcia_init);
+module_exit(sa1111_drv_pcmcia_exit);
+
+MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
+MODULE_LICENSE("GPL");
index f7b44577a7a0e4c40cbe6f148bab10dae331093d..a6a34619d4fd930e63a9a58b17f0d9472528c2c3 100644 (file)
@@ -25,7 +25,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void sa1111_start_hc(void)
+static void sa1111_start_hc(struct sa1111_dev *dev)
 {
        unsigned int usb_rst = 0;
 
@@ -48,31 +48,35 @@ static void sa1111_start_hc(void)
         * Configure the power sense and control lines.  Place the USB
         * host controller in reset.
         */
-       USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+       sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+                     dev->mapbase + SA1111_USB_RESET);
 
        /*
         * Now, carefully enable the USB clock, and take
         * the USB host controller out of reset.
         */
-       SKPCR |= SKPCR_UCLKEN;
+       sa1111_enable_device(dev);
        udelay(11);
-       USB_RESET = usb_rst;
+       sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
 }
 
-static void sa1111_stop_hc(void)
+static void sa1111_stop_hc(struct sa1111_dev *dev)
 {
+       unsigned int usb_rst;
        printk(KERN_DEBUG __FILE__ 
               ": stopping SA-1111 OHCI USB Controller\n");
 
        /*
         * Put the USB host controller into reset.
         */
-       USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+       usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+       sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+                     dev->mapbase + SA1111_USB_RESET);
 
        /*
         * Stop the USB clock.
         */
-       SKPCR &= ~SKPCR_UCLKEN;
+       sa1111_disable_device(dev);
 
 #ifdef CONFIG_SA1100_BADGE4
        if (machine_is_badge4()) {
@@ -86,9 +90,9 @@ static void sa1111_stop_hc(void)
 /*-------------------------------------------------------------------------*/
 
 #if 0
-static void dump_hci_status(const char *label)
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
 {
-       unsigned long status = USB_STATUS; 
+       unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
 
        dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
             ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
@@ -101,11 +105,14 @@ static void dump_hci_status(const char *label)
 
 static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
 {
-       //dump_hci_status("irq");
+       struct usb_hcd *hcd = __hcd;
+//     unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
+
+       //dump_hci_status(hcd, "irq");
 
 #if 0
        /* may work better this way -- need to investigate further */
-       if (USB_STATUS & USB_STATUS_NIRQHCIM) {
+       if (status & USB_STATUS_NIRQHCIM) {
                //dbg ("not normal HC interrupt; ignoring");
                return;
        }
@@ -116,7 +123,7 @@ static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
 
 /*-------------------------------------------------------------------------*/
 
-void usb_hcd_sa1111_remove (struct usb_hcd *);
+void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
 
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
@@ -132,21 +139,20 @@ void usb_hcd_sa1111_remove (struct usb_hcd *);
  *
  * Store this function in the HCD's struct pci_driver as probe().
  */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_out)
+int usb_hcd_sa1111_probe (const struct hc_driver *driver,
+                         struct usb_hcd **hcd_out,
+                         struct sa1111_dev *dev)
 {
        int retval;
        struct usb_hcd *hcd = 0;
 
-       if (!sa1111)
-               return -ENODEV;
-
-       if (!request_mem_region(_USB_OHCI_OP_BASE, 
-                               _USB_EXTENT, hcd_name)) {
+       if (!request_mem_region(dev->res.start, 
+                               dev->res.end - dev->res.start + 1, hcd_name)) {
                dbg("request_mem_region failed");
                return -EBUSY;
        }
 
-       sa1111_start_hc();
+       sa1111_start_hc(dev);
 
        hcd = driver->hcd_alloc ();
        if (hcd == NULL){
@@ -157,9 +163,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
 
        hcd->driver = (struct hc_driver *) driver;
        hcd->description = driver->description;
-       hcd->irq = NIRQHCIM;
-       hcd->regs = (void *) &USB_OHCI_OP_BASE;
+       hcd->irq = dev->irq[1];
+       hcd->regs = dev->mapbase;
        hcd->pdev = SA1111_FAKE_PCIDEV;
+       hcd->parent = &dev->dev;
 
        retval = hcd_buffer_create (hcd);
        if (retval != 0) {
@@ -167,8 +174,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
                goto err1;
        }
 
-       set_irq_type(NIRQHCIM, IRQT_RISING);
-       retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
+       set_irq_type(hcd->irq, IRQT_RISING);
+       retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
                              hcd->description, hcd);
        if (retval != 0) {
                dbg("request_irq failed");
@@ -191,7 +198,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
 
        if ((retval = driver->start (hcd)) < 0) 
        {
-               usb_hcd_sa1111_remove(hcd);
+               usb_hcd_sa1111_remove(hcd, dev);
                return retval;
        }
 
@@ -202,8 +209,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
        hcd_buffer_destroy (hcd);
        if (hcd) driver->hcd_free(hcd);
  err1:
-       sa1111_stop_hc();
-       release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+       sa1111_stop_hc(dev);
+       release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
        return retval;
 }
 
@@ -221,7 +228,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
  * context, normally "rmmod", "apmd", or something similar.
  *
  */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
+void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
 {
        struct usb_device       *hub;
        void *base;
@@ -244,13 +251,13 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
 
        usb_deregister_bus (&hcd->self);
        if (atomic_read (&hcd->self.refcnt) != 1)
-               err (__FUNCTION__ ": %s, count != 1", hcd->self.bus_name);
+               err ("%s: %s, count != 1", __FUNCTION__, hcd->self.bus_name);
 
        base = hcd->regs;
        hcd->driver->hcd_free (hcd);
 
-       sa1111_stop_hc();
-       release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+       sa1111_stop_hc(dev);
+       release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -275,7 +282,7 @@ ohci_sa1111_start (struct usb_hcd *hcd)
        }
        ohci->regs = hcd->regs;
 
-       ohci->parent_dev = &sa1111->dev;
+       ohci->parent_dev = hcd->parent;
 
        if (hc_reset (ohci) < 0) {
                ohci_stop (hcd);
@@ -342,26 +349,67 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-/* Only one SA-1111 ever exists. */
-static struct usb_hcd *the_sa1111_hcd;
+static int ohci_hcd_sa1111_drv_probe(struct device *_dev)
+{
+       struct sa1111_dev *dev = SA1111_DEV(_dev);
+       struct usb_hcd *hcd = NULL;
+       int ret;
+
+       ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
+
+       if (ret == 0)
+               dev->dev.driver_data = hcd;
+
+       return ret;
+}
+
+static int ohci_hcd_sa1111_drv_remove(struct device *_dev)
+{
+       struct sa1111_dev *dev = SA1111_DEV(_dev);
+       struct usb_hcd *hcd = dev->dev.driver_data;
+
+       usb_hcd_sa1111_remove(hcd, dev);
+
+       dev->dev.driver_data = NULL;
 
-static int __init ohci_hcd_sa1111_init (void) 
+       return 0;
+}
+
+static int ohci_hcd_sa1111_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+       return 0;
+}
+
+static int ohci_hcd_sa1111_drv_resume(struct device *dev, u32 level)
+{
+       return 0;
+}
+
+static struct sa1111_driver ohci_hcd_sa1111_driver = {
+       .drv = {
+               .name           = "SA1111 OHCI",
+               .bus            = &sa1111_bus_type,
+               .probe          = ohci_hcd_sa1111_drv_probe,
+               .remove         = ohci_hcd_sa1111_drv_remove,
+               .suspend        = ohci_hcd_sa1111_drv_suspend,
+               .resume         = ohci_hcd_sa1111_drv_resume,
+       },
+       .devid                  = SA1111_DEVID_USB,
+};
+
+static int __init ohci_hcd_sa1111_init (void)
 {
        dbg (DRIVER_INFO " (SA-1111)");
        dbg ("block sizes: ed %d td %d",
                sizeof (struct ed), sizeof (struct td));
 
-       the_sa1111_hcd = 0;
-       return usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &the_sa1111_hcd);
+       return driver_register(&ohci_hcd_sa1111_driver.drv);
 }
-module_init (ohci_hcd_sa1111_init);
 
-
-static void __exit ohci_hcd_sa1111_cleanup (void) 
-{      
-       if (the_sa1111_hcd) {
-               usb_hcd_sa1111_remove(the_sa1111_hcd);
-               the_sa1111_hcd = 0;
-       }
+static void __exit ohci_hcd_sa1111_cleanup (void)
+{
+       remove_driver(&ohci_hcd_sa1111_driver.drv);
 }
+
+module_init (ohci_hcd_sa1111_init);
 module_exit (ohci_hcd_sa1111_cleanup);
index c334e869f8ef22e9fb39ee88884c0fd1d632a712..58774d1092ebc7ee10555798226f50a28bcee579 100644 (file)
 #define SA1111_SMCR    0x0004
 #define SA1111_SKID    0x0008
 
-#define _SBI_SKCR      _SA1111(SA1111_SKCR)
-#define _SBI_SMCR      _SA1111(SA1111_SMCR)
-#define _SBI_SKID      _SA1111(SA1111_SKID)
-
-#if LANGUAGE == C
-
 #define SBI_SKCR       __CCREG(SA1111_SKCR)
 #define SBI_SMCR       __CCREG(SA1111_SMCR)
 #define SBI_SKID       __CCREG(SA1111_SKID)
 
-#endif  /* LANGUAGE == C */
-
 #define SKCR_PLL_BYPASS        (1<<0)
 #define SKCR_RCLKEN    (1<<1)
 #define SKCR_SLEEP     (1<<2)
 #define SA1111_SKPMC   0x020c
 #define SA1111_SKPTC   0x0210
 #define SA1111_SKPEN0  0x0214
-#define SA1111_SKPWN0  0x0218
+#define SA1111_SKPWM0  0x0218
 #define SA1111_SKPEN1  0x021c
 #define SA1111_SKPWM1  0x0220
 
-#define _SKPCR         _SA1111(SA1111_SKPCR)
-#define _SKCDR         _SA1111(SA1111_SKCDR)
-#define _SKAUD         _SA1111(SA1111_SKAUD)
-#define _SKPMC         _SA1111(SA1111_SKPMC)
-#define _SKPTC         _SA1111(SA1111_SKPTC)
-#define _SKPEN0                _SA1111(SA1111_SKPEN0)
-#define _SKPWM0                _SA1111(SA1111_SKPWM0)
-#define _SKPEN1                _SA1111(SA1111_SKPEN1)
-#define _SKPWM1                _SA1111(SA1111_SKPWM1)
-
-#if LANGUAGE == C
-
 #define SKPCR          __CCREG(SA1111_SKPCR)
 #define SKCDR          __CCREG(SA1111_SKCDR)
 #define SKAUD          __CCREG(SA1111_SKAUD)
 #define SKPEN1         __CCREG(SA1111_SKPEN1)
 #define SKPWM1         __CCREG(SA1111_SKPWM1)
 
-#endif  /* LANGUAGE == C */
-
 #define SKPCR_UCLKEN   (1<<0)
 #define SKPCR_ACCLKEN  (1<<1)
 #define SKPCR_I2SCLKEN (1<<2)
 /*
  * USB Host controller
  */
-#define _USB_OHCI_OP_BASE      _SA1111( 0x400 )
-#define _USB_STATUS            _SA1111( 0x518 )
-#define _USB_RESET             _SA1111( 0x51c )
-#define _USB_INTERRUPTEST      _SA1111( 0x520 )
-
-#define _USB_EXTENT            (_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
+#define SA1111_USB             0x0400
 
-#if LANGUAGE == C
-
-#define USB_OHCI_OP_BASE       __CCREG(0x0400)
-#define USB_STATUS             __CCREG(0x0518)
-#define USB_RESET              __CCREG(0x051c)
-#define USB_INTERRUPTEST       __CCReG(0x0520)
-
-#endif  /* LANGUAGE == C */
+/*
+ * Offsets from SA1111_USB_BASE
+ */
+#define SA1111_USB_STATUS      0x0118
+#define SA1111_USB_RESET       0x011c
+#define SA1111_USB_IRQTEST     0x0120
 
 #define USB_RESET_FORCEIFRESET (1 << 0)
 #define USB_RESET_FORCEHCRESET (1 << 1)
  *    WAKE_POL0                Wake-up polarity selection 0
  *    WAKE_POL1                Wake-up polarity selection 1
  */
+#define SA1111_INTC            0x1600
 
-#define SA1111_INTTEST0                0x1600
-#define SA1111_INTTEST1                0x1604
-#define SA1111_INTEN0          0x1608
-#define SA1111_INTEN1          0x160c
-#define SA1111_INTPOL0         0x1610
-#define SA1111_INTPOL1         0x1614
-#define SA1111_INTTSTSEL       0x1618
-#define SA1111_INTSTATCLR0     0x161c
-#define SA1111_INTSTATCLR1     0x1620
-#define SA1111_INTSET0         0x1624
-#define SA1111_INTSET1         0x1628
-#define SA1111_WAKE_EN0                0x162c
-#define SA1111_WAKE_EN1                0x1630
-#define SA1111_WAKE_POL0       0x1634
-#define SA1111_WAKE_POL1       0x1638
-
-#define _INTTEST0      _SA1111(SA1111_INTTEST0)
-#define _INTTEST1      _SA1111(SA1111_INTTEST1)
-#define _INTEN0                _SA1111(SA1111_INTEN0)
-#define _INTEN1                _SA1111(SA1111_INTEN1)
-#define _INTPOL0       _SA1111(SA1111_INTPOL0)
-#define _INTPOL1       _SA1111(SA1111_INTPOL1)
-#define _INTTSTSEL     _SA1111(SA1111_INTTSTSEL)
-#define _INTSTATCLR0   _SA1111(SA1111_INTSTATCLR0)
-#define _INTSTATCLR1   _SA1111(SA1111_INTSTATCLR1)
-#define _INTSET0       _SA1111(SA1111_INTSET0)
-#define _INTSET1       _SA1111(SA1111_INTSET1)
-#define _WAKE_EN0      _SA1111(SA1111_WAKE_EN0)
-#define _WAKE_EN1      _SA1111(SA1111_WAKE_EN1)
-#define _WAKE_POL0     _SA1111(SA1111_WAKE_POL0)
-#define _WAKE_POL1     _SA1111(SA1111_WAKE_POL1)
-
-#if LANGUAGE == C
-
-#define INTTEST0       __CCREG(SA1111_INTTEST0)
-#define INTTEST1       __CCREG(SA1111_INTTEST1)
-#define INTEN0         __CCREG(SA1111_INTEN0)
-#define INTEN1         __CCREG(SA1111_INTEN1)
-#define INTPOL0                __CCREG(SA1111_INTPOL0)
-#define INTPOL1                __CCREG(SA1111_INTPOL1)
-#define INTTSTSEL      __CCREG(SA1111_INTTSTSEL)
-#define INTSTATCLR0    __CCREG(SA1111_INTSTATCLR0)
-#define INTSTATCLR1    __CCREG(SA1111_INTSTATCLR1)
-#define INTSET0                __CCREG(SA1111_INTSET0)
-#define INTSET1                __CCREG(SA1111_INTSET1)
-#define WAKE_EN0       __CCREG(SA1111_WAKE_EN0)
-#define WAKE_EN1       __CCREG(SA1111_WAKE_EN1)
-#define WAKE_POL0      __CCREG(SA1111_WAKE_POL0)
-#define WAKE_POL1      __CCREG(SA1111_WAKE_POL1)
-
-#endif  /* LANGUAGE == C */
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_INTTEST0                0x0000
+#define SA1111_INTTEST1                0x0004
+#define SA1111_INTEN0          0x0008
+#define SA1111_INTEN1          0x000c
+#define SA1111_INTPOL0         0x0010
+#define SA1111_INTPOL1         0x0014
+#define SA1111_INTTSTSEL       0x0018
+#define SA1111_INTSTATCLR0     0x001c
+#define SA1111_INTSTATCLR1     0x0020
+#define SA1111_INTSET0         0x0024
+#define SA1111_INTSET1         0x0028
+#define SA1111_WAKEEN0         0x002c
+#define SA1111_WAKEEN1         0x0030
+#define SA1111_WAKEPOL0                0x0034
+#define SA1111_WAKEPOL1                0x0038
+
+#define INTTEST0       __CCREG(SA1111_INTC + SA1111_INTTEST0)
+#define INTTEST1       __CCREG(SA1111_INTC + SA1111_INTTEST1)
+#define INTEN0         __CCREG(SA1111_INTC + SA1111_INTEN0)
+#define INTEN1         __CCREG(SA1111_INTC + SA1111_INTEN1)
+#define INTPOL0                __CCREG(SA1111_INTC + SA1111_INTPOL0)
+#define INTPOL1                __CCREG(SA1111_INTC + SA1111_INTPOL1)
+#define INTTSTSEL      __CCREG(SA1111_INTC + SA1111_INTTSTSEL)
+#define INTSTATCLR0    __CCREG(SA1111_INTC + SA1111_INTSTATCLR0)
+#define INTSTATCLR1    __CCREG(SA1111_INTC + SA1111_INTSTATCLR1)
+#define INTSET0                __CCREG(SA1111_INTC + SA1111_INTSET0)
+#define INTSET1                __CCREG(SA1111_INTC + SA1111_INTSET1)
+#define WAKE_EN0       __CCREG(SA1111_INTC + SA1111_WAKEEN0)
+#define WAKE_EN1       __CCREG(SA1111_INTC + SA1111_WAKEEN1)
+#define WAKE_POL0      __CCREG(SA1111_INTC + SA1111_WAKEPOL0)
+#define WAKE_POL1      __CCREG(SA1111_INTC + SA1111_WAKEPOL1)
 
 /*
  * PS/2 Trackpad and Mouse Interfaces
  *
- * Registers   (prefix kbd applies to trackpad interface, mse to mouse)
- *    KBDCR     Control Register
- *    KBDSTAT       Status Register
- *    KBDDATA       Transmit/Receive Data register
- *    KBDCLKDIV     Clock Division Register
- *    KBDPRECNT     Clock Precount Register
- *    KBDTEST1      Test register 1
- *    KBDTEST2      Test register 2
- *    KBDTEST3      Test register 3
- *    KBDTEST4      Test register 4
- *    MSECR
- *    MSESTAT
- *    MSEDATA
- *    MSECLKDIV
- *    MSEPRECNT
- *    MSETEST1
- *    MSETEST2
- *    MSETEST3
- *    MSETEST4
- *
+ * Registers
+ *    PS2CR            Control Register
+ *    PS2STAT          Status Register
+ *    PS2DATA          Transmit/Receive Data register
+ *    PS2CLKDIV                Clock Division Register
+ *    PS2PRECNT                Clock Precount Register
+ *    PS2TEST1         Test register 1
+ *    PS2TEST2         Test register 2
+ *    PS2TEST3         Test register 3
+ *    PS2TEST4         Test register 4
  */
 
 #define SA1111_KBD             0x0a00
  *    PCSSR    Sleep State Register
  */
 
-#define _PCCR          _SA1111( 0x1800 )
-#define _PCSSR         _SA1111( 0x1804 )
-#define _PCSR          _SA1111( 0x1808 )
-
-#if LANGUAGE == C
-
-#define PCCR           __CCREG(0x1800)
-#define PCSSR          __CCREG(0x1804)
-#define PCSR           __CCREG(0x1808)
+#define SA1111_PCMCIA  0x1600
 
-#endif  /* LANGUAGE == C */
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_PCCR    0x0000
+#define SA1111_PCSSR   0x0004
+#define SA1111_PCSR    0x0008
 
 #define PCSR_S0_READY  (1<<0)
 #define PCSR_S1_READY  (1<<1)
 #define PCSSR_S0_SLEEP (1<<0)
 #define PCSSR_S1_SLEEP (1<<1)
 
-struct sa1111_device {
+
+
+
+extern struct bus_type sa1111_bus_type;
+
+#define SA1111_DEVID_SBI       0
+#define SA1111_DEVID_SK                1
+#define SA1111_DEVID_USB       2
+#define SA1111_DEVID_SAC       3
+#define SA1111_DEVID_SSP       4
+#define SA1111_DEVID_PS2       5
+#define SA1111_DEVID_GPIO      6
+#define SA1111_DEVID_INT       7
+#define SA1111_DEVID_PCMCIA    8
+
+struct sa1111_dev {
        struct device   dev;
-       struct resource resource;
-       void            *base;
+       unsigned int    devid;
+       struct resource res;
+       void            *mapbase;
+       unsigned int    skpcr_mask;
+       unsigned int    irq[6];
 };
 
-extern struct sa1111_device *sa1111;
+#define SA1111_DEV(_d) container_of((_d), struct sa1111_dev, dev)
 
-int sa1111_check_dma_bug(dma_addr_t addr);
+struct sa1111_driver {
+       struct device_driver    drv;
+       unsigned int            devid;
+};
+
+#define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
+
+#define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
 
 /*
  * These frob the SKPCR register.
  */
-void sa1111_enable_device(unsigned int mask);
-void sa1111_disable_device(unsigned int mask);
+void sa1111_enable_device(struct sa1111_dev *);
+void sa1111_disable_device(struct sa1111_dev *);
+
+unsigned int sa1111_pll_clock(struct sa1111_dev *);
+
+#define SA1111_AUDIO_ACLINK    0
+#define SA1111_AUDIO_I2S       1
 
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode);
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate);
+int sa1111_get_audio_rate(struct sa1111_dev *sadev);
+
+int sa1111_check_dma_bug(dma_addr_t addr);
 
 #endif  /* _ASM_ARCH_SA1111 */