Merge branches 'acorn', 'ebsa110' and 'sa11x0' into platforms
authorRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 25 Mar 2012 22:57:55 +0000 (23:57 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 25 Mar 2012 22:57:55 +0000 (23:57 +0100)
67 files changed:
arch/arm/Kconfig
arch/arm/common/sa1111.c
arch/arm/include/asm/hardware/sa1111.h
arch/arm/mach-ebsa110/core.c
arch/arm/mach-ebsa110/core.h [new file with mode: 0644]
arch/arm/mach-ebsa110/include/mach/hardware.h
arch/arm/mach-ebsa110/io.c
arch/arm/mach-ebsa110/leds.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-sa1100/Makefile
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/dma.c [deleted file]
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/h3100.c
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/h3xxx.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/include/mach/SA-1100.h
arch/arm/mach-sa1100/include/mach/dma.h [deleted file]
arch/arm/mach-sa1100/include/mach/irqs.h
arch/arm/mach-sa1100/include/mach/mcp.h
arch/arm/mach-sa1100/include/mach/neponset.h
arch/arm/mach-sa1100/include/mach/shannon.h
arch/arm/mach-sa1100/irq.c
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/nanoengine.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-sa1100/sleep.S
arch/arm/mach-sa1100/ssp.c
arch/arm/mach-sa1100/time.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/sa11x0-dma.c [new file with mode: 0644]
drivers/gpio/gpio-sa1100.c
drivers/input/keyboard/jornada720_kbd.c
drivers/input/serio/sa1111ps2.c
drivers/input/touchscreen/jornada720_ts.c
drivers/mfd/Kconfig
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/ucb1x00-assabet.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mtd/maps/sa1100-flash.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/irda/Kconfig
drivers/net/irda/sa1100_ir.c
drivers/pcmcia/sa1100_neponset.c
drivers/pcmcia/sa1111_generic.c
drivers/rtc/rtc-sa1100.c
drivers/tty/serial/sa1100.c
drivers/usb/host/ohci-sa1111.c
drivers/video/sa1100fb.c
drivers/video/sa1100fb.h
include/linux/mfd/mcp.h
include/linux/mfd/ucb1x00.h
include/linux/sa11x0-dma.h [new file with mode: 0644]
include/video/sa1100fb.h [new file with mode: 0644]

index 4b15d91..4ade2d8 100644 (file)
@@ -759,6 +759,7 @@ config ARCH_SA1100
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_IDE
        select NEED_MACH_MEMORY_H
+       select SPARSE_IRQ
        help
          Support for StrongARM 11x0 based boards.
 
index 61691cd..9173d11 100644 (file)
@@ -16,6 +16,7 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -28,9 +29,8 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/irq.h>
+#include <asm/mach-types.h>
 #include <asm/sizes.h>
 
 #include <asm/hardware/sa1111.h>
 #define IRQ_S1_CD_VALID                (52)
 #define IRQ_S0_BVD1_STSCHG     (53)
 #define IRQ_S1_BVD1_STSCHG     (54)
+#define SA1111_IRQ_NR          (55)
 
-extern void __init sa1110_mb_enable(void);
+extern void sa1110_mb_enable(void);
+extern void sa1110_mb_disable(void);
 
 /*
  * We keep the following data for the overall SA1111.  Note that the
@@ -104,6 +106,7 @@ struct sa1111 {
        int             irq_base;       /* base for cascaded on-chip IRQs */
        spinlock_t      lock;
        void __iomem    *base;
+       struct sa1111_platform_data *pdata;
 #ifdef CONFIG_PM
        void            *saved_state;
 #endif
@@ -118,6 +121,7 @@ static struct sa1111 *g_sa1111;
 struct sa1111_dev_info {
        unsigned long   offset;
        unsigned long   skpcr_mask;
+       bool            dma;
        unsigned int    devid;
        unsigned int    irq[6];
 };
@@ -126,6 +130,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_USB,
                .skpcr_mask     = SKPCR_UCLKEN,
+               .dma            = true,
                .devid          = SA1111_DEVID_USB,
                .irq = {
                        IRQ_USBPWR,
@@ -139,6 +144,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = 0x0600,
                .skpcr_mask     = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+               .dma            = true,
                .devid          = SA1111_DEVID_SAC,
                .irq = {
                        AUDXMTDMADONEA,
@@ -155,7 +161,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_KBD,
                .skpcr_mask     = SKPCR_PTCLKEN,
-               .devid          = SA1111_DEVID_PS2,
+               .devid          = SA1111_DEVID_PS2_KBD,
                .irq = {
                        IRQ_TPRXINT,
                        IRQ_TPTXINT
@@ -164,7 +170,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_MSE,
                .skpcr_mask     = SKPCR_PMCLKEN,
-               .devid          = SA1111_DEVID_PS2,
+               .devid          = SA1111_DEVID_PS2_MSE,
                .irq = {
                        IRQ_MSRXINT,
                        IRQ_MSTXINT
@@ -434,16 +440,28 @@ static struct irq_chip sa1111_high_chip = {
        .irq_set_wake   = sa1111_wake_highirq,
 };
 
-static void sa1111_setup_irq(struct sa1111 *sachip)
+static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
 {
        void __iomem *irqbase = sachip->base + SA1111_INTC;
-       unsigned int irq;
+       unsigned i, irq;
+       int ret;
 
        /*
         * We're guaranteed that this region hasn't been taken.
         */
        request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
 
+       ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
+       if (ret <= 0) {
+               dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
+                       SA1111_IRQ_NR, ret);
+               if (ret == 0)
+                       ret = -EINVAL;
+               return ret;
+       }
+
+       sachip->irq_base = ret;
+
        /* disable all IRQs */
        sa1111_writel(0, irqbase + SA1111_INTEN0);
        sa1111_writel(0, irqbase + SA1111_INTEN1);
@@ -463,14 +481,16 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
        sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0);
        sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1);
 
-       for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
+       for (i = IRQ_GPAIN0; i <= SSPROR; i++) {
+               irq = sachip->irq_base + i;
                irq_set_chip_and_handler(irq, &sa1111_low_chip,
                                         handle_edge_irq);
                irq_set_chip_data(irq, sachip);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
        }
 
-       for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
+       for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) {
+               irq = sachip->irq_base + i;
                irq_set_chip_and_handler(irq, &sa1111_high_chip,
                                         handle_edge_irq);
                irq_set_chip_data(irq, sachip);
@@ -483,6 +503,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
        irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
        irq_set_handler_data(sachip->irq, sachip);
        irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
+
+       dev_info(sachip->dev, "Providing IRQ%u-%u\n",
+               sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
+
+       return 0;
 }
 
 /*
@@ -581,41 +606,10 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
 }
 #endif
 
-#ifdef CONFIG_DMABOUNCE
-/*
- * According to the "Intel StrongARM SA-1111 Microprocessor Companion
- * Chip Specification Update" (June 2000), erratum #7, there is a
- * 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.
- *
- * This routine only identifies whether or not a given DMA address
- * is susceptible to the bug.
- *
- * This should only get called for sa1111_device types due to the
- * way we configure our device dma_masks.
- */
-static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
-{
-       /*
-        * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
-        * User's Guide" mentions that jumpers R51 and R52 control the
-        * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
-        * SDRAM bank 1 on Neponset). The default configuration selects
-        * Assabet, so any address in bank 1 is necessarily invalid.
-        */
-       return (machine_is_assabet() || machine_is_pfs168()) &&
-               (addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
-}
-#endif
-
 static void sa1111_dev_release(struct device *_dev)
 {
        struct sa1111_dev *dev = SA1111_DEV(_dev);
 
-       release_resource(&dev->res);
        kfree(dev);
 }
 
@@ -624,67 +618,58 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
                      struct sa1111_dev_info *info)
 {
        struct sa1111_dev *dev;
+       unsigned i;
        int ret;
 
        dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL);
        if (!dev) {
                ret = -ENOMEM;
-               goto out;
+               goto err_alloc;
        }
 
+       device_initialize(&dev->dev);
        dev_set_name(&dev->dev, "%4.4lx", info->offset);
        dev->devid       = info->devid;
        dev->dev.parent  = sachip->dev;
        dev->dev.bus     = &sa1111_bus_type;
        dev->dev.release = sa1111_dev_release;
-       dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
        dev->res.start   = sachip->phys + info->offset;
        dev->res.end     = dev->res.start + 511;
        dev->res.name    = dev_name(&dev->dev);
        dev->res.flags   = IORESOURCE_MEM;
        dev->mapbase     = sachip->base + info->offset;
        dev->skpcr_mask  = info->skpcr_mask;
-       memmove(dev->irq, info->irq, sizeof(dev->irq));
-
-       ret = request_resource(parent, &dev->res);
-       if (ret) {
-               printk("SA1111: failed to allocate resource for %s\n",
-                       dev->res.name);
-               dev_set_name(&dev->dev, NULL);
-               kfree(dev);
-               goto out;
-       }
-
 
-       ret = device_register(&dev->dev);
-       if (ret) {
-               release_resource(&dev->res);
-               kfree(dev);
-               goto out;
-       }
+       for (i = 0; i < ARRAY_SIZE(info->irq); i++)
+               dev->irq[i] = sachip->irq_base + info->irq[i];
 
-#ifdef CONFIG_DMABOUNCE
        /*
-        * If the parent device has a DMA mask associated with it,
-        * propagate it down to the children.
+        * If the parent device has a DMA mask associated with it, and
+        * this child supports DMA, propagate it down to the children.
         */
-       if (sachip->dev->dma_mask) {
+       if (info->dma && sachip->dev->dma_mask) {
                dev->dma_mask = *sachip->dev->dma_mask;
                dev->dev.dma_mask = &dev->dma_mask;
+               dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
+       }
 
-               if (dev->dma_mask != 0xffffffffUL) {
-                       ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
-                                       sa1111_needs_bounce);
-                       if (ret) {
-                               dev_err(&dev->dev, "SA1111: Failed to register"
-                                       " with dmabounce\n");
-                               device_unregister(&dev->dev);
-                       }
-               }
+       ret = request_resource(parent, &dev->res);
+       if (ret) {
+               dev_err(sachip->dev, "failed to allocate resource for %s\n",
+                       dev->res.name);
+               goto err_resource;
        }
-#endif
 
-out:
+       ret = device_add(&dev->dev);
+       if (ret)
+               goto err_add;
+       return 0;
+
+ err_add:
+       release_resource(&dev->res);
+ err_resource:
+       put_device(&dev->dev);
+ err_alloc:
        return ret;
 }
 
@@ -698,16 +683,21 @@ out:
  *     Returns:
  *     %-ENODEV        device not found.
  *     %-EBUSY         physical address already marked in-use.
+ *     %-EINVAL        no platform data passed
  *     %0              successful.
  */
 static int __devinit
 __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
+       struct sa1111_platform_data *pd = me->platform_data;
        struct sa1111 *sachip;
        unsigned long id;
        unsigned int has_devs;
        int i, ret = -ENODEV;
 
+       if (!pd)
+               return -EINVAL;
+
        sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL);
        if (!sachip)
                return -ENOMEM;
@@ -727,6 +717,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
        sachip->dev = me;
        dev_set_drvdata(sachip->dev, sachip);
 
+       sachip->pdata = pd;
        sachip->phys = mem->start;
        sachip->irq = irq;
 
@@ -759,6 +750,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
         */
        sa1111_wake(sachip);
 
+       /*
+        * The interrupt controller must be initialised before any
+        * other device to ensure that the interrupts are available.
+        */
+       if (sachip->irq != NO_IRQ) {
+               ret = sa1111_setup_irq(sachip, pd->irq_base);
+               if (ret)
+                       goto err_unmap;
+       }
+
 #ifdef CONFIG_ARCH_SA1100
        {
        unsigned int val;
@@ -789,24 +790,14 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
        }
 #endif
 
-       /*
-        * The interrupt controller must be initialised before any
-        * other device to ensure that the interrupts are available.
-        */
-       if (sachip->irq != NO_IRQ)
-               sa1111_setup_irq(sachip);
-
        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);
+       if (pd)
+               has_devs &= ~pd->disable_devs;
 
        for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
-               if (has_devs & (1 << i))
+               if (sa1111_devices[i].devid & has_devs)
                        sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
 
        return 0;
@@ -824,7 +815,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 
 static int sa1111_remove_one(struct device *dev, void *data)
 {
-       device_unregister(dev);
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+       device_del(&sadev->dev);
+       release_resource(&sadev->res);
+       put_device(&sadev->dev);
        return 0;
 }
 
@@ -846,6 +840,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
        if (sachip->irq != NO_IRQ) {
                irq_set_chained_handler(sachip->irq, NULL);
                irq_set_handler_data(sachip->irq, NULL);
+               irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
 
                release_mem_region(sachip->phys + SA1111_INTC, 512);
        }
@@ -904,6 +899,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
        save->skpwm0   = sa1111_readl(base + SA1111_SKPWM0);
        save->skpwm1   = sa1111_readl(base + SA1111_SKPWM1);
 
+       sa1111_writel(0, sachip->base + SA1111_SKPWM0);
+       sa1111_writel(0, sachip->base + SA1111_SKPWM1);
+
        base = sachip->base + SA1111_INTC;
        save->intpol0  = sa1111_readl(base + SA1111_INTPOL0);
        save->intpol1  = sa1111_readl(base + SA1111_INTPOL1);
@@ -919,13 +917,15 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
         */
        val = sa1111_readl(sachip->base + SA1111_SKCR);
        sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
-       sa1111_writel(0, sachip->base + SA1111_SKPWM0);
-       sa1111_writel(0, sachip->base + SA1111_SKPWM1);
 
        clk_disable(sachip->clk);
 
        spin_unlock_irqrestore(&sachip->lock, flags);
 
+#ifdef CONFIG_ARCH_SA1100
+       sa1110_mb_disable();
+#endif
+
        return 0;
 }
 
@@ -966,6 +966,11 @@ static int sa1111_resume(struct platform_device *dev)
         */
        sa1111_wake(sachip);
 
+#ifdef CONFIG_ARCH_SA1100
+       /* Enable the memory bus request/grant signals */
+       sa1110_mb_enable();
+#endif
+
        /*
         * Only lock for write ops. Also, sa1111_wake must be called with
         * released spinlock!
@@ -1053,6 +1058,7 @@ static struct platform_driver sa1111_device_driver = {
        .resume         = sa1111_resume,
        .driver         = {
                .name   = "sa1111",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -1238,16 +1244,23 @@ EXPORT_SYMBOL(sa1111_set_sleep_io);
  *     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)
+int sa1111_enable_device(struct sa1111_dev *sadev)
 {
        struct sa1111 *sachip = sa1111_chip_driver(sadev);
        unsigned long flags;
        unsigned int val;
+       int ret = 0;
 
-       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);
+       if (sachip->pdata && sachip->pdata->enable)
+               ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid);
+
+       if (ret == 0) {
+               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);
+       }
+       return ret;
 }
 EXPORT_SYMBOL(sa1111_enable_device);
 
@@ -1265,6 +1278,9 @@ void sa1111_disable_device(struct sa1111_dev *sadev)
        val = sa1111_readl(sachip->base + SA1111_SKPCR);
        sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
        spin_unlock_irqrestore(&sachip->lock, flags);
+
+       if (sachip->pdata && sachip->pdata->disable)
+               sachip->pdata->disable(sachip->pdata->data, sadev->devid);
 }
 EXPORT_SYMBOL(sa1111_disable_device);
 
@@ -1279,7 +1295,7 @@ 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;
+       return dev->devid & drv->devid;
 }
 
 static int sa1111_bus_suspend(struct device *dev, pm_message_t state)
@@ -1304,6 +1320,14 @@ static int sa1111_bus_resume(struct device *dev)
        return ret;
 }
 
+static void sa1111_bus_shutdown(struct device *dev)
+{
+       struct sa1111_driver *drv = SA1111_DRV(dev->driver);
+
+       if (drv && drv->shutdown)
+               drv->shutdown(SA1111_DEV(dev));
+}
+
 static int sa1111_bus_probe(struct device *dev)
 {
        struct sa1111_dev *sadev = SA1111_DEV(dev);
@@ -1333,6 +1357,7 @@ struct bus_type sa1111_bus_type = {
        .remove         = sa1111_bus_remove,
        .suspend        = sa1111_bus_suspend,
        .resume         = sa1111_bus_resume,
+       .shutdown       = sa1111_bus_shutdown,
 };
 EXPORT_SYMBOL(sa1111_bus_type);
 
@@ -1349,9 +1374,70 @@ void sa1111_driver_unregister(struct sa1111_driver *driver)
 }
 EXPORT_SYMBOL(sa1111_driver_unregister);
 
+#ifdef CONFIG_DMABOUNCE
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
+ * Chip Specification Update" (June 2000), erratum #7, there is a
+ * 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.
+ *
+ * This routine only identifies whether or not a given DMA address
+ * is susceptible to the bug.
+ *
+ * This should only get called for sa1111_device types due to the
+ * way we configure our device dma_masks.
+ */
+static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
+{
+       /*
+        * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
+        * User's Guide" mentions that jumpers R51 and R52 control the
+        * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
+        * SDRAM bank 1 on Neponset). The default configuration selects
+        * Assabet, so any address in bank 1 is necessarily invalid.
+        */
+       return (machine_is_assabet() || machine_is_pfs168()) &&
+               (addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
+}
+
+static int sa1111_notifier_call(struct notifier_block *n, unsigned long action,
+       void *data)
+{
+       struct sa1111_dev *dev = SA1111_DEV(data);
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) {
+                       int ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
+                                       sa1111_needs_bounce);
+                       if (ret)
+                               dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret);
+               }
+               break;
+
+       case BUS_NOTIFY_DEL_DEVICE:
+               if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL)
+                       dmabounce_unregister_dev(&dev->dev);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block sa1111_bus_notifier = {
+       .notifier_call = sa1111_notifier_call,
+};
+#endif
+
 static int __init sa1111_init(void)
 {
        int ret = bus_register(&sa1111_bus_type);
+#ifdef CONFIG_DMABOUNCE
+       if (ret == 0)
+               bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
        if (ret == 0)
                platform_driver_register(&sa1111_device_driver);
        return ret;
@@ -1360,6 +1446,9 @@ static int __init sa1111_init(void)
 static void __exit sa1111_exit(void)
 {
        platform_driver_unregister(&sa1111_device_driver);
+#ifdef CONFIG_DMABOUNCE
+       bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
        bus_unregister(&sa1111_bus_type);
 }
 
index 92ed254..7c2bbc7 100644 (file)
 #define SKPCR_DCLKEN   (1<<7)
 #define SKPCR_PWMCLKEN (1<<8)
 
-/*
- * USB Host controller
- */
+/* USB Host controller */
 #define SA1111_USB             0x0400
 
 /*
- * 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)
-#define USB_RESET_CLKGENRESET  (1 << 2)
-#define USB_RESET_SIMSCALEDOWN (1 << 3)
-#define USB_RESET_USBINTTEST   (1 << 4)
-#define USB_RESET_SLEEPSTBYEN  (1 << 5)
-#define USB_RESET_PWRSENSELOW  (1 << 6)
-#define USB_RESET_PWRCTRLLOW   (1 << 7)
-
-#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
-#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
-#define USB_STATUS_NIRQHCIM       (1 <<  9)
-#define USB_STATUS_NHCIMFCLR      (1 << 10)
-#define USB_STATUS_USBPWRSENSE    (1 << 11)
-
-/*
  * Serial Audio Controller
  *
  * Registers
  *    PC_SSR           GPIO Block C Sleep State
  */
 
-#define _PA_DDR                _SA1111( 0x1000 )
-#define _PA_DRR                _SA1111( 0x1004 )
-#define _PA_DWR                _SA1111( 0x1004 )
-#define _PA_SDR                _SA1111( 0x1008 )
-#define _PA_SSR                _SA1111( 0x100c )
-#define _PB_DDR                _SA1111( 0x1010 )
-#define _PB_DRR                _SA1111( 0x1014 )
-#define _PB_DWR                _SA1111( 0x1014 )
-#define _PB_SDR                _SA1111( 0x1018 )
-#define _PB_SSR                _SA1111( 0x101c )
-#define _PC_DDR                _SA1111( 0x1020 )
-#define _PC_DRR                _SA1111( 0x1024 )
-#define _PC_DWR                _SA1111( 0x1024 )
-#define _PC_SDR                _SA1111( 0x1028 )
-#define _PC_SSR                _SA1111( 0x102c )
-
 #define SA1111_GPIO    0x1000
 
 #define SA1111_GPIO_PADDR      (0x000)
 #define SA1111_WAKEPOL0                0x0034
 #define SA1111_WAKEPOL1                0x0038
 
-/*
- * PS/2 Trackpad and Mouse Interfaces
- *
- * 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
- */
-
+/* PS/2 Trackpad and Mouse Interfaces */
 #define SA1111_KBD             0x0a00
 #define SA1111_MSE             0x0c00
 
-/*
- * These are offsets from the above bases.
- */
-#define SA1111_PS2CR           0x0000
-#define SA1111_PS2STAT         0x0004
-#define SA1111_PS2DATA         0x0008
-#define SA1111_PS2CLKDIV       0x000c
-#define SA1111_PS2PRECNT       0x0010
-
-#define PS2CR_ENA              0x08
-#define PS2CR_FKD              0x02
-#define PS2CR_FKC              0x01
-
-#define PS2STAT_STP            0x0100
-#define PS2STAT_TXE            0x0080
-#define PS2STAT_TXB            0x0040
-#define PS2STAT_RXF            0x0020
-#define PS2STAT_RXB            0x0010
-#define PS2STAT_ENA            0x0008
-#define PS2STAT_RXP            0x0004
-#define PS2STAT_KBD            0x0002
-#define PS2STAT_KBC            0x0001
+/* PCMCIA Interface */
+#define SA1111_PCMCIA          0x1600
 
-/*
- * PCMCIA Interface
- *
- * Registers
- *    PCSR     Status Register
- *    PCCR     Control Register
- *    PCSSR    Sleep State Register
- */
-
-#define SA1111_PCMCIA  0x1600
-
-/*
- * 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 PCSR_S0_DETECT (1<<2)
-#define PCSR_S1_DETECT (1<<3)
-#define PCSR_S0_VS1    (1<<4)
-#define PCSR_S0_VS2    (1<<5)
-#define PCSR_S1_VS1    (1<<6)
-#define PCSR_S1_VS2    (1<<7)
-#define PCSR_S0_WP     (1<<8)
-#define PCSR_S1_WP     (1<<9)
-#define PCSR_S0_BVD1   (1<<10)
-#define PCSR_S0_BVD2   (1<<11)
-#define PCSR_S1_BVD1   (1<<12)
-#define PCSR_S1_BVD2   (1<<13)
-
-#define PCCR_S0_RST    (1<<0)
-#define PCCR_S1_RST    (1<<1)
-#define PCCR_S0_FLT    (1<<2)
-#define PCCR_S1_FLT    (1<<3)
-#define PCCR_S0_PWAITEN        (1<<4)
-#define PCCR_S1_PWAITEN        (1<<5)
-#define PCCR_S0_PSE    (1<<6)
-#define PCCR_S1_PSE    (1<<7)
-
-#define PCSSR_S0_SLEEP (1<<0)
-#define PCSSR_S1_SLEEP (1<<1)
 
 
 
 
 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
+#define SA1111_DEVID_SBI       (1 << 0)
+#define SA1111_DEVID_SK                (1 << 1)
+#define SA1111_DEVID_USB       (1 << 2)
+#define SA1111_DEVID_SAC       (1 << 3)
+#define SA1111_DEVID_SSP       (1 << 4)
+#define SA1111_DEVID_PS2       (3 << 5)
+#define SA1111_DEVID_PS2_KBD   (1 << 5)
+#define SA1111_DEVID_PS2_MSE   (1 << 6)
+#define SA1111_DEVID_GPIO      (1 << 7)
+#define SA1111_DEVID_INT       (1 << 8)
+#define SA1111_DEVID_PCMCIA    (1 << 9)
 
 struct sa1111_dev {
        struct device   dev;
@@ -548,6 +432,7 @@ struct sa1111_driver {
        int (*remove)(struct sa1111_dev *);
        int (*suspend)(struct sa1111_dev *, pm_message_t);
        int (*resume)(struct sa1111_dev *);
+       void (*shutdown)(struct sa1111_dev *);
 };
 
 #define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
@@ -555,9 +440,10 @@ struct sa1111_driver {
 #define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
 
 /*
- * These frob the SKPCR register.
+ * These frob the SKPCR register, and call platform specific
+ * enable/disable functions.
  */
-void sa1111_enable_device(struct sa1111_dev *);
+int sa1111_enable_device(struct sa1111_dev *);
 void sa1111_disable_device(struct sa1111_dev *);
 
 unsigned int sa1111_pll_clock(struct sa1111_dev *);
@@ -580,6 +466,10 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i
 
 struct sa1111_platform_data {
        int     irq_base;       /* base for cascaded on-chip IRQs */
+       unsigned disable_devs;
+       void    *data;
+       int     (*enable)(void *, unsigned);
+       void    (*disable)(void *, unsigned);
 };
 
 #endif  /* _ASM_ARCH_SA1111 */
index 294aad0..6235efb 100644 (file)
 
 #include <asm/mach/time.h>
 
-#define IRQ_MASK               0xfe000000      /* read */
-#define IRQ_MSET               0xfe000000      /* write */
-#define IRQ_STAT               0xff000000      /* read */
-#define IRQ_MCLR               0xff000000      /* write */
+#include "core.h"
 
 static void ebsa110_mask_irq(struct irq_data *d)
 {
@@ -79,22 +76,22 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
        {       /* IRQ_STAT/IRQ_MCLR */
                .virtual        = IRQ_STAT,
                .pfn            = __phys_to_pfn(TRICK4_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK4_SIZE,
                .type           = MT_DEVICE
        }, {    /* IRQ_MASK/IRQ_MSET */
                .virtual        = IRQ_MASK,
                .pfn            = __phys_to_pfn(TRICK3_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK3_SIZE,
                .type           = MT_DEVICE
        }, {    /* SOFT_BASE */
                .virtual        = SOFT_BASE,
                .pfn            = __phys_to_pfn(TRICK1_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK1_SIZE,
                .type           = MT_DEVICE
        }, {    /* PIT_BASE */
                .virtual        = PIT_BASE,
                .pfn            = __phys_to_pfn(TRICK0_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK0_SIZE,
                .type           = MT_DEVICE
        },
 
diff --git a/arch/arm/mach-ebsa110/core.h b/arch/arm/mach-ebsa110/core.h
new file mode 100644 (file)
index 0000000..c93c9e4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 1996-2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the core hardware definitions of the EBSA-110.
+ */
+#ifndef CORE_H
+#define CORE_H
+
+/* Physical addresses/sizes */
+#define ISAMEM_PHYS            0xe0000000
+#define ISAMEM_SIZE            0x10000000
+
+#define ISAIO_PHYS             0xf0000000
+#define ISAIO_SIZE             PGDIR_SIZE
+
+#define TRICK0_PHYS            0xf2000000
+#define TRICK0_SIZE            PGDIR_SIZE
+#define TRICK1_PHYS            0xf2400000
+#define TRICK1_SIZE            PGDIR_SIZE
+#define TRICK2_PHYS            0xf2800000
+#define TRICK3_PHYS            0xf2c00000
+#define TRICK3_SIZE            PGDIR_SIZE
+#define TRICK4_PHYS            0xf3000000
+#define TRICK4_SIZE            PGDIR_SIZE
+#define TRICK5_PHYS            0xf3400000
+#define TRICK6_PHYS            0xf3800000
+#define TRICK7_PHYS            0xf3c00000
+
+/* Virtual addresses */
+#define PIT_BASE               0xfc000000      /* trick 0 */
+#define SOFT_BASE              0xfd000000      /* trick 1 */
+#define IRQ_MASK               0xfe000000      /* trick 3 - read */
+#define IRQ_MSET               0xfe000000      /* trick 3 - write */
+#define IRQ_STAT               0xff000000      /* trick 4 - read */
+#define IRQ_MCLR               0xff000000      /* trick 4 - write */
+
+#endif
index 4b2fb77..f4e5407 100644 (file)
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-/*
- * The EBSA110 has a weird "ISA IO" region:
- *
- * Region 0 (addr = 0xf0000000 + io << 2)
- * --------------------------------------------------------
- * Physical region     IO region
- * f0000fe0 - f0000ffc 3f8 - 3ff  ttyS0
- * f0000e60 - f0000e64 398 - 399
- * f0000de0 - f0000dfc 378 - 37f  lp0
- * f0000be0 - f0000bfc 2f8 - 2ff  ttyS1
- *
- * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
- * --------------------------------------------------------
- * Physical region     IO region
- * f00014f1             a79        pnp write data
- * f00007c0 - f00007c1 3e0 - 3e1  pcmcia
- * f00004f1            279        pnp address
- * f0000440 - f000046c  220 - 236  eth0
- * f0000405            203        pnp read data
- */
-
-#define ISAMEM_PHYS            0xe0000000
-#define ISAMEM_SIZE            0x10000000
-
-#define ISAIO_PHYS             0xf0000000
-#define ISAIO_SIZE             PGDIR_SIZE
-
-#define TRICK0_PHYS            0xf2000000
-#define TRICK1_PHYS            0xf2400000
-#define TRICK2_PHYS            0xf2800000
-#define TRICK3_PHYS            0xf2c00000
-#define TRICK4_PHYS            0xf3000000
-#define TRICK5_PHYS            0xf3400000
-#define TRICK6_PHYS            0xf3800000
-#define TRICK7_PHYS            0xf3c00000
-
 #define ISAMEM_BASE            0xe0000000
 #define ISAIO_BASE             0xf0000000
 
-#define PIT_BASE               0xfc000000
-#define SOFT_BASE              0xfd000000
-
 /*
  * RAM definitions
  */
index c52e304..756cc37 100644 (file)
@@ -177,6 +177,26 @@ void writesl(void __iomem *addr, const void *data, int len)
 }
 EXPORT_SYMBOL(writesl);
 
+/*
+ * The EBSA110 has a weird "ISA IO" region:
+ *
+ * Region 0 (addr = 0xf0000000 + io << 2)
+ * --------------------------------------------------------
+ * Physical region     IO region
+ * f0000fe0 - f0000ffc 3f8 - 3ff  ttyS0
+ * f0000e60 - f0000e64 398 - 399
+ * f0000de0 - f0000dfc 378 - 37f  lp0
+ * f0000be0 - f0000bfc 2f8 - 2ff  ttyS1
+ *
+ * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
+ * --------------------------------------------------------
+ * Physical region     IO region
+ * f00014f1             a79        pnp write data
+ * f00007c0 - f00007c1 3e0 - 3e1  pcmcia
+ * f00004f1            279        pnp address
+ * f0000440 - f000046c  220 - 236  eth0
+ * f0000405            203        pnp read data
+ */
 #define SUPERIO_PORT(p) \
        (((p) >> 3) == (0x3f8 >> 3) || \
         ((p) >> 3) == (0x2f8 >> 3) || \
index 6a6ea57..d43121a 100644 (file)
@@ -20,6 +20,8 @@
 #include <asm/system.h>
 #include <asm/mach-types.h>
 
+#include "core.h"
+
 static spinlock_t leds_lock;
 
 static void ebsa110_leds_event(led_event_t ledevt)
index 6ebd276..6bb3f47 100644 (file)
@@ -223,6 +223,7 @@ static struct resource sa1111_resources[] = {
 
 static struct sa1111_platform_data sa1111_info = {
        .irq_base       = LUBBOCK_SA1111_IRQ_BASE,
+       .disable_devs   = SA1111_DEVID_SAC,
 };
 
 static struct platform_device sa1111_device = {
index ed7408d..60b97ec 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o
+obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
index 0c4b76a..375d3f7 100644 (file)
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/serial_core.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/mach/serial_sa1100.h>
 #include <mach/assabet.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 #define ASSABET_BCR_DB1110 \
-       (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+       (ASSABET_BCR_SPK_OFF    | \
         ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
         ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
         ASSABET_BCR_IRDA_MD0)
 
 #define ASSABET_BCR_DB1111 \
-       (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+       (ASSABET_BCR_SPK_OFF    | \
         ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
         ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
         ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
@@ -69,31 +72,10 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
 
 EXPORT_SYMBOL(ASSABET_BCR_frob);
 
-static void assabet_backlight_power(int on)
-{
-#ifndef ASSABET_PAL_VIDEO
-       if (on)
-               ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
-       else
-#endif
-               ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
-}
-
-/*
- * Turn on/off the backlight.  When turning the backlight on,
- * we wait 500us after turning it on so we don't cause the
- * supplies to droop when we enable the LCD controller (and
- * cause a hard reset.)
- */
-static void assabet_lcd_power(int on)
+static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
 {
-#ifndef ASSABET_PAL_VIDEO
-       if (on) {
-               ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
-               udelay(500);
-       } else
-#endif
-               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+       if (state == UCB_RST_PROBE)
+               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
 }
 
 
@@ -152,15 +134,8 @@ static struct flash_platform_data assabet_flash_data = {
 };
 
 static struct resource assabet_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = SA1100_CS1_PHYS,
-               .end    = SA1100_CS1_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 
@@ -199,18 +174,126 @@ static struct irda_platform_data assabet_irda_data = {
        .set_speed      = assabet_irda_set_speed,
 };
 
+static struct ucb1x00_plat_data assabet_ucb1x00_data = {
+       .reset          = assabet_ucb1x00_reset,
+       .gpio_base      = -1,
+};
+
 static struct mcp_plat_data assabet_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec_pdata    = &assabet_ucb1x00_data,
+};
+
+static void assabet_lcd_set_visual(u32 visual)
+{
+       u_int is_true_color = visual == FB_VISUAL_TRUECOLOR;
+
+       if (machine_is_assabet()) {
+#if 1          // phase 4 or newer Assabet's
+               if (is_true_color)
+                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+               else
+                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+#else
+               // older Assabet's
+               if (is_true_color)
+                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+               else
+                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+#endif
+       }
+}
+
+#ifndef ASSABET_PAL_VIDEO
+static void assabet_lcd_backlight_power(int on)
+{
+       if (on)
+               ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
+       else
+               ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+/*
+ * Turn on/off the backlight.  When turning the backlight on, we wait
+ * 500us after turning it on so we don't cause the supplies to droop
+ * when we enable the LCD controller (and cause a hard reset.)
+ */
+static void assabet_lcd_power(int on)
+{
+       if (on) {
+               ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
+               udelay(500);
+       } else
+               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+/*
+ * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
+ * takes an RGB666 signal, but we provide it with an RGB565 signal
+ * instead (def_rgb_16).
+ */
+static struct sa1100fb_mach_info lq039q2ds54_info = {
+       .pixclock       = 171521,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 5,            .vsync_len      = 1,
+       .left_margin    = 61,           .upper_margin   = 3,
+       .right_margin   = 9,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .backlight_power = assabet_lcd_backlight_power,
+       .lcd_power = assabet_lcd_power,
+       .set_visual = assabet_lcd_set_visual,
+};
+#else
+static void assabet_pal_backlight_power(int on)
+{
+       ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+static void assabet_pal_power(int on)
+{
+       ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+static struct sa1100fb_mach_info pal_info = {
+       .pixclock       = 67797,        .bpp            = 16,
+       .xres           = 640,          .yres           = 512,
+
+       .hsync_len      = 64,           .vsync_len      = 6,
+       .left_margin    = 125,          .upper_margin   = 70,
+       .right_margin   = 115,          .lower_margin   = 36,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+
+       .backlight_power = assabet_pal_backlight_power,
+       .lcd_power = assabet_pal_power,
+       .set_visual = assabet_lcd_set_visual,
 };
+#endif
+
+#ifdef CONFIG_ASSABET_NEPONSET
+static struct resource neponset_resources[] = {
+       DEFINE_RES_MEM(0x10000000, 0x08000000),
+       DEFINE_RES_MEM(0x18000000, 0x04000000),
+       DEFINE_RES_MEM(0x40000000, SZ_8K),
+       DEFINE_RES_IRQ(IRQ_GPIO25),
+};
+#endif
 
 static void __init assabet_init(void)
 {
        /*
         * Ensure that the power supply is in "high power" mode.
         */
-       GPDR |= GPIO_GPIO16;
        GPSR = GPIO_GPIO16;
+       GPDR |= GPIO_GPIO16;
 
        /*
         * Ensure that these pins are set as outputs and are driving
@@ -218,8 +301,16 @@ static void __init assabet_init(void)
         * the WS latch in the CPLD, and we don't float causing
         * excessive power drain.  --rmk
         */
-       GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
        GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+       GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+
+       /*
+        * Also set GPIO27 as an output; this is used to clock UART3
+        * via the FPGA and as otherwise has no pullups or pulldowns,
+        * so stop it floating.
+        */
+       GPCR = GPIO_GPIO27;
+       GPDR |= GPIO_GPIO27;
 
        /*
         * Set up registers for sleep mode.
@@ -231,8 +322,7 @@ static void __init assabet_init(void)
        PPDR |= PPC_TXD3 | PPC_TXD1;
        PPSR |= PPC_TXD3 | PPC_TXD1;
 
-       sa1100fb_lcd_power = assabet_lcd_power;
-       sa1100fb_backlight_power = assabet_backlight_power;
+       sa11x0_ppc_configure_mcp();
 
        if (machine_has_neponset()) {
                /*
@@ -246,9 +336,17 @@ static void __init assabet_init(void)
 #ifndef CONFIG_ASSABET_NEPONSET
                printk( "Warning: Neponset detected but full support "
                        "hasn't been configured in the kernel\n" );
+#else
+               platform_device_register_simple("neponset", 0,
+                       neponset_resources, ARRAY_SIZE(neponset_resources));
 #endif
        }
 
+#ifndef ASSABET_PAL_VIDEO
+       sa11x0_register_lcd(&lq039q2ds54_info);
+#else
+       sa11x0_register_lcd(&pal_video);
+#endif
        sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
                            ARRAY_SIZE(assabet_flash_resources));
        sa11x0_register_irda(&assabet_irda_data);
@@ -412,21 +510,8 @@ static void __init assabet_map_io(void)
         */
        Ser1SDCR0 |= SDCR0_SUS;
 
-       if (machine_has_neponset()) {
-#ifdef CONFIG_ASSABET_NEPONSET
-               extern void neponset_map_io(void);
-
-               /*
-                * We map Neponset registers even if it isn't present since
-                * many drivers will try to probe their stuff (and fail).
-                * This is still more friendly than a kernel paging request
-                * crash.
-                */
-               neponset_map_io();
-#endif
-       } else {
+       if (!machine_has_neponset())
                sa1100_register_uart_fns(&assabet_port_fns);
-       }
 
        /*
         * When Neponset is attached, the first UART should be
@@ -449,6 +534,7 @@ MACHINE_START(ASSABET, "Intel-Assabet")
        .atag_offset    = 0x100,
        .fixup          = fixup_assabet,
        .map_io         = assabet_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = assabet_init,
index b07a2c0..e0f0c03 100644 (file)
 #include "generic.h"
 
 static struct resource sa1111_resources[] = {
-       [0] = {
-               .start          = BADGE4_SA1111_BASE,
-               .end            = BADGE4_SA1111_BASE + 0x00001fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = BADGE4_IRQ_GPIO_SA1111,
-               .end            = BADGE4_IRQ_GPIO_SA1111,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(BADGE4_SA1111_BASE, 0x2000),
+       [1] = DEFINE_RES_IRQ(BADGE4_IRQ_GPIO_SA1111),
 };
 
+static int badge4_sa1111_enable(void *data, unsigned devid)
+{
+       if (devid == SA1111_DEVID_USB)
+               badge4_set_5V(BADGE4_5V_USB, 1);
+       return 0;
+}
+
+static void badge4_sa1111_disable(void *data, unsigned devid)
+{
+       if (devid == SA1111_DEVID_USB)
+               badge4_set_5V(BADGE4_5V_USB, 0);
+}
+
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
+       .enable         = badge4_sa1111_enable,
+       .disable        = badge4_sa1111_disable,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -121,11 +128,8 @@ static struct flash_platform_data badge4_flash_data = {
        .nr_parts       = ARRAY_SIZE(badge4_partitions),
 };
 
-static struct resource badge4_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_64M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource badge4_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_64M);
 
 static int five_v_on __initdata = 0;
 
@@ -269,11 +273,6 @@ static struct map_desc badge4_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(0x10000000),
                .length         = 0x00100000,
                .type           = MT_DEVICE
-       }, {    /* SA-1111      */
-               .virtual        = 0xf4000000,
-               .pfn            = __phys_to_pfn(0x48000000),
-               .length         = 0x00100000,
-               .type           = MT_DEVICE
        }
 };
 
@@ -304,6 +303,7 @@ static void __init badge4_map_io(void)
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
        .atag_offset    = 0x100,
        .map_io         = badge4_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
 #ifdef CONFIG_SA1111
index 11bb6d0..4a61f60 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
 
 #include <mach/cerf.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
-       [0] = {
-               .start  = 0x80030000,
-               .end    = 0x8003ffff,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(0x80030000, SZ_64K),
 };
 
 static struct platform_device cerfuart2_device = {
@@ -87,11 +83,8 @@ static struct flash_platform_data cerf_flash_data = {
        .nr_parts       = ARRAY_SIZE(cerf_partitions),
 };
 
-static struct resource cerf_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource cerf_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init cerf_init_irq(void)
 {
@@ -128,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = {
 
 static void __init cerf_init(void)
 {
+       sa11x0_ppc_configure_mcp();
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
        sa11x0_register_mcp(&cerf_mcp_data);
@@ -136,6 +130,7 @@ static void __init cerf_init(void)
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
        /* Maintainer: support@intrinsyc.com */
        .map_io         = cerf_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = cerf_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = cerf_init,
index fd56521..48885b7 100644 (file)
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <mach/collie.h>
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 static struct resource collie_scoop_resources[] = {
-       [0] = {
-               .start          = 0x40800000,
-               .end            = 0x40800fff,
-               .flags          = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
 };
 
 static struct scoop_config collie_scoop_setup = {
@@ -85,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
        .num_devs       = 1,
 };
 
+static struct ucb1x00_plat_data collie_ucb1x00_data = {
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+};
+
 static struct mcp_plat_data collie_mcp_data = {
        .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
        .sclk_rate      = 9216000,
-       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+       .codec_pdata    = &collie_ucb1x00_data,
 };
 
 /*
@@ -221,16 +224,8 @@ device_initcall(collie_uart_init);
 
 
 static struct resource locomo_resources[] = {
-       [0] = {
-               .start          = 0x40000000,
-               .end            = 0x40001fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = IRQ_GPIO25,
-               .end            = IRQ_GPIO25,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO25),
 };
 
 static struct locomo_platform_data locomo_info = {
@@ -303,11 +298,21 @@ static struct flash_platform_data collie_flash_data = {
 };
 
 static struct resource collie_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+};
+
+static struct sa1100fb_mach_info collie_lcd_info = {
+       .pixclock       = 171521,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 5,            .vsync_len      = 1,
+       .left_margin    = 11,           .upper_margin   = 2,
+       .right_margin   = 30,           .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 
 static void __init collie_init(void)
@@ -341,6 +346,10 @@ static void __init collie_init(void)
 
        collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
        collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
+
+       sa11x0_ppc_configure_mcp();
+
+
        platform_scoop_config = &collie_pcmcia_config;
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -348,6 +357,7 @@ static void __init collie_init(void)
                printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
        }
 
+       sa11x0_register_lcd(&collie_lcd_info);
        sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
                            ARRAY_SIZE(collie_flash_resources));
        sa11x0_register_mcp(&collie_mcp_data);
@@ -383,6 +393,7 @@ static void __init collie_map_io(void)
 
 MACHINE_START(COLLIE, "Sharp-Collie")
        .map_io         = collie_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = collie_init,
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
deleted file mode 100644 (file)
index ad66035..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * arch/arm/mach-sa1100/dma.c
- *
- * Support functions for the SA11x0 internal DMA channels.
- *
- * Copyright (C) 2000, 2001 by Nicolas Pitre
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK( s, arg... )  printk( "dma<%p>: " s, regs , ##arg )
-#else
-#define DPRINTK( x... )
-#endif
-
-
-typedef struct {
-       const char *device_id;          /* device name */
-       u_long device;                  /* this channel device, 0  if unused*/
-       dma_callback_t callback;        /* to call when DMA completes */
-       void *data;                     /* ... with private data ptr */
-} sa1100_dma_t;
-
-static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
-
-static DEFINE_SPINLOCK(dma_list_lock);
-
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-       dma_regs_t *dma_regs = dev_id;
-       sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
-       int status = dma_regs->RdDCSR;
-
-       if (status & (DCSR_ERROR)) {
-               printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
-               dma_regs->ClrDCSR = DCSR_ERROR;
-       }
-
-       dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
-       if (dma->callback) {
-               if (status & DCSR_DONEA)
-                       dma->callback(dma->data);
-               if (status & DCSR_DONEB)
-                       dma->callback(dma->data);
-       }
-       return IRQ_HANDLED;
-}
-
-
-/**
- *     sa1100_request_dma - allocate one of the SA11x0's DMA channels
- *     @device: The SA11x0 peripheral targeted by this request
- *     @device_id: An ascii name for the claiming device
- *     @callback: Function to be called when the DMA completes
- *     @data: A cookie passed back to the callback function
- *     @dma_regs: Pointer to the location of the allocated channel's identifier
- *
- *     This function will search for a free DMA channel and returns the
- *     address of the hardware registers for that channel as the channel
- *     identifier. This identifier is written to the location pointed by
- *     @dma_regs. The list of possible values for @device are listed into
- *     arch/arm/mach-sa1100/include/mach/dma.h as a dma_device_t enum.
- *
- *     Note that reading from a port and writing to the same port are
- *     actually considered as two different streams requiring separate
- *     DMA registrations.
- *
- *     The @callback function is called from interrupt context when one
- *     of the two possible DMA buffers in flight has terminated. That
- *     function has to be small and efficient while posponing more complex
- *     processing to a lower priority execution context.
- *
- *     If no channels are available, or if the desired @device is already in
- *     use by another DMA channel, then an error code is returned.  This
- *     function must be called before any other DMA calls.
- **/
-
-int sa1100_request_dma (dma_device_t device, const char *device_id,
-                       dma_callback_t callback, void *data,
-                       dma_regs_t **dma_regs)
-{
-       sa1100_dma_t *dma = NULL;
-       dma_regs_t *regs;
-       int i, err;
-
-       *dma_regs = NULL;
-
-       err = 0;
-       spin_lock(&dma_list_lock);
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
-               if (dma_chan[i].device == device) {
-                       err = -EBUSY;
-                       break;
-               } else if (!dma_chan[i].device && !dma) {
-                       dma = &dma_chan[i];
-               }
-       }
-       if (!err) {
-               if (dma)
-                       dma->device = device;
-               else
-                       err = -ENOSR;
-       }
-       spin_unlock(&dma_list_lock);
-       if (err)
-               return err;
-
-       i = dma - dma_chan;
-       regs = (dma_regs_t *)&DDAR(i);
-       err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED,
-                         device_id, regs);
-       if (err) {
-               printk(KERN_ERR
-                      "%s: unable to request IRQ %d for %s\n",
-                      __func__, IRQ_DMA0 + i, device_id);
-               dma->device = 0;
-               return err;
-       }
-
-       *dma_regs = regs;
-       dma->device_id = device_id;
-       dma->callback = callback;
-       dma->data = data;
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       regs->DDAR = device;
-
-       return 0;
-}
-
-
-/**
- *     sa1100_free_dma - free a SA11x0 DMA channel
- *     @regs: identifier for the channel to free
- *
- *     This clears all activities on a given DMA channel and releases it
- *     for future requests.  The @regs identifier is provided by a
- *     successful call to sa1100_request_dma().
- **/
-
-void sa1100_free_dma(dma_regs_t *regs)
-{
-       int i;
-
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-               if (regs == (dma_regs_t *)&DDAR(i))
-                       break;
-       if (i >= SA1100_DMA_CHANNELS) {
-               printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-               return;
-       }
-
-       if (!dma_chan[i].device) {
-               printk(KERN_ERR "%s: Trying to free free DMA\n", __func__);
-               return;
-       }
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       free_irq(IRQ_DMA0 + i, regs);
-       dma_chan[i].device = 0;
-}
-
-
-/**
- *     sa1100_start_dma - submit a data buffer for DMA
- *     @regs: identifier for the channel to use
- *     @dma_ptr: buffer physical (or bus) start address
- *     @size: buffer size
- *
- *     This function hands the given data buffer to the hardware for DMA
- *     access. If another buffer is already in flight then this buffer
- *     will be queued so the DMA engine will switch to it automatically
- *     when the previous one is done.  The DMA engine is actually toggling
- *     between two buffers so at most 2 successful calls can be made before
- *     one of them terminates and the callback function is called.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- *
- *     The @size must not be larger than %MAX_DMA_SIZE.  If a given buffer
- *     is larger than that then it's the caller's responsibility to split
- *     it into smaller chunks and submit them separately. If this is the
- *     case then a @size of %CUT_DMA_SIZE is recommended to avoid ending
- *     up with too small chunks. The callback function can be used to chain
- *     submissions of buffer chunks.
- *
- *     Error return values:
- *     %-EOVERFLOW:    Given buffer size is too big.
- *     %-EBUSY:        Both DMA buffers are already in use.
- *     %-EAGAIN:       Both buffers were busy but one of them just completed
- *                     but the interrupt handler has to execute first.
- *
- *     This function returs 0 on success.
- **/
-
-int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
-{
-       unsigned long flags;
-       u_long status;
-       int ret;
-
-       if (dma_ptr & 3)
-               printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
-                      (unsigned long)dma_ptr);
-
-       if (size > MAX_DMA_SIZE)
-               return -EOVERFLOW;
-
-       local_irq_save(flags);
-       status = regs->RdDCSR;
-
-       /* If both DMA buffers are started, there's nothing else we can do. */
-       if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
-               DPRINTK("start: st %#x busy\n", status);
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
-           (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
-               if (status & DCSR_DONEA) {
-                       /* give a chance for the interrupt to be processed */
-                       ret = -EAGAIN;
-                       goto out;
-               }
-               regs->DBSA = dma_ptr;
-               regs->DBTA = size;
-               regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
-               DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
-       } else {
-               if (status & DCSR_DONEB) {
-                       /* give a chance for the interrupt to be processed */
-                       ret = -EAGAIN;
-                       goto out;
-               }
-               regs->DBSB = dma_ptr;
-               regs->DBTB = size;
-               regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
-               DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
-       }
-       ret = 0;
-
-out:
-       local_irq_restore(flags);
-       return ret;
-}
-
-
-/**
- *     sa1100_get_dma_pos - return current DMA position
- *     @regs: identifier for the channel to use
- *
- *     This function returns the current physical (or bus) address for the
- *     given DMA channel.  If the channel is running i.e. not in a stopped
- *     state then the caller must disable interrupts prior calling this
- *     function and process the returned value before re-enabling them to
- *     prevent races with the completion interrupt handler and the callback
- *     function. The validation of the returned value is the caller's
- *     responsibility as well -- the hardware seems to return out of range
- *     values when the DMA engine completes a buffer.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
-{
-       int status;
-
-       /*
-        * We must determine whether buffer A or B is active.
-        * Two possibilities: either we are in the middle of
-        * a buffer, or the DMA controller just switched to the
-        * next toggle but the interrupt hasn't been serviced yet.
-        * The former case is straight forward.  In the later case,
-        * we'll do like if DMA is just at the end of the previous
-        * toggle since all registers haven't been reset yet.
-        * This goes around the edge case and since we're always
-        * a little behind anyways it shouldn't make a big difference.
-        * If DMA has been stopped prior calling this then the
-        * position is exact.
-        */
-       status = regs->RdDCSR;
-       if ((!(status & DCSR_BIU) &&  (status & DCSR_STRTA)) ||
-           ( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
-               return regs->DBSA;
-       else
-               return regs->DBSB;
-}
-
-
-/**
- *     sa1100_reset_dma - reset a DMA channel
- *     @regs: identifier for the channel to use
- *
- *     This function resets and reconfigure the given DMA channel. This is
- *     particularly useful after a sleep/wakeup event.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-void sa1100_reset_dma(dma_regs_t *regs)
-{
-       int i;
-
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-               if (regs == (dma_regs_t *)&DDAR(i))
-                       break;
-       if (i >= SA1100_DMA_CHANNELS) {
-               printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-               return;
-       }
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       regs->DDAR = dma_chan[i].device;
-}
-
-
-EXPORT_SYMBOL(sa1100_request_dma);
-EXPORT_SYMBOL(sa1100_free_dma);
-EXPORT_SYMBOL(sa1100_start_dma);
-EXPORT_SYMBOL(sa1100_get_dma_pos);
-EXPORT_SYMBOL(sa1100_reset_dma);
-
index bb10ee2..b184704 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/div64.h>
-#include <mach/hardware.h>
 #include <asm/system.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 #include <asm/irq.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 unsigned int reset_status;
@@ -149,16 +154,8 @@ static void sa11x0_register_device(struct platform_device *dev, void *data)
 
 
 static struct resource sa11x0udc_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser0UDCCR),
-               .end    = __PREG(Ser0UDCCR) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser0UDC,
-               .end    = IRQ_Ser0UDC,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser0UDC),
 };
 
 static u64 sa11x0udc_dma_mask = 0xffffffffUL;
@@ -175,16 +172,8 @@ static struct platform_device sa11x0udc_device = {
 };
 
 static struct resource sa11x0uart1_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser1UTCR0),
-               .end    = __PREG(Ser1UTCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser1UART,
-               .end    = IRQ_Ser1UART,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser1UART),
 };
 
 static struct platform_device sa11x0uart1_device = {
@@ -195,16 +184,8 @@ static struct platform_device sa11x0uart1_device = {
 };
 
 static struct resource sa11x0uart3_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser3UTCR0),
-               .end    = __PREG(Ser3UTCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser3UART,
-               .end    = IRQ_Ser3UART,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser3UART),
 };
 
 static struct platform_device sa11x0uart3_device = {
@@ -215,16 +196,9 @@ static struct platform_device sa11x0uart3_device = {
 };
 
 static struct resource sa11x0mcp_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser4MCCR0),
-               .end    = __PREG(Ser4MCCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser4MCP,
-               .end    = IRQ_Ser4MCP,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
+       [1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
+       [2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
 };
 
 static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
@@ -240,22 +214,24 @@ static struct platform_device sa11x0mcp_device = {
        .resource       = sa11x0mcp_resources,
 };
 
+void __init sa11x0_ppc_configure_mcp(void)
+{
+       /* Setup the PPC unit for the MCP */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+}
+
 void sa11x0_register_mcp(struct mcp_plat_data *data)
 {
        sa11x0_register_device(&sa11x0mcp_device, data);
 }
 
 static struct resource sa11x0ssp_resources[] = {
-       [0] = {
-               .start  = 0x80070000,
-               .end    = 0x8007ffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser4SSP,
-               .end    = IRQ_Ser4SSP,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0x80070000, SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser4SSP),
 };
 
 static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
@@ -272,16 +248,8 @@ static struct platform_device sa11x0ssp_device = {
 };
 
 static struct resource sa11x0fb_resources[] = {
-       [0] = {
-               .start  = 0xb0100000,
-               .end    = 0xb010ffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_LCD,
-               .end    = IRQ_LCD,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0xb0100000, SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_LCD),
 };
 
 static struct platform_device sa11x0fb_device = {
@@ -294,6 +262,11 @@ static struct platform_device sa11x0fb_device = {
        .resource       = sa11x0fb_resources,
 };
 
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
+{
+       sa11x0_register_device(&sa11x0fb_device, inf);
+}
+
 static struct platform_device sa11x0pcmcia_device = {
        .name           = "sa11x0-pcmcia",
        .id             = -1,
@@ -314,23 +287,10 @@ void sa11x0_register_mtd(struct flash_platform_data *flash,
 }
 
 static struct resource sa11x0ir_resources[] = {
-       {
-               .start  = __PREG(Ser2UTCR0),
-               .end    = __PREG(Ser2UTCR0) + 0x24 - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = __PREG(Ser2HSCR0),
-               .end    = __PREG(Ser2HSCR0) + 0x1c - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = __PREG(Ser2HSCR2),
-               .end    = __PREG(Ser2HSCR2) + 0x04 - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_Ser2ICP,
-               .end    = IRQ_Ser2ICP,
-               .flags  = IORESOURCE_IRQ,
-       }
+       DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24),
+       DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c),
+       DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04),
+       DEFINE_RES_IRQ(IRQ_Ser2ICP),
 };
 
 static struct platform_device sa11x0ir_device = {
@@ -350,14 +310,37 @@ static struct platform_device sa11x0rtc_device = {
        .id             = -1,
 };
 
+static struct resource sa11x0dma_resources[] = {
+       DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
+       DEFINE_RES_IRQ(IRQ_DMA0),
+       DEFINE_RES_IRQ(IRQ_DMA1),
+       DEFINE_RES_IRQ(IRQ_DMA2),
+       DEFINE_RES_IRQ(IRQ_DMA3),
+       DEFINE_RES_IRQ(IRQ_DMA4),
+       DEFINE_RES_IRQ(IRQ_DMA5),
+};
+
+static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device sa11x0dma_device = {
+       .name           = "sa11x0-dma",
+       .id             = -1,
+       .dev = {
+               .dma_mask = &sa11x0dma_dma_mask,
+               .coherent_dma_mask = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(sa11x0dma_resources),
+       .resource       = sa11x0dma_resources,
+};
+
 static struct platform_device *sa11x0_devices[] __initdata = {
        &sa11x0udc_device,
        &sa11x0uart1_device,
        &sa11x0uart3_device,
        &sa11x0ssp_device,
        &sa11x0pcmcia_device,
-       &sa11x0fb_device,
        &sa11x0rtc_device,
+       &sa11x0dma_device,
 };
 
 static int __init sa1100_init(void)
@@ -368,12 +351,6 @@ static int __init sa1100_init(void)
 
 arch_initcall(sa1100_init);
 
-void (*sa1100fb_backlight_power)(int on);
-void (*sa1100fb_lcd_power)(int on);
-
-EXPORT_SYMBOL(sa1100fb_backlight_power);
-EXPORT_SYMBOL(sa1100fb_lcd_power);
-
 
 /*
  * Common I/O mapping:
@@ -428,7 +405,7 @@ void __init sa1100_map_io(void)
  * the MBGNT signal false to ensure the SA1111 doesn't own the
  * SDRAM bus.
  */
-void __init sa1110_mb_disable(void)
+void sa1110_mb_disable(void)
 {
        unsigned long flags;
 
@@ -447,7 +424,7 @@ void __init sa1110_mb_disable(void)
  * If the system is going to use the SA-1111 DMA engines, set up
  * the memory bus request/grant pins.
  */
-void __devinit sa1110_mb_enable(void)
+void sa1110_mb_enable(void)
 {
        unsigned long flags;
 
index 33268cf..9eb3b3c 100644 (file)
@@ -16,9 +16,6 @@ extern void sa11x0_restart(char, const char *);
        mi->bank[__nr].start = (__start), \
        mi->bank[__nr].size = (__size)
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
 extern void sa1110_mb_enable(void);
 extern void sa1110_mb_disable(void);
 
@@ -39,4 +36,8 @@ struct irda_platform_data;
 void sa11x0_register_irda(struct irda_platform_data *irda);
 
 struct mcp_plat_data;
+void sa11x0_ppc_configure_mcp(void);
 void sa11x0_register_mcp(struct mcp_plat_data *data);
+
+struct sa1100fb_mach_info;
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
index 1e6b3c1..b2e8d0f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -36,13 +39,28 @@ static void h3100_lcd_power(int enable)
        }
 }
 
+static struct sa1100fb_mach_info h3100_lcd_info = {
+       .pixclock       = 406977,       .bpp            = 4,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 26,           .vsync_len      = 41,
+       .left_margin    = 4,            .upper_margin   = 0,
+       .right_margin   = 4,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .cmap_greyscale = 1,
+       .cmap_inverse   = 1,
+
+       .lccr0          = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .lcd_power = h3100_lcd_power,
+};
 
 static void __init h3100_map_io(void)
 {
        h3xxx_map_io();
 
-       sa1100fb_lcd_power = h3100_lcd_power;
-
        /* Older bootldrs put GPIO2-9 in alternate mode on the
           assumption that they are used for video */
        GAFR &= ~0x000001fb;
@@ -80,12 +98,15 @@ static void __init h3100_mach_init(void)
 {
        h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
        h3xxx_mach_init();
+
+       sa11x0_register_lcd(&h3100_lcd_info);
        sa11x0_register_irda(&h3100_irda_data);
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
        .atag_offset    = 0x100,
        .map_io         = h3100_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = h3100_mach_init,
index 6b58e74..cb6659f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -56,11 +59,35 @@ err2:       gpio_free(H3XXX_EGPIO_LCD_ON);
 err1:  return;
 }
 
+static const struct sa1100fb_rgb h3600_rgb_16 = {
+       .red    = { .offset = 12, .length = 4, },
+       .green  = { .offset = 7,  .length = 4, },
+       .blue   = { .offset = 1,  .length = 4, },
+       .transp = { .offset = 0,  .length = 0, },
+};
+
+static struct sa1100fb_mach_info h3600_lcd_info = {
+       .pixclock       = 174757,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 3,            .vsync_len      = 3,
+       .left_margin    = 12,           .upper_margin   = 10,
+       .right_margin   = 17,           .lower_margin   = 1,
+
+       .cmap_static    = 1,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .rgb[RGB_16] = &h3600_rgb_16,
+
+       .lcd_power = h3600_lcd_power,
+};
+
+
 static void __init h3600_map_io(void)
 {
        h3xxx_map_io();
-
-       sa1100fb_lcd_power = h3600_lcd_power;
 }
 
 /*
@@ -121,12 +148,15 @@ static void __init h3600_mach_init(void)
 {
        h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
        h3xxx_mach_init();
+
+       sa11x0_register_lcd(&h3600_lcd_info);
        sa11x0_register_irda(&h3600_irda_data);
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
        .atag_offset    = 0x100,
        .map_io         = h3600_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = h3600_mach_init,
index b0784c9..63150e1 100644 (file)
@@ -109,11 +109,8 @@ static struct flash_platform_data h3xxx_flash_data = {
        .nr_parts       = ARRAY_SIZE(h3xxx_partitions),
 };
 
-static struct resource h3xxx_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource h3xxx_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 
 /*
@@ -186,11 +183,7 @@ static struct sa1100_port_fns h3xxx_port_fns __initdata = {
  */
 
 static struct resource egpio_resources[] = {
-       [0] = {
-               .start  = H3600_EGPIO_PHYS,
-               .end    = H3600_EGPIO_PHYS + 0x4 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
 };
 
 static struct htc_egpio_chip egpio_chips[] = {
index c01bb36..5535475 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/irq.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -35,6 +33,9 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /**********************************************************************
@@ -179,11 +180,8 @@ static struct flash_platform_data hackkit_flash_data = {
        .nr_parts       = ARRAY_SIZE(hackkit_partitions),
 };
 
-static struct resource hackkit_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource hackkit_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init hackkit_init(void)
 {
@@ -197,6 +195,7 @@ static void __init hackkit_init(void)
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
        .atag_offset    = 0x100,
        .map_io         = hackkit_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = hackkit_init,
index bae8296..3f2d1b6 100644 (file)
 
 /*
  * Direct Memory Access (DMA) control registers
- *
- * Registers
- *    DDAR0            Direct Memory Access (DMA) Device Address Register
- *                     channel 0 (read/write).
- *    DCSR0            Direct Memory Access (DMA) Control and Status
- *                     Register channel 0 (read/write).
- *    DBSA0            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 0 (read/write).
- *    DBTA0            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 0 (read/write).
- *    DBSB0            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 0 (read/write).
- *    DBTB0            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 0 (read/write).
- *
- *    DDAR1            Direct Memory Access (DMA) Device Address Register
- *                     channel 1 (read/write).
- *    DCSR1            Direct Memory Access (DMA) Control and Status
- *                     Register channel 1 (read/write).
- *    DBSA1            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 1 (read/write).
- *    DBTA1            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 1 (read/write).
- *    DBSB1            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 1 (read/write).
- *    DBTB1            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 1 (read/write).
- *
- *    DDAR2            Direct Memory Access (DMA) Device Address Register
- *                     channel 2 (read/write).
- *    DCSR2            Direct Memory Access (DMA) Control and Status
- *                     Register channel 2 (read/write).
- *    DBSA2            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 2 (read/write).
- *    DBTA2            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 2 (read/write).
- *    DBSB2            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 2 (read/write).
- *    DBTB2            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 2 (read/write).
- *
- *    DDAR3            Direct Memory Access (DMA) Device Address Register
- *                     channel 3 (read/write).
- *    DCSR3            Direct Memory Access (DMA) Control and Status
- *                     Register channel 3 (read/write).
- *    DBSA3            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 3 (read/write).
- *    DBTA3            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 3 (read/write).
- *    DBSB3            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 3 (read/write).
- *    DBTB3            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 3 (read/write).
- *
- *    DDAR4            Direct Memory Access (DMA) Device Address Register
- *                     channel 4 (read/write).
- *    DCSR4            Direct Memory Access (DMA) Control and Status
- *                     Register channel 4 (read/write).
- *    DBSA4            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 4 (read/write).
- *    DBTA4            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 4 (read/write).
- *    DBSB4            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 4 (read/write).
- *    DBTB4            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 4 (read/write).
- *
- *    DDAR5            Direct Memory Access (DMA) Device Address Register
- *                     channel 5 (read/write).
- *    DCSR5            Direct Memory Access (DMA) Control and Status
- *                     Register channel 5 (read/write).
- *    DBSA5            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 5 (read/write).
- *    DBTA5            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 5 (read/write).
- *    DBSB5            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 5 (read/write).
- *    DBTB5            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 5 (read/write).
  */
-
-#define DMASp          0x00000020      /* DMA control reg. Space [byte]   */
-
-#define DDAR(Nb)       __REG(0xB0000000 + (Nb)*DMASp)  /* DMA Device Address Reg. channel [0..5] */
-#define SetDCSR(Nb)    __REG(0xB0000004 + (Nb)*DMASp)  /* Set DMA Control & Status Reg. channel [0..5] (write) */
-#define ClrDCSR(Nb)    __REG(0xB0000008 + (Nb)*DMASp)  /* Clear DMA Control & Status Reg. channel [0..5] (write) */
-#define RdDCSR(Nb)     __REG(0xB000000C + (Nb)*DMASp)  /* Read DMA Control & Status Reg. channel [0..5] (read) */
-#define DBSA(Nb)       __REG(0xB0000010 + (Nb)*DMASp)  /* DMA Buffer Start address reg. A channel [0..5] */
-#define DBTA(Nb)       __REG(0xB0000014 + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. A channel [0..5] */
-#define DBSB(Nb)       __REG(0xB0000018 + (Nb)*DMASp)  /* DMA Buffer Start address reg. B channel [0..5] */
-#define DBTB(Nb)       __REG(0xB000001C + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. B channel [0..5] */
-
-#define DDAR_RW        0x00000001      /* device data Read/Write          */
-#define DDAR_DevWr     (DDAR_RW*0)     /*  Device data Write              */
-                                       /*  (memory -> device)             */
-#define DDAR_DevRd     (DDAR_RW*1)     /*  Device data Read               */
-                                       /*  (device -> memory)             */
-#define DDAR_E         0x00000002      /* big/little Endian device        */
-#define DDAR_LtlEnd    (DDAR_E*0)      /*  Little Endian device           */
-#define DDAR_BigEnd    (DDAR_E*1)      /*  Big Endian device              */
-#define DDAR_BS        0x00000004      /* device Burst Size               */
-#define DDAR_Brst4     (DDAR_BS*0)     /*  Burst-of-4 device              */
-#define DDAR_Brst8     (DDAR_BS*1)     /*  Burst-of-8 device              */
-#define DDAR_DW        0x00000008      /* device Data Width               */
-#define DDAR_8BitDev   (DDAR_DW*0)     /*  8-Bit Device                   */
-#define DDAR_16BitDev  (DDAR_DW*1)     /*  16-Bit Device                  */
-#define DDAR_DS        Fld (4, 4)      /* Device Select                   */
-#define DDAR_Ser0UDCTr                 /*  Ser. port 0 UDC Transmit       */ \
-                       (0x0 << FShft (DDAR_DS))
-#define DDAR_Ser0UDCRc                 /*  Ser. port 0 UDC Receive        */ \
-                       (0x1 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCTr                        /*  Ser. port 1 SDLC Transmit      */ \
-                       (0x2 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCRc                        /*  Ser. port 1 SDLC Receive       */ \
-                       (0x3 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTTr                        /*  Ser. port 1 UART Transmit      */ \
-                       (0x4 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTRc                        /*  Ser. port 1 UART Receive       */ \
-                       (0x5 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPTr                 /*  Ser. port 2 ICP Transmit       */ \
-                       (0x6 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPRc                 /*  Ser. port 2 ICP Receive        */ \
-                       (0x7 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTTr                        /*  Ser. port 3 UART Transmit      */ \
-                       (0x8 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTRc                        /*  Ser. port 3 UART Receive       */ \
-                       (0x9 << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Tr                        /*  Ser. port 4 MCP 0 Transmit     */ \
-                                       /*  (audio)                        */ \
-                       (0xA << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Rc                        /*  Ser. port 4 MCP 0 Receive      */ \
-                                       /*  (audio)                        */ \
-                       (0xB << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Tr                        /*  Ser. port 4 MCP 1 Transmit     */ \
-                                       /*  (telecom)                      */ \
-                       (0xC << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Rc                        /*  Ser. port 4 MCP 1 Receive      */ \
-                                       /*  (telecom)                      */ \
-                       (0xD << FShft (DDAR_DS))
-#define DDAR_Ser4SSPTr                 /*  Ser. port 4 SSP Transmit       */ \
-                       (0xE << FShft (DDAR_DS))
-#define DDAR_Ser4SSPRc                 /*  Ser. port 4 SSP Receive        */ \
-                       (0xF << FShft (DDAR_DS))
-#define DDAR_DA        Fld (24, 8)     /* Device Address                  */
-#define DDAR_DevAdd(Add)               /*  Device Address                 */ \
-                       (((Add) & 0xF0000000) | \
-                        (((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2)))
-#define DDAR_Ser0UDCWr                 /* Ser. port 0 UDC Write           */ \
-                       (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser0UDCTr + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser0UDCRd                 /* Ser. port 0 UDC Read            */ \
-                       (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser0UDCRc + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser1UARTWr                        /* Ser. port 1 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1UARTTr + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1UARTRd                        /* Ser. port 1 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1UARTRc + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1SDLCWr                        /* Ser. port 1 SDLC Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1SDLCTr + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser1SDLCRd                        /* Ser. port 1 SDLC Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1SDLCRc + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser2UARTWr                        /* Ser. port 2 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2UARTRd                        /* Ser. port 2 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2HSSPWr                        /* Ser. port 2 HSSP Write          */ \
-                       (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser2HSSPRd                        /* Ser. port 2 HSSP Read           */ \
-                       (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser3UARTWr                        /* Ser. port 3 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser3UARTTr + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser3UARTRd                        /* Ser. port 3 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser3UARTRc + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser4MCP0Wr                        /* Ser. port 4 MCP 0 Write (audio) */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP0Tr + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP0Rd                        /* Ser. port 4 MCP 0 Read (audio)  */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP0Rc + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP1Wr                        /* Ser. port 4 MCP 1 Write         */ \
-                                       /* (telecom)                       */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP1Tr + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4MCP1Rd                        /* Ser. port 4 MCP 1 Read          */ \
-                                       /* (telecom)                       */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP1Rc + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4SSPWr                 /* Ser. port 4 SSP Write (16 bits) */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4SSPTr + DDAR_DevAdd (__PREG(Ser4SSDR)))
-#define DDAR_Ser4SSPRd                 /* Ser. port 4 SSP Read (16 bits)  */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4SSPRc + DDAR_DevAdd (__PREG(Ser4SSDR)))
-
-#define DCSR_RUN       0x00000001      /* DMA running                     */
-#define DCSR_IE        0x00000002      /* DMA Interrupt Enable            */
-#define DCSR_ERROR     0x00000004      /* DMA ERROR                       */
-#define DCSR_DONEA     0x00000008      /* DONE DMA transfer buffer A      */
-#define DCSR_STRTA     0x00000010      /* STaRTed DMA transfer buffer A   */
-#define DCSR_DONEB     0x00000020      /* DONE DMA transfer buffer B      */
-#define DCSR_STRTB     0x00000040      /* STaRTed DMA transfer buffer B   */
-#define DCSR_BIU       0x00000080      /* DMA Buffer In Use               */
-#define DCSR_BufA      (DCSR_BIU*0)    /*  DMA Buffer A in use            */
-#define DCSR_BufB      (DCSR_BIU*1)    /*  DMA Buffer B in use            */
-
-#define DBT_TC         Fld (13, 0)     /* Transfer Count                  */
-#define DBTA_TCA       DBT_TC          /* Transfer Count buffer A         */
-#define DBTB_TCB       DBT_TC          /* Transfer Count buffer B         */
+#define DMA_SIZE       (6 * 0x20)
+#define DMA_PHYS       0xb0000000
 
 
 /*
 #define LCD_Int100_0A  0xF             /* LCD Intensity = 100.0% =  1     */
                                        /* (Alternative)                   */
 
-#define LCCR0          __REG(0xB0100000)  /* LCD Control Reg. 0 */
-#define LCSR           __REG(0xB0100004)  /* LCD Status Reg. */
-#define DBAR1          __REG(0xB0100010)  /* LCD DMA Base Address Reg. channel 1 */
-#define DCAR1          __REG(0xB0100014)  /* LCD DMA Current Address Reg. channel 1 */
-#define DBAR2          __REG(0xB0100018)  /* LCD DMA Base Address Reg.  channel 2 */
-#define DCAR2          __REG(0xB010001C)  /* LCD DMA Current Address Reg. channel 2 */
-#define LCCR1          __REG(0xB0100020)  /* LCD Control Reg. 1 */
-#define LCCR2          __REG(0xB0100024)  /* LCD Control Reg. 2 */
-#define LCCR3          __REG(0xB0100028)  /* LCD Control Reg. 3 */
-
 #define LCCR0_LEN      0x00000001      /* LCD ENable                      */
 #define LCCR0_CMS      0x00000002      /* Color/Monochrome display Select */
 #define LCCR0_Color    (LCCR0_CMS*0)   /*  Color display                  */
diff --git a/arch/arm/mach-sa1100/include/mach/dma.h b/arch/arm/mach-sa1100/include/mach/dma.h
deleted file mode 100644 (file)
index dda1b35..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/dma.h
- *
- * Generic SA1100 DMA support
- *
- * Copyright (C) 2000 Nicolas Pitre
- *
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#include "hardware.h"
-
-
-/*
- * The SA1100 has six internal DMA channels.
- */
-#define SA1100_DMA_CHANNELS    6
-
-/*
- * Maximum physical DMA buffer size
- */
-#define MAX_DMA_SIZE           0x1fff
-#define CUT_DMA_SIZE           0x1000
-
-/*
- * All possible SA1100 devices a DMA channel can be attached to.
- */
-typedef enum {
-       DMA_Ser0UDCWr  = DDAR_Ser0UDCWr,   /* Ser. port 0 UDC Write */
-       DMA_Ser0UDCRd  = DDAR_Ser0UDCRd,   /* Ser. port 0 UDC Read */
-       DMA_Ser1UARTWr = DDAR_Ser1UARTWr,  /* Ser. port 1 UART Write */
-       DMA_Ser1UARTRd = DDAR_Ser1UARTRd,  /* Ser. port 1 UART Read */
-       DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr,  /* Ser. port 1 SDLC Write */
-       DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd,  /* Ser. port 1 SDLC Read */
-       DMA_Ser2UARTWr = DDAR_Ser2UARTWr,  /* Ser. port 2 UART Write */
-       DMA_Ser2UARTRd = DDAR_Ser2UARTRd,  /* Ser. port 2 UART Read */
-       DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr,  /* Ser. port 2 HSSP Write */
-       DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd,  /* Ser. port 2 HSSP Read */
-       DMA_Ser3UARTWr = DDAR_Ser3UARTWr,  /* Ser. port 3 UART Write */
-       DMA_Ser3UARTRd = DDAR_Ser3UARTRd,  /* Ser. port 3 UART Read */
-       DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr,  /* Ser. port 4 MCP 0 Write (audio) */
-       DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd,  /* Ser. port 4 MCP 0 Read (audio) */
-       DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr,  /* Ser. port 4 MCP 1 Write */
-       DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd,  /* Ser. port 4 MCP 1 Read */
-       DMA_Ser4SSPWr  = DDAR_Ser4SSPWr,   /* Ser. port 4 SSP Write (16 bits) */
-       DMA_Ser4SSPRd  = DDAR_Ser4SSPRd    /* Ser. port 4 SSP Read (16 bits) */
-} dma_device_t;
-
-typedef struct {
-       volatile u_long DDAR;
-       volatile u_long SetDCSR;
-       volatile u_long ClrDCSR;
-       volatile u_long RdDCSR;
-       volatile dma_addr_t DBSA;
-       volatile u_long DBTA;
-       volatile dma_addr_t DBSB;
-       volatile u_long DBTB;
-} dma_regs_t;
-
-typedef void (*dma_callback_t)(void *data);
-
-/*
- * DMA function prototypes
- */
-
-extern int sa1100_request_dma( dma_device_t device, const char *device_id,
-                              dma_callback_t callback, void *data,
-                              dma_regs_t **regs );
-extern void sa1100_free_dma( dma_regs_t *regs );
-extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size );
-extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs);
-extern void sa1100_reset_dma(dma_regs_t *regs);
-
-/**
- *     sa1100_stop_dma - stop DMA in progress
- *     @regs: identifier for the channel to use
- *
- *     This stops DMA without clearing buffer pointers. Unlike
- *     sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma()
- *     or sa1100_get_dma_pos().
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_stop_dma(regs)  ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- *     sa1100_resume_dma - resume DMA on a stopped channel
- *     @regs: identifier for the channel to use
- *
- *     This resumes DMA on a channel previously stopped with
- *     sa1100_stop_dma().
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_resume_dma(regs)        ((regs)->SetDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- *     sa1100_clear_dma - clear DMA pointers
- *     @regs: identifier for the channel to use
- *
- *     This clear any DMA state so the DMA engine is ready to restart
- *     with new buffers through sa1100_start_dma(). Any buffers in flight
- *     are discarded.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_clear_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB)
-
-#endif /* _ASM_ARCH_DMA_H */
index d18f21a..3790298 100644 (file)
 /*
  * Figure out the MAX IRQ number.
  *
- * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
- * If we have an LoCoMo, the max IRQ is IRQ_BOARD_START + 4
- * Otherwise, we have the standard IRQs only.
+ * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
+ * allocate their IRQs above NR_IRQS.
+ *
+ * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
+ * to be included in the NR_IRQS calculation.
  */
-#ifdef CONFIG_SA1111
-#define NR_IRQS                        (IRQ_BOARD_END + 55)
-#elif defined(CONFIG_SHARP_LOCOMO)
-#define NR_IRQS                        (IRQ_BOARD_START + 4)
+#ifdef CONFIG_SHARP_LOCOMO
+#define NR_IRQS_LOCOMO         4
 #else
-#define NR_IRQS                        (IRQ_BOARD_START)
+#define NR_IRQS_LOCOMO         0
 #endif
 
-/*
- * Board specific IRQs.  Define them here.
- * Do not surround them with ifdefs.
- */
-#define IRQ_NEPONSET_SMC9196   (IRQ_BOARD_START + 0)
-#define IRQ_NEPONSET_USAR      (IRQ_BOARD_START + 1)
-#define IRQ_NEPONSET_SA1111    (IRQ_BOARD_START + 2)
+#ifndef NR_IRQS
+#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#endif
+#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
index ed1a331..4b2860a 100644 (file)
@@ -16,7 +16,7 @@ struct mcp_plat_data {
        u32 mccr0;
        u32 mccr1;
        unsigned int sclk_rate;
-       int gpio_base;
+       void *codec_pdata;
 };
 
 #endif
index ffe2bc4..5516a52 100644 (file)
 /*
  * Neponset definitions: 
  */
-
-#define NEPONSET_CPLD_BASE      (0x10000000)
-#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
-#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
-
-#define _IRR                    0x10000024      /* Interrupt Reason Register */
-#define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
-#define _MDM_CTL_0              0x100000b0      /* Modem control 0 (RW)      */
-#define _MDM_CTL_1              0x100000b4      /* Modem control 1 (RW)      */
-#define _NCR_0                 0x100000a0      /* Control Register (RW)     */
-#define _KP_X_OUT               0x10000090      /* Keypad row write (RW)     */
-#define _KP_Y_IN                0x10000080      /* Keypad column read (RO)   */
-#define _SWPK                   0x10000020      /* Switch pack (RO)          */
-#define _WHOAMI                 0x10000000      /* System ID Register (RO)   */
-
-#define _LEDS                   0x10000010      /* LEDs [31:0] (WO)          */
-
-#define IRR                     (*((volatile u_char *) Nep_p2v(_IRR)))
-#define AUD_CTL                 (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
-#define MDM_CTL_0               (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
-#define MDM_CTL_1               (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
-#define NCR_0                  (*((volatile u_char *) Nep_p2v(_NCR_0)))
-#define KP_X_OUT                (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
-#define KP_Y_IN                 (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
-#define SWPK                    (*((volatile u_char *) Nep_p2v(_SWPK)))
-#define WHOAMI                  (*((volatile u_char *) Nep_p2v(_WHOAMI)))
-
-#define LEDS                    (*((volatile Word   *) Nep_p2v(_LEDS)))
-
-#define IRR_ETHERNET           (1<<0)
-#define IRR_USAR               (1<<1)
-#define IRR_SA1111             (1<<2)
-
-#define AUD_SEL_1341            (1<<0)
-#define AUD_MUTE_1341           (1<<1)
-
-#define MDM_CTL0_RTS1          (1 << 0)
-#define MDM_CTL0_DTR1          (1 << 1)
-#define MDM_CTL0_RTS2          (1 << 2)
-#define MDM_CTL0_DTR2          (1 << 3)
-
-#define MDM_CTL1_CTS1          (1 << 0)
-#define MDM_CTL1_DSR1          (1 << 1)
-#define MDM_CTL1_DCD1          (1 << 2)
-#define MDM_CTL1_CTS2          (1 << 3)
-#define MDM_CTL1_DSR2          (1 << 4)
-#define MDM_CTL1_DCD2          (1 << 5)
-
 #define NCR_GP01_OFF           (1<<0)
 #define NCR_TP_PWR_EN          (1<<1)
 #define NCR_MS_PWR_EN          (1<<2)
@@ -71,4 +23,8 @@
 #define NCR_A0VPP              (1<<5)
 #define NCR_A1VPP              (1<<6)
 
+void neponset_ncr_frob(unsigned int, unsigned int);
+#define neponset_ncr_set(v)    neponset_ncr_frob(0, v)
+#define neponset_ncr_clear(v)  neponset_ncr_frob(v, 0)
+
 #endif
index ec27d6e..a0d1114 100644 (file)
@@ -21,7 +21,7 @@
 #define SHANNON_GPIO_U3_RTS            GPIO_GPIO (19)  /* ?? */
 #define SHANNON_GPIO_U3_CTS            GPIO_GPIO (20)  /* ?? */
 #define SHANNON_GPIO_SENSE_12V         GPIO_GPIO (21)  /* Input, 12v flash unprotect detected */
-#define SHANNON_GPIO_DISP_EN           GPIO_GPIO (22)  /* out */
+#define SHANNON_GPIO_DISP_EN           22              /* out */
 /* XXX GPIO 23 unaccounted for */
 #define SHANNON_GPIO_EJECT_0           GPIO_GPIO (24)  /* in */
 #define SHANNON_IRQ_GPIO_EJECT_0       IRQ_GPIO24
index dfbf824..516ccc2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/irq.h>
 
 #include "generic.h"
@@ -221,11 +222,8 @@ static struct irq_chip sa1100_normal_chip = {
        .irq_set_wake   = sa1100_set_wake,
 };
 
-static struct resource irq_resource = {
-       .name   = "irqs",
-       .start  = 0x90050000,
-       .end    = 0x9005ffff,
-};
+static struct resource irq_resource =
+       DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
 
 static struct sa1100irq_state {
        unsigned int    saved;
index ee121d6..ca7a7e8 100644 (file)
@@ -23,9 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <video/s1d13xxxfb.h>
 
-#include <mach/hardware.h>
 #include <asm/hardware/sa1111.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -34,6 +32,9 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /*
@@ -46,7 +47,7 @@
 
 /* memory space (line 52 of HP's doc) */
 #define SA1111REGSTART 0x40000000
-#define SA1111REGLEN   0x00001fff
+#define SA1111REGLEN   0x00002000
 #define EPSONREGSTART  0x48000000
 #define EPSONREGLEN    0x00100000
 #define EPSONFBSTART   0x48200000
@@ -174,16 +175,8 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
 };
 
 static struct resource s1d13xxxfb_resources[] = {
-       [0] = {
-               .start  = EPSONFBSTART,
-               .end    = EPSONFBSTART + EPSONFBLEN,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = EPSONREGSTART,
-               .end    = EPSONREGSTART + EPSONREGLEN,
-               .flags  = IORESOURCE_MEM,
-       }
+       [0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
+       [1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
 };
 
 static struct platform_device s1d13xxxfb_device = {
@@ -197,20 +190,12 @@ static struct platform_device s1d13xxxfb_device = {
 };
 
 static struct resource sa1111_resources[] = {
-       [0] = {
-               .start          = SA1111REGSTART,
-               .end            = SA1111REGSTART + SA1111REGLEN,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = IRQ_GPIO1,
-               .end            = IRQ_GPIO1,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO1),
 };
 
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -284,11 +269,6 @@ static struct map_desc jornada720_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(EPSONFBSTART),
                .length         = EPSONFBLEN,
                .type           = MT_DEVICE
-       }, {    /* SA-1111 */
-               .virtual        = 0xf4000000,
-               .pfn            = __phys_to_pfn(SA1111REGSTART),
-               .length         = SA1111REGLEN,
-               .type           = MT_DEVICE
        }
 };
 
@@ -352,11 +332,8 @@ static struct flash_platform_data jornada720_flash_data = {
        .nr_parts       = ARRAY_SIZE(jornada720_partitions),
 };
 
-static struct resource jornada720_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource jornada720_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init jornada720_mach_init(void)
 {
@@ -367,6 +344,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720")
        /* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
        .atag_offset    = 0x100,
        .map_io         = jornada720_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = jornada720_mach_init,
index af4e276..eb6534e 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -15,6 +17,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -26,8 +29,86 @@ static struct mcp_plat_data lart_mcp_data = {
        .sclk_rate      = 11981000,
 };
 
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info = {
+       .pixclock       = 150000,       .bpp            = 4,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 1,            .vsync_len      = 1,
+       .left_margin    = 4,            .upper_margin   = 0,
+       .right_margin   = 2,            .lower_margin   = 0,
+
+       .cmap_greyscale = 1,
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info = {
+       .pixclock       = 150000,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 2,            .vsync_len      = 3,
+       .left_margin    = 69,           .upper_margin   = 14,
+       .right_margin   = 8,            .lower_margin   = 4,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info = {
+       .pixclock       = 39721,        .bpp            = 16,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 95,           .vsync_len      = 2,
+       .left_margin    = 40,           .upper_margin   = 32,
+       .right_margin   = 24,           .lower_margin   = 11,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info = {
+       .pixclock       = 63291,        .bpp            = 16,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 64,           .vsync_len      = 3,
+       .left_margin    = 122,          .upper_margin   = 45,
+       .right_margin   = 10,           .lower_margin   = 10,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
+
 static void __init lart_init(void)
 {
+       struct sa1100fb_mach_info *inf = NULL;
+
+#ifdef LART_GREY_LCD
+       inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+       inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+       inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+       inf = &lart_kit01_info;
+#endif
+
+       if (inf)
+               sa11x0_register_lcd(inf);
+
+       sa11x0_ppc_configure_mcp();
        sa11x0_register_mcp(&lart_mcp_data);
 }
 
@@ -63,6 +144,7 @@ static void __init lart_map_io(void)
 MACHINE_START(LART, "LART")
        .atag_offset    = 0x100,
        .map_io         = lart_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .init_machine   = lart_init,
        .timer          = &sa1100_timer,
index 85f6ee6..8f6446b 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <mach/hardware.h>
 #include <mach/nanoengine.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -58,15 +59,8 @@ static struct flash_platform_data nanoengine_flash_data = {
 };
 
 static struct resource nanoengine_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = SA1100_CS1_PHYS,
-               .end    = SA1100_CS1_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
@@ -114,6 +108,7 @@ static void __init nanoengine_init(void)
 MACHINE_START(NANOENGINE, "BSE nanoEngine")
        .atag_offset    = 0x100,
        .map_io         = nanoengine_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = nanoengine_init,
index b4fa53a..6c58f01 100644 (file)
 /*
  * linux/arch/arm/mach-sa1100/neponset.c
- *
  */
-#include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
-#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
-#include <mach/assabet.h>
-#include <mach/neponset.h>
 #include <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
 
-/*
- * Install handler for Neponset IRQ.  Note that we have to loop here
- * since the ETHERNET and USAR IRQs are level based, and we need to
- * ensure that the IRQ signal is deasserted before returning.  This
- * is rather unfortunate.
- */
-static void
-neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned int irr;
-
-       while (1) {
-               /*
-                * Acknowledge the parent IRQ.
-                */
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
-
-               /*
-                * Read the interrupt reason register.  Let's have all
-                * active IRQ bits high.  Note: there is a typo in the
-                * Neponset user's guide for the SA1111 IRR level.
-                */
-               irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
-
-               if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
-                       break;
-
-               /*
-                * Since there is no individual mask, we have to
-                * mask the parent IRQ.  This is safe, since we'll
-                * recheck the register for any pending IRQs.
-                */
-               if (irr & (IRR_ETHERNET | IRR_USAR)) {
-                       desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-                       /*
-                        * Ack the interrupt now to prevent re-entering
-                        * this neponset handler.  Again, this is safe
-                        * since we'll check the IRR register prior to
-                        * leaving.
-                        */
-                       desc->irq_data.chip->irq_ack(&desc->irq_data);
+#include <mach/hardware.h>
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#include <mach/irqs.h>
+
+#define NEP_IRQ_SMC91X 0
+#define NEP_IRQ_USAR   1
+#define NEP_IRQ_SA1111 2
+#define NEP_IRQ_NR     3
+
+#define WHOAMI         0x00
+#define LEDS           0x10
+#define SWPK           0x20
+#define IRR            0x24
+#define KP_Y_IN                0x80
+#define KP_X_OUT       0x90
+#define NCR_0          0xa0
+#define MDM_CTL_0      0xb0
+#define MDM_CTL_1      0xb4
+#define AUD_CTL                0xc0
+
+#define IRR_ETHERNET   (1 << 0)
+#define IRR_USAR       (1 << 1)
+#define IRR_SA1111     (1 << 2)
+
+#define MDM_CTL0_RTS1  (1 << 0)
+#define MDM_CTL0_DTR1  (1 << 1)
+#define MDM_CTL0_RTS2  (1 << 2)
+#define MDM_CTL0_DTR2  (1 << 3)
+
+#define MDM_CTL1_CTS1  (1 << 0)
+#define MDM_CTL1_DSR1  (1 << 1)
+#define MDM_CTL1_DCD1  (1 << 2)
+#define MDM_CTL1_CTS2  (1 << 3)
+#define MDM_CTL1_DSR2  (1 << 4)
+#define MDM_CTL1_DCD2  (1 << 5)
+
+#define AUD_SEL_1341   (1 << 0)
+#define AUD_MUTE_1341  (1 << 1)
 
-                       if (irr & IRR_ETHERNET) {
-                               generic_handle_irq(IRQ_NEPONSET_SMC9196);
-                       }
+extern void sa1110_mb_disable(void);
 
-                       if (irr & IRR_USAR) {
-                               generic_handle_irq(IRQ_NEPONSET_USAR);
-                       }
+struct neponset_drvdata {
+       void __iomem *base;
+       struct platform_device *sa1111;
+       struct platform_device *smc91x;
+       unsigned irq_base;
+#ifdef CONFIG_PM_SLEEP
+       u32 ncr0;
+       u32 mdm_ctl_0;
+#endif
+};
 
-                       desc->irq_data.chip->irq_unmask(&desc->irq_data);
-               }
+static void __iomem *nep_base;
 
-               if (irr & IRR_SA1111) {
-                       generic_handle_irq(IRQ_NEPONSET_SA1111);
-               }
+void neponset_ncr_frob(unsigned int mask, unsigned int val)
+{
+       void __iomem *base = nep_base;
+
+       if (base) {
+               unsigned long flags;
+               unsigned v;
+
+               local_irq_save(flags);
+               v = readb_relaxed(base + NCR_0);
+               writeb_relaxed((v & ~mask) | val, base + NCR_0);
+               local_irq_restore(flags);
+       } else {
+               WARN(1, "nep_base unset\n");
        }
 }
 
 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
 {
-       u_int mdm_ctl0 = MDM_CTL_0;
+       void __iomem *base = nep_base;
+       u_int mdm_ctl0;
 
+       if (!base)
+               return;
+
+       mdm_ctl0 = readb_relaxed(base + MDM_CTL_0);
        if (port->mapbase == _Ser1UTCR0) {
                if (mctrl & TIOCM_RTS)
                        mdm_ctl0 &= ~MDM_CTL0_RTS2;
@@ -106,14 +121,19 @@ static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
                        mdm_ctl0 |= MDM_CTL0_DTR1;
        }
 
-       MDM_CTL_0 = mdm_ctl0;
+       writeb_relaxed(mdm_ctl0, base + MDM_CTL_0);
 }
 
 static u_int neponset_get_mctrl(struct uart_port *port)
 {
+       void __iomem *base = nep_base;
        u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-       u_int mdm_ctl1 = MDM_CTL_1;
+       u_int mdm_ctl1;
+
+       if (!base)
+               return ret;
 
+       mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
        if (port->mapbase == _Ser1UTCR0) {
                if (mdm_ctl1 & MDM_CTL1_DCD2)
                        ret &= ~TIOCM_CD;
@@ -138,209 +158,278 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
        .get_mctrl      = neponset_get_mctrl,
 };
 
-static int __devinit neponset_probe(struct platform_device *dev)
+/*
+ * Install handler for Neponset IRQ.  Note that we have to loop here
+ * since the ETHERNET and USAR IRQs are level based, and we need to
+ * ensure that the IRQ signal is deasserted before returning.  This
+ * is rather unfortunate.
+ */
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       sa1100_register_uart_fns(&neponset_port_fns);
+       struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
+       unsigned int irr;
 
-       /*
-        * Install handler for GPIO25.
-        */
-       irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
-       irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
+       while (1) {
+               /*
+                * Acknowledge the parent IRQ.
+                */
+               desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-       /*
-        * We would set IRQ_GPIO25 to be a wake-up IRQ, but
-        * unfortunately something on the Neponset activates
-        * this IRQ on sleep (ethernet?)
-        */
-#if 0
-       enable_irq_wake(IRQ_GPIO25);
-#endif
+               /*
+                * Read the interrupt reason register.  Let's have all
+                * active IRQ bits high.  Note: there is a typo in the
+                * Neponset user's guide for the SA1111 IRR level.
+                */
+               irr = readb_relaxed(d->base + IRR);
+               irr ^= IRR_ETHERNET | IRR_USAR;
 
-       /*
-        * Setup other Neponset IRQs.  SA1111 will be done by the
-        * generic SA1111 code.
-        */
-       irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq);
-       set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
-       irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq);
-       set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
+               if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
+                       break;
 
-       /*
-        * Disable GPIO 0/1 drivers so the buttons work on the module.
-        */
-       NCR_0 = NCR_GP01_OFF;
+               /*
+                * Since there is no individual mask, we have to
+                * mask the parent IRQ.  This is safe, since we'll
+                * recheck the register for any pending IRQs.
+                */
+               if (irr & (IRR_ETHERNET | IRR_USAR)) {
+                       desc->irq_data.chip->irq_mask(&desc->irq_data);
 
-       return 0;
-}
+                       /*
+                        * Ack the interrupt now to prevent re-entering
+                        * this neponset handler.  Again, this is safe
+                        * since we'll check the IRR register prior to
+                        * leaving.
+                        */
+                       desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-#ifdef CONFIG_PM
+                       if (irr & IRR_ETHERNET)
+                               generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
 
-/*
- * LDM power management.
- */
-static unsigned int neponset_saved_state;
+                       if (irr & IRR_USAR)
+                               generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
 
-static int neponset_suspend(struct platform_device *dev, pm_message_t state)
-{
-       /*
-        * Save state.
-        */
-       neponset_saved_state = NCR_0;
+                       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+               }
 
-       return 0;
+               if (irr & IRR_SA1111)
+                       generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
+       }
 }
 
-static int neponset_resume(struct platform_device *dev)
+/* Yes, we really do not have any kind of masking or unmasking */
+static void nochip_noop(struct irq_data *irq)
 {
-       NCR_0 = neponset_saved_state;
-
-       return 0;
 }
 
-#else
-#define neponset_suspend NULL
-#define neponset_resume  NULL
-#endif
-
-static struct platform_driver neponset_device_driver = {
-       .probe          = neponset_probe,
-       .suspend        = neponset_suspend,
-       .resume         = neponset_resume,
-       .driver         = {
-               .name   = "neponset",
-       },
-};
-
-static struct resource neponset_resources[] = {
-       [0] = {
-               .start  = 0x10000000,
-               .end    = 0x17ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device neponset_device = {
-       .name           = "neponset",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(neponset_resources),
-       .resource       = neponset_resources,
-};
-
-static struct resource sa1111_resources[] = {
-       [0] = {
-               .start  = 0x40000000,
-               .end    = 0x40001fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_NEPONSET_SA1111,
-               .end    = IRQ_NEPONSET_SA1111,
-               .flags  = IORESOURCE_IRQ,
-       },
+static struct irq_chip nochip = {
+       .name = "neponset",
+       .irq_ack = nochip_noop,
+       .irq_mask = nochip_noop,
+       .irq_unmask = nochip_noop,
 };
 
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
 };
 
-static u64 sa1111_dmamask = 0xffffffffUL;
+static int __devinit neponset_probe(struct platform_device *dev)
+{
+       struct neponset_drvdata *d;
+       struct resource *nep_res, *sa1111_res, *smc91x_res;
+       struct resource sa1111_resources[] = {
+               DEFINE_RES_MEM(0x40000000, SZ_8K),
+               { .flags = IORESOURCE_IRQ },
+       };
+       struct platform_device_info sa1111_devinfo = {
+               .parent = &dev->dev,
+               .name = "sa1111",
+               .id = 0,
+               .res = sa1111_resources,
+               .num_res = ARRAY_SIZE(sa1111_resources),
+               .data = &sa1111_info,
+               .size_data = sizeof(sa1111_info),
+               .dma_mask = 0xffffffffUL,
+       };
+       struct resource smc91x_resources[] = {
+               DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
+                       0x02000000, "smc91x-regs"),
+               DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
+                       0x02000000, "smc91x-attrib"),
+               { .flags = IORESOURCE_IRQ },
+       };
+       struct platform_device_info smc91x_devinfo = {
+               .parent = &dev->dev,
+               .name = "smc91x",
+               .id = 0,
+               .res = smc91x_resources,
+               .num_res = ARRAY_SIZE(smc91x_resources),
+       };
+       int ret, irq;
+
+       if (nep_base)
+               return -EBUSY;
+
+       irq = ret = platform_get_irq(dev, 0);
+       if (ret < 0)
+               goto err_alloc;
+
+       nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
+       if (!nep_res || !smc91x_res || !sa1111_res) {
+               ret = -ENXIO;
+               goto err_alloc;
+       }
 
-static struct platform_device sa1111_device = {
-       .name           = "sa1111",
-       .id             = 0,
-       .dev            = {
-               .dma_mask = &sa1111_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-               .platform_data = &sa1111_info,
-       },
-       .num_resources  = ARRAY_SIZE(sa1111_resources),
-       .resource       = sa1111_resources,
-};
+       d = kzalloc(sizeof(*d), GFP_KERNEL);
+       if (!d) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
 
-static struct resource smc91x_resources[] = {
-       [0] = {
-               .name   = "smc91x-regs",
-               .start  = SA1100_CS3_PHYS,
-               .end    = SA1100_CS3_PHYS + 0x01ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_NEPONSET_SMC9196,
-               .end    = IRQ_NEPONSET_SMC9196,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .name   = "smc91x-attrib",
-               .start  = SA1100_CS3_PHYS + 0x02000000,
-               .end    = SA1100_CS3_PHYS + 0x03ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
+       d->base = ioremap(nep_res->start, SZ_4K);
+       if (!d->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
-static struct platform_device smc91x_device = {
-       .name           = "smc91x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(smc91x_resources),
-       .resource       = smc91x_resources,
-};
+       if (readb_relaxed(d->base + WHOAMI) != 0x11) {
+               dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
+                        readb_relaxed(d->base + WHOAMI));
+               ret = -ENODEV;
+               goto err_id;
+       }
 
-static struct platform_device *devices[] __initdata = {
-       &neponset_device,
-       &sa1111_device,
-       &smc91x_device,
-};
+       ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
+       if (ret <= 0) {
+               dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
+                       NEP_IRQ_NR, ret);
+               if (ret == 0)
+                       ret = -ENOMEM;
+               goto err_irq_alloc;
+       }
 
-extern void sa1110_mb_disable(void);
+       d->irq_base = ret;
 
-static int __init neponset_init(void)
-{
-       platform_driver_register(&neponset_device_driver);
+       irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
+               handle_simple_irq);
+       set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE);
+       irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
+               handle_simple_irq);
+       set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE);
+       irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
 
-       /*
-        * The Neponset is only present on the Assabet machine type.
-        */
-       if (!machine_is_assabet())
-               return -ENODEV;
+       irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+       irq_set_handler_data(irq, d);
+       irq_set_chained_handler(irq, neponset_irq_handler);
 
        /*
-        * Ensure that the memory bus request/grant signals are setup,
-        * and the grant is held in its inactive state, whether or not
-        * we actually have a Neponset attached.
+        * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
+        * something on the Neponset activates this IRQ on sleep (eth?)
         */
+#if 0
+       enable_irq_wake(irq);
+#endif
+
+       dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
+                d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
+       nep_base = d->base;
+
+       sa1100_register_uart_fns(&neponset_port_fns);
+
+       /* Ensure that the memory bus request/grant signals are setup */
        sa1110_mb_disable();
 
-       if (!machine_has_neponset()) {
-               printk(KERN_DEBUG "Neponset expansion board not present\n");
-               return -ENODEV;
-       }
+       /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
+       writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
 
-       if (WHOAMI != 0x11) {
-               printk(KERN_WARNING "Neponset board detected, but "
-                       "wrong ID: %02x\n", WHOAMI);
-               return -ENODEV;
-       }
+       sa1111_resources[0].parent = sa1111_res;
+       sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
+       sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
+       d->sa1111 = platform_device_register_full(&sa1111_devinfo);
+
+       smc91x_resources[0].parent = smc91x_res;
+       smc91x_resources[1].parent = smc91x_res;
+       smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
+       smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
+       d->smc91x = platform_device_register_full(&smc91x_devinfo);
+
+       platform_set_drvdata(dev, d);
 
-       return platform_add_devices(devices, ARRAY_SIZE(devices));
+       return 0;
+
+ err_irq_alloc:
+ err_id:
+       iounmap(d->base);
+ err_ioremap:
+       kfree(d);
+ err_alloc:
+       return ret;
 }
 
-subsys_initcall(neponset_init);
+static int __devexit neponset_remove(struct platform_device *dev)
+{
+       struct neponset_drvdata *d = platform_get_drvdata(dev);
+       int irq = platform_get_irq(dev, 0);
+
+       if (!IS_ERR(d->sa1111))
+               platform_device_unregister(d->sa1111);
+       if (!IS_ERR(d->smc91x))
+               platform_device_unregister(d->smc91x);
+       irq_set_chained_handler(irq, NULL);
+       irq_free_descs(d->irq_base, NEP_IRQ_NR);
+       nep_base = NULL;
+       iounmap(d->base);
+       kfree(d);
 
-static struct map_desc neponset_io_desc[] __initdata = {
-       {       /* System Registers */
-               .virtual        =  0xf3000000,
-               .pfn            = __phys_to_pfn(0x10000000),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       }, {    /* SA-1111 */
-               .virtual        =  0xf4000000,
-               .pfn            = __phys_to_pfn(0x40000000),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       }
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int neponset_suspend(struct device *dev)
+{
+       struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+       d->ncr0 = readb_relaxed(d->base + NCR_0);
+       d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0);
+
+       return 0;
+}
+
+static int neponset_resume(struct device *dev)
+{
+       struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+       writeb_relaxed(d->ncr0, d->base + NCR_0);
+       writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0);
+
+       return 0;
+}
+
+static const struct dev_pm_ops neponset_pm_ops = {
+       .suspend_noirq = neponset_suspend,
+       .resume_noirq = neponset_resume,
+       .freeze_noirq = neponset_suspend,
+       .restore_noirq = neponset_resume,
+};
+#define PM_OPS &neponset_pm_ops
+#else
+#define PM_OPS NULL
+#endif
+
+static struct platform_driver neponset_device_driver = {
+       .probe          = neponset_probe,
+       .remove         = __devexit_p(neponset_remove),
+       .driver         = {
+               .name   = "neponset",
+               .owner  = THIS_MODULE,
+               .pm     = PM_OPS,
+       },
 };
 
-void __init neponset_map_io(void)
+static int __init neponset_init(void)
 {
-       iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
+       return platform_driver_register(&neponset_device_driver);
 }
+
+subsys_initcall(neponset_init);
index 0d01ca7..41bb018 100644 (file)
@@ -135,12 +135,8 @@ struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys
                                 &sys->resources);
 }
 
-static struct resource pci_io_ports = {
-       .name   = "PCI IO",
-       .start  = 0x400,
-       .end    = 0x7FF,
-       .flags  = IORESOURCE_IO,
-};
+static struct resource pci_io_ports =
+       DEFINE_RES_IO_NAMED(0x400, 0x400, "PCI IO");
 
 static struct resource pci_non_prefetchable_memory = {
        .name   = "PCI non-prefetchable",
index 9307df0..1602575 100644 (file)
 #define IRQ_GPIO_ETH0_IRQ      IRQ_GPIO21
 
 static struct resource smc91x_resources[] = {
-       [0] = {
-               .start  = PLEB_ETH0_P,
-               .end    = PLEB_ETH0_P | 0x03ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(PLEB_ETH0_P, 0x04000000),
 #if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
-       [1] = {
-               .start  = IRQ_GPIO_ETH0_IRQ,
-               .end    = IRQ_GPIO_ETH0_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO_ETH0_IRQ),
 #endif
 };
 
@@ -70,16 +62,8 @@ static struct platform_device *devices[] __initdata = {
  * the two SA1100 lowest chip select outputs.
  */
 static struct resource pleb_flash_resources[] = {
-       [0] = {
-               .start = SA1100_CS0_PHYS,
-               .end   = SA1100_CS0_PHYS + SZ_8M - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = SA1100_CS1_PHYS,
-               .end   = SA1100_CS1_PHYS + SZ_8M - 1,
-               .flags = IORESOURCE_MEM,
-       }
+       [0] = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_8M),
+       [1] = DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_8M),
 };
 
 
@@ -147,6 +131,7 @@ static void __init pleb_map_io(void)
 
 MACHINE_START(PLEB, "PLEB")
        .map_io         = pleb_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = pleb_init,
index 318b2b7..ca8bf59 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -19,6 +21,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/shannon.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -46,19 +49,32 @@ static struct flash_platform_data shannon_flash_data = {
        .nr_parts       = ARRAY_SIZE(shannon_partitions),
 };
 
-static struct resource shannon_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_4M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource shannon_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_4M);
 
 static struct mcp_plat_data shannon_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
 };
 
+static struct sa1100fb_mach_info shannon_lcd_info = {
+       .pixclock       = 152500,       .bpp            = 8,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 4,            .vsync_len      = 3,
+       .left_margin    = 2,            .upper_margin   = 0,
+       .right_margin   = 1,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+       .lccr3          = LCCR3_ACBsDiv(512),
+};
+
 static void __init shannon_init(void)
 {
+       sa11x0_ppc_configure_mcp();
+       sa11x0_register_lcd(&shannon_lcd_info);
        sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
        sa11x0_register_mcp(&shannon_mcp_data);
 }
@@ -84,6 +100,7 @@ static void __init shannon_map_io(void)
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
        .atag_offset    = 0x100,
        .map_io         = shannon_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = shannon_init,
index e17c04d..3efae03 100644 (file)
@@ -7,15 +7,15 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
-#include <linux/string.h> 
+#include <linux/string.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
@@ -26,6 +26,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/simpad.h>
+#include <mach/irqs.h>
 
 #include <linux/serial_core.h>
 #include <linux/ioport.h>
@@ -176,21 +177,18 @@ static struct flash_platform_data simpad_flash_data = {
 
 
 static struct resource simpad_flash_resources [] = {
-       {
-               .start     = SA1100_CS0_PHYS,
-               .end       = SA1100_CS0_PHYS + SZ_16M -1,
-               .flags     = IORESOURCE_MEM,
-       }, {
-               .start     = SA1100_CS1_PHYS,
-               .end       = SA1100_CS1_PHYS + SZ_16M -1,
-               .flags     = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_16M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M),
+};
+
+static struct ucb1x00_plat_data simpad_ucb1x00_data = {
+       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
 };
 
 static struct mcp_plat_data simpad_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
-       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+       .codec_pdata    = &simpad_ucb1x00_data,
 };
 
 
@@ -376,6 +374,7 @@ static int __init simpad_init(void)
 
        pm_power_off = simpad_power_off;
 
+       sa11x0_ppc_configure_mcp();
        sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
        sa11x0_register_mcp(&simpad_mcp_data);
@@ -394,6 +393,7 @@ MACHINE_START(SIMPAD, "Simpad")
        /* Maintainer: Holger Freyther */
        .atag_offset    = 0x100,
        .map_io         = simpad_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .restart        = sa11x0_restart,
index e822331..30cc672 100644 (file)
  *
  * Causes sa11x0 to enter sleep state
  *
+ * Must be aligned to a cacheline.
  */
-
+       .balign 32
 ENTRY(sa1100_finish_suspend)
        @ disable clock switching
        mcr     p15, 0, r1, c15, c2, 2
 
-        @ Adjust memory timing before lowering CPU clock
-       @ Clock speed adjustment without changing memory timing makes
-       @ CPU hang in some cases
-        ldr     r0, =MDREFR
-        ldr     r1, [r0]
-        orr     r1, r1, #MDREFR_K1DB2
-        str     r1, [r0]
+       ldr     r6, =MDREFR
+       ldr     r4, [r6]
+       orr     r4, r4, #MDREFR_K1DB2
+       ldr     r5, =PPCR
+
+       @ Pre-load __udelay into the I-cache
+       mov     r0, #1
+       bl      __udelay
+       mov     r0, r0
+
+       @ The following must all exist in a single cache line to
+       @ avoid accessing memory until this sequence is complete,
+       @ otherwise we occasionally hang.
+
+       @ Adjust memory timing before lowering CPU clock
+       str     r4, [r6]
 
        @ delay 90us and set CPU PLL to lowest speed
        @ fixes resume problem on high speed SA1110
        mov     r0, #90
        bl      __udelay
-       ldr     r0, =PPCR
        mov     r1, #0
-       str     r1, [r0]
+       str     r1, [r5]
        mov     r0, #90
        bl      __udelay
 
@@ -85,12 +94,10 @@ ENTRY(sa1100_finish_suspend)
        bic     r5, r5, #FMsk(MSC_RT)
        bic     r5, r5, #FMsk(MSC_RT)<<16
 
-       ldr     r6, =MDREFR
-
        ldr     r7, [r6]
-bic    r7, r7, #0x0000FF00
-bic    r7, r7, #0x000000F0
-orr    r8, r7, #MDREFR_SLFRSH
+       bic     r7, r7, #0x0000FF00
+       bic     r7, r7, #0x000000F0
+       orr     r8, r7, #MDREFR_SLFRSH
 
        ldr     r9, =MDCNFG
        ldr     r10, [r9]
index b20ff93..e22fca9 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/hardware/ssp.h>
 
 #define TIMEOUT 100000
index 69e3353..6af26e8 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static u32 notrace sa1100_read_sched_clock(void)
 {
index f1a2749..4a6c46d 100644 (file)
@@ -252,6 +252,15 @@ config EP93XX_DMA
        help
          Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
 
+config DMA_SA11X0
+       tristate "SA-11x0 DMA support"
+       depends on ARCH_SA1100
+       select DMA_ENGINE
+       help
+         Support the DMA engine found on Intel StrongARM SA-1100 and
+         SA-1110 SoCs.  This DMA engine can only be used with on-chip
+         devices.
+
 config DMA_ENGINE
        bool
 
index 009a222..86b795b 100644 (file)
@@ -27,3 +27,4 @@ obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
new file mode 100644 (file)
index 0000000..16a6b48
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * SA11x0 DMAengine support
+ *
+ * Copyright (C) 2012 Russell King
+ *   Derived in part from arch/arm/mach-sa1100/dma.c,
+ *   Copyright (C) 2000, 2001 by Nicolas Pitre
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sa11x0-dma.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define NR_PHY_CHAN    6
+#define DMA_ALIGN      3
+#define DMA_MAX_SIZE   0x1fff
+#define DMA_CHUNK_SIZE 0x1000
+
+#define DMA_DDAR       0x00
+#define DMA_DCSR_S     0x04
+#define DMA_DCSR_C     0x08
+#define DMA_DCSR_R     0x0c
+#define DMA_DBSA       0x10
+#define DMA_DBTA       0x14
+#define DMA_DBSB       0x18
+#define DMA_DBTB       0x1c
+#define DMA_SIZE       0x20
+
+#define DCSR_RUN       (1 << 0)
+#define DCSR_IE                (1 << 1)
+#define DCSR_ERROR     (1 << 2)
+#define DCSR_DONEA     (1 << 3)
+#define DCSR_STRTA     (1 << 4)
+#define DCSR_DONEB     (1 << 5)
+#define DCSR_STRTB     (1 << 6)
+#define DCSR_BIU       (1 << 7)
+
+#define DDAR_RW                (1 << 0)        /* 0 = W, 1 = R */
+#define DDAR_E         (1 << 1)        /* 0 = LE, 1 = BE */
+#define DDAR_BS                (1 << 2)        /* 0 = BS4, 1 = BS8 */
+#define DDAR_DW                (1 << 3)        /* 0 = 8b, 1 = 16b */
+#define DDAR_Ser0UDCTr (0x0 << 4)
+#define DDAR_Ser0UDCRc (0x1 << 4)
+#define DDAR_Ser1SDLCTr        (0x2 << 4)
+#define DDAR_Ser1SDLCRc        (0x3 << 4)
+#define DDAR_Ser1UARTTr        (0x4 << 4)
+#define DDAR_Ser1UARTRc        (0x5 << 4)
+#define DDAR_Ser2ICPTr (0x6 << 4)
+#define DDAR_Ser2ICPRc (0x7 << 4)
+#define DDAR_Ser3UARTTr        (0x8 << 4)
+#define DDAR_Ser3UARTRc        (0x9 << 4)
+#define DDAR_Ser4MCP0Tr        (0xa << 4)
+#define DDAR_Ser4MCP0Rc        (0xb << 4)
+#define DDAR_Ser4MCP1Tr        (0xc << 4)
+#define DDAR_Ser4MCP1Rc        (0xd << 4)
+#define DDAR_Ser4SSPTr (0xe << 4)
+#define DDAR_Ser4SSPRc (0xf << 4)
+
+struct sa11x0_dma_sg {
+       u32                     addr;
+       u32                     len;
+};
+
+struct sa11x0_dma_desc {
+       struct dma_async_tx_descriptor tx;
+       u32                     ddar;
+       size_t                  size;
+
+       /* maybe protected by c->lock */
+       struct list_head        node;
+       unsigned                sglen;
+       struct sa11x0_dma_sg    sg[0];
+};
+
+struct sa11x0_dma_phy;
+
+struct sa11x0_dma_chan {
+       struct dma_chan         chan;
+       spinlock_t              lock;
+       dma_cookie_t            lc;
+
+       /* protected by c->lock */
+       struct sa11x0_dma_phy   *phy;
+       enum dma_status         status;
+       struct list_head        desc_submitted;
+       struct list_head        desc_issued;
+
+       /* protected by d->lock */
+       struct list_head        node;
+
+       u32                     ddar;
+       const char              *name;
+};
+
+struct sa11x0_dma_phy {
+       void __iomem            *base;
+       struct sa11x0_dma_dev   *dev;
+       unsigned                num;
+
+       struct sa11x0_dma_chan  *vchan;
+
+       /* Protected by c->lock */
+       unsigned                sg_load;
+       struct sa11x0_dma_desc  *txd_load;
+       unsigned                sg_done;
+       struct sa11x0_dma_desc  *txd_done;
+#ifdef CONFIG_PM_SLEEP
+       u32                     dbs[2];
+       u32                     dbt[2];
+       u32                     dcsr;
+#endif
+};
+
+struct sa11x0_dma_dev {
+       struct dma_device       slave;
+       void __iomem            *base;
+       spinlock_t              lock;
+       struct tasklet_struct   task;
+       struct list_head        chan_pending;
+       struct list_head        desc_complete;
+       struct sa11x0_dma_phy   phy[NR_PHY_CHAN];
+};
+
+static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct sa11x0_dma_chan, chan);
+}
+
+static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
+{
+       return container_of(dmadev, struct sa11x0_dma_dev, slave);
+}
+
+static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx)
+{
+       return container_of(tx, struct sa11x0_dma_desc, tx);
+}
+
+static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
+{
+       if (list_empty(&c->desc_issued))
+               return NULL;
+
+       return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
+}
+
+static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
+{
+       list_del(&txd->node);
+       p->txd_load = txd;
+       p->sg_load = 0;
+
+       dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
+               p->num, txd, txd->tx.cookie, txd->ddar);
+}
+
+static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
+       struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = p->txd_load;
+       struct sa11x0_dma_sg *sg;
+       void __iomem *base = p->base;
+       unsigned dbsx, dbtx;
+       u32 dcsr;
+
+       if (!txd)
+               return;
+
+       dcsr = readl_relaxed(base + DMA_DCSR_R);
+
+       /* Don't try to load the next transfer if both buffers are started */
+       if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
+               return;
+
+       if (p->sg_load == txd->sglen) {
+               struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
+
+               /*
+                * We have reached the end of the current descriptor.
+                * Peek at the next descriptor, and if compatible with
+                * the current, start processing it.
+                */
+               if (txn && txn->ddar == txd->ddar) {
+                       txd = txn;
+                       sa11x0_dma_start_desc(p, txn);
+               } else {
+                       p->txd_load = NULL;
+                       return;
+               }
+       }
+
+       sg = &txd->sg[p->sg_load++];
+
+       /* Select buffer to load according to channel status */
+       if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
+           ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
+               dbsx = DMA_DBSA;
+               dbtx = DMA_DBTA;
+               dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
+       } else {
+               dbsx = DMA_DBSB;
+               dbtx = DMA_DBTB;
+               dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
+       }
+
+       writel_relaxed(sg->addr, base + dbsx);
+       writel_relaxed(sg->len, base + dbtx);
+       writel(dcsr, base + DMA_DCSR_S);
+
+       dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
+               p->num, dcsr,
+               'A' + (dbsx == DMA_DBSB), sg->addr,
+               'A' + (dbtx == DMA_DBTB), sg->len);
+}
+
+static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
+       struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = p->txd_done;
+
+       if (++p->sg_done == txd->sglen) {
+               struct sa11x0_dma_dev *d = p->dev;
+
+               dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
+                       p->num, p->txd_done, p->txd_done->tx.cookie);
+
+               c->lc = txd->tx.cookie;
+
+               spin_lock(&d->lock);
+               list_add_tail(&txd->node, &d->desc_complete);
+               spin_unlock(&d->lock);
+
+               p->sg_done = 0;
+               p->txd_done = p->txd_load;
+
+               tasklet_schedule(&d->task);
+       }
+
+       sa11x0_dma_start_sg(p, c);
+}
+
+static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
+{
+       struct sa11x0_dma_phy *p = dev_id;
+       struct sa11x0_dma_dev *d = p->dev;
+       struct sa11x0_dma_chan *c;
+       u32 dcsr;
+
+       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+       if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
+               return IRQ_NONE;
+
+       /* Clear reported status bits */
+       writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
+               p->base + DMA_DCSR_C);
+
+       dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
+
+       if (dcsr & DCSR_ERROR) {
+               dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
+                       p->num, dcsr,
+                       readl_relaxed(p->base + DMA_DDAR),
+                       readl_relaxed(p->base + DMA_DBSA),
+                       readl_relaxed(p->base + DMA_DBTA),
+                       readl_relaxed(p->base + DMA_DBSB),
+                       readl_relaxed(p->base + DMA_DBTB));
+       }
+
+       c = p->vchan;
+       if (c) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&c->lock, flags);
+               /*
+                * Now that we're holding the lock, check that the vchan
+                * really is associated with this pchan before touching the
+                * hardware.  This should always succeed, because we won't
+                * change p->vchan or c->phy while the channel is actively
+                * transferring.
+                */
+               if (c->phy == p) {
+                       if (dcsr & DCSR_DONEA)
+                               sa11x0_dma_complete(p, c);
+                       if (dcsr & DCSR_DONEB)
+                               sa11x0_dma_complete(p, c);
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
+
+       /* If the issued list is empty, we have no further txds to process */
+       if (txd) {
+               struct sa11x0_dma_phy *p = c->phy;
+
+               sa11x0_dma_start_desc(p, txd);
+               p->txd_done = txd;
+               p->sg_done = 0;
+
+               /* The channel should not have any transfers started */
+               WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
+                                     (DCSR_STRTA | DCSR_STRTB));
+
+               /* Clear the run and start bits before changing DDAR */
+               writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
+                              p->base + DMA_DCSR_C);
+               writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+               /* Try to start both buffers */
+               sa11x0_dma_start_sg(p, c);
+               sa11x0_dma_start_sg(p, c);
+       }
+}
+
+static void sa11x0_dma_tasklet(unsigned long arg)
+{
+       struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
+       struct sa11x0_dma_phy *p;
+       struct sa11x0_dma_chan *c;
+       struct sa11x0_dma_desc *txd, *txn;
+       LIST_HEAD(head);
+       unsigned pch, pch_alloc = 0;
+
+       dev_dbg(d->slave.dev, "tasklet enter\n");
+
+       /* Get the completed tx descriptors */
+       spin_lock_irq(&d->lock);
+       list_splice_init(&d->desc_complete, &head);
+       spin_unlock_irq(&d->lock);
+
+       list_for_each_entry(txd, &head, node) {
+               c = to_sa11x0_dma_chan(txd->tx.chan);
+
+               dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
+                       c, txd, txd->tx.cookie);
+
+               spin_lock_irq(&c->lock);
+               p = c->phy;
+               if (p) {
+                       if (!p->txd_done)
+                               sa11x0_dma_start_txd(c);
+                       if (!p->txd_done) {
+                               /* No current txd associated with this channel */
+                               dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
+
+                               /* Mark this channel free */
+                               c->phy = NULL;
+                               p->vchan = NULL;
+                       }
+               }
+               spin_unlock_irq(&c->lock);
+       }
+
+       spin_lock_irq(&d->lock);
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               p = &d->phy[pch];
+
+               if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
+                       c = list_first_entry(&d->chan_pending,
+                               struct sa11x0_dma_chan, node);
+                       list_del_init(&c->node);
+
+                       pch_alloc |= 1 << pch;
+
+                       /* Mark this channel allocated */
+                       p->vchan = c;
+
+                       dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c);
+               }
+       }
+       spin_unlock_irq(&d->lock);
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               if (pch_alloc & (1 << pch)) {
+                       p = &d->phy[pch];
+                       c = p->vchan;
+
+                       spin_lock_irq(&c->lock);
+                       c->phy = p;
+
+                       sa11x0_dma_start_txd(c);
+                       spin_unlock_irq(&c->lock);
+               }
+       }
+
+       /* Now free the completed tx descriptor, and call their callbacks */
+       list_for_each_entry_safe(txd, txn, &head, node) {
+               dma_async_tx_callback callback = txd->tx.callback;
+               void *callback_param = txd->tx.callback_param;
+
+               dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
+                       txd, txd->tx.cookie);
+
+               kfree(txd);
+
+               if (callback)
+                       callback(callback_param);
+       }
+
+       dev_dbg(d->slave.dev, "tasklet exit\n");
+}
+
+
+static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
+{
+       struct sa11x0_dma_desc *txd, *txn;
+
+       list_for_each_entry_safe(txd, txn, head, node) {
+               dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
+               kfree(txd);
+       }
+}
+
+static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       return 0;
+}
+
+static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&c->lock, flags);
+       spin_lock(&d->lock);
+       list_del_init(&c->node);
+       spin_unlock(&d->lock);
+
+       list_splice_tail_init(&c->desc_submitted, &head);
+       list_splice_tail_init(&c->desc_issued, &head);
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       sa11x0_dma_desc_free(d, &head);
+}
+
+static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
+{
+       unsigned reg;
+       u32 dcsr;
+
+       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+       if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
+           (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
+               reg = DMA_DBSA;
+       else
+               reg = DMA_DBSB;
+
+       return readl_relaxed(p->base + reg);
+}
+
+static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
+       dma_cookie_t cookie, struct dma_tx_state *state)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       struct sa11x0_dma_phy *p;
+       struct sa11x0_dma_desc *txd;
+       dma_cookie_t last_used, last_complete;
+       unsigned long flags;
+       enum dma_status ret;
+       size_t bytes = 0;
+
+       last_used = c->chan.cookie;
+       last_complete = c->lc;
+
+       ret = dma_async_is_complete(cookie, last_complete, last_used);
+       if (ret == DMA_SUCCESS) {
+               dma_set_tx_state(state, last_complete, last_used, 0);
+               return ret;
+       }
+
+       spin_lock_irqsave(&c->lock, flags);
+       p = c->phy;
+       ret = c->status;
+       if (p) {
+               dma_addr_t addr = sa11x0_dma_pos(p);
+
+               dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
+
+               txd = p->txd_done;
+               if (txd) {
+                       unsigned i;
+
+                       for (i = 0; i < txd->sglen; i++) {
+                               dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
+                                       i, txd->sg[i].addr, txd->sg[i].len);
+                               if (addr >= txd->sg[i].addr &&
+                                   addr < txd->sg[i].addr + txd->sg[i].len) {
+                                       unsigned len;
+
+                                       len = txd->sg[i].len -
+                                               (addr - txd->sg[i].addr);
+                                       dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
+                                               i, len);
+                                       bytes += len;
+                                       i++;
+                                       break;
+                               }
+                       }
+                       for (; i < txd->sglen; i++) {
+                               dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
+                                       i, txd->sg[i].addr, txd->sg[i].len);
+                               bytes += txd->sg[i].len;
+                       }
+               }
+               if (txd != p->txd_load && p->txd_load)
+                       bytes += p->txd_load->size;
+       }
+       list_for_each_entry(txd, &c->desc_issued, node) {
+               bytes += txd->size;
+       }
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       dma_set_tx_state(state, last_complete, last_used, bytes);
+
+       dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
+
+       return ret;
+}
+
+/*
+ * Move pending txds to the issued list, and re-init pending list.
+ * If not already pending, add this channel to the list of pending
+ * channels and trigger the tasklet to run.
+ */
+static void sa11x0_dma_issue_pending(struct dma_chan *chan)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->lock, flags);
+       list_splice_tail_init(&c->desc_submitted, &c->desc_issued);
+       if (!list_empty(&c->desc_issued)) {
+               spin_lock(&d->lock);
+               if (!c->phy && list_empty(&c->node)) {
+                       list_add_tail(&c->node, &d->chan_pending);
+                       tasklet_schedule(&d->task);
+                       dev_dbg(d->slave.dev, "vchan %p: issued\n", c);
+               }
+               spin_unlock(&d->lock);
+       } else
+               dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c);
+       spin_unlock_irqrestore(&c->lock, flags);
+}
+
+static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
+       struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->lock, flags);
+       c->chan.cookie += 1;
+       if (c->chan.cookie < 0)
+               c->chan.cookie = 1;
+       txd->tx.cookie = c->chan.cookie;
+
+       list_add_tail(&txd->node, &c->desc_submitted);
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
+               c, txd, txd->tx.cookie);
+
+       return txd->tx.cookie;
+}
+
+static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
+       enum dma_transfer_direction dir, unsigned long flags)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_desc *txd;
+       struct scatterlist *sgent;
+       unsigned i, j = sglen;
+       size_t size = 0;
+
+       /* SA11x0 channels can only operate in their native direction */
+       if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
+               dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
+                       c, c->ddar, dir);
+               return NULL;
+       }
+
+       /* Do not allow zero-sized txds */
+       if (sglen == 0)
+               return NULL;
+
+       for_each_sg(sg, sgent, sglen, i) {
+               dma_addr_t addr = sg_dma_address(sgent);
+               unsigned int len = sg_dma_len(sgent);
+
+               if (len > DMA_MAX_SIZE)
+                       j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
+               if (addr & DMA_ALIGN) {
+                       dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
+                               c, addr);
+                       return NULL;
+               }
+       }
+
+       txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
+       if (!txd) {
+               dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c);
+               return NULL;
+       }
+
+       j = 0;
+       for_each_sg(sg, sgent, sglen, i) {
+               dma_addr_t addr = sg_dma_address(sgent);
+               unsigned len = sg_dma_len(sgent);
+
+               size += len;
+
+               do {
+                       unsigned tlen = len;
+
+                       /*
+                        * Check whether the transfer will fit.  If not, try
+                        * to split the transfer up such that we end up with
+                        * equal chunks - but make sure that we preserve the
+                        * alignment.  This avoids small segments.
+                        */
+                       if (tlen > DMA_MAX_SIZE) {
+                               unsigned mult = DIV_ROUND_UP(tlen,
+                                       DMA_MAX_SIZE & ~DMA_ALIGN);
+
+                               tlen = (tlen / mult) & ~DMA_ALIGN;
+                       }
+
+                       txd->sg[j].addr = addr;
+                       txd->sg[j].len = tlen;
+
+                       addr += tlen;
+                       len -= tlen;
+                       j++;
+               } while (len);
+       }
+
+       dma_async_tx_descriptor_init(&txd->tx, &c->chan);
+       txd->tx.flags = flags;
+       txd->tx.tx_submit = sa11x0_dma_tx_submit;
+       txd->ddar = c->ddar;
+       txd->size = size;
+       txd->sglen = j;
+
+       dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
+               c, txd, txd->size, txd->sglen);
+
+       return &txd->tx;
+}
+
+static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
+{
+       u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
+       dma_addr_t addr;
+       enum dma_slave_buswidth width;
+       u32 maxburst;
+
+       if (ddar & DDAR_RW) {
+               addr = cfg->src_addr;
+               width = cfg->src_addr_width;
+               maxburst = cfg->src_maxburst;
+       } else {
+               addr = cfg->dst_addr;
+               width = cfg->dst_addr_width;
+               maxburst = cfg->dst_maxburst;
+       }
+
+       if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
+            width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
+           (maxburst != 4 && maxburst != 8))
+               return -EINVAL;
+
+       if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
+               ddar |= DDAR_DW;
+       if (maxburst == 8)
+               ddar |= DDAR_BS;
+
+       dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
+               c, addr, width, maxburst);
+
+       c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
+
+       return 0;
+}
+
+static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       struct sa11x0_dma_phy *p;
+       LIST_HEAD(head);
+       unsigned long flags;
+       int ret;
+
+       switch (cmd) {
+       case DMA_SLAVE_CONFIG:
+               return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
+
+       case DMA_TERMINATE_ALL:
+               dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c);
+               /* Clear the tx descriptor lists */
+               spin_lock_irqsave(&c->lock, flags);
+               list_splice_tail_init(&c->desc_submitted, &head);
+               list_splice_tail_init(&c->desc_issued, &head);
+
+               p = c->phy;
+               if (p) {
+                       struct sa11x0_dma_desc *txd, *txn;
+
+                       dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
+                       /* vchan is assigned to a pchan - stop the channel */
+                       writel(DCSR_RUN | DCSR_IE |
+                               DCSR_STRTA | DCSR_DONEA |
+                               DCSR_STRTB | DCSR_DONEB,
+                               p->base + DMA_DCSR_C);
+
+                       list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
+                               if (txd->tx.chan == &c->chan)
+                                       list_move(&txd->node, &head);
+
+                       if (p->txd_load) {
+                               if (p->txd_load != p->txd_done)
+                                       list_add_tail(&p->txd_load->node, &head);
+                               p->txd_load = NULL;
+                       }
+                       if (p->txd_done) {
+                               list_add_tail(&p->txd_done->node, &head);
+                               p->txd_done = NULL;
+                       }
+                       c->phy = NULL;
+                       spin_lock(&d->lock);
+                       p->vchan = NULL;
+                       spin_unlock(&d->lock);
+                       tasklet_schedule(&d->task);
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               sa11x0_dma_desc_free(d, &head);
+               ret = 0;
+               break;
+
+       case DMA_PAUSE:
+               dev_dbg(d->slave.dev, "vchan %p: pause\n", c);
+               spin_lock_irqsave(&c->lock, flags);
+               if (c->status == DMA_IN_PROGRESS) {
+                       c->status = DMA_PAUSED;
+
+                       p = c->phy;
+                       if (p) {
+                               writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+                       } else {
+                               spin_lock(&d->lock);
+                               list_del_init(&c->node);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               ret = 0;
+               break;
+
+       case DMA_RESUME:
+               dev_dbg(d->slave.dev, "vchan %p: resume\n", c);
+               spin_lock_irqsave(&c->lock, flags);
+               if (c->status == DMA_PAUSED) {
+                       c->status = DMA_IN_PROGRESS;
+
+                       p = c->phy;
+                       if (p) {
+                               writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
+                       } else if (!list_empty(&c->desc_issued)) {
+                               spin_lock(&d->lock);
+                               list_add_tail(&c->node, &d->chan_pending);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               ret = 0;
+               break;
+
+       default:
+               ret = -ENXIO;
+               break;
+       }
+
+       return ret;
+}
+
+struct sa11x0_dma_channel_desc {
+       u32 ddar;
+       const char *name;
+};
+
+#define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
+static const struct sa11x0_dma_channel_desc chan_desc[] = {
+       CD(Ser0UDCTr, 0),
+       CD(Ser0UDCRc, DDAR_RW),
+       CD(Ser1SDLCTr, 0),
+       CD(Ser1SDLCRc, DDAR_RW),
+       CD(Ser1UARTTr, 0),
+       CD(Ser1UARTRc, DDAR_RW),
+       CD(Ser2ICPTr, 0),
+       CD(Ser2ICPRc, DDAR_RW),
+       CD(Ser3UARTTr, 0),
+       CD(Ser3UARTRc, DDAR_RW),
+       CD(Ser4MCP0Tr, 0),
+       CD(Ser4MCP0Rc, DDAR_RW),
+       CD(Ser4MCP1Tr, 0),
+       CD(Ser4MCP1Rc, DDAR_RW),
+       CD(Ser4SSPTr, 0),
+       CD(Ser4SSPRc, DDAR_RW),
+};
+
+static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
+       struct device *dev)
+{
+       unsigned i;
+
+       dmadev->chancnt = ARRAY_SIZE(chan_desc);
+       INIT_LIST_HEAD(&dmadev->channels);
+       dmadev->dev = dev;
+       dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
+       dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
+       dmadev->device_control = sa11x0_dma_control;
+       dmadev->device_tx_status = sa11x0_dma_tx_status;
+       dmadev->device_issue_pending = sa11x0_dma_issue_pending;
+
+       for (i = 0; i < dmadev->chancnt; i++) {
+               struct sa11x0_dma_chan *c;
+
+               c = kzalloc(sizeof(*c), GFP_KERNEL);
+               if (!c) {
+                       dev_err(dev, "no memory for channel %u\n", i);
+                       return -ENOMEM;
+               }
+
+               c->chan.device = dmadev;
+               c->status = DMA_IN_PROGRESS;
+               c->ddar = chan_desc[i].ddar;
+               c->name = chan_desc[i].name;
+               spin_lock_init(&c->lock);
+               INIT_LIST_HEAD(&c->desc_submitted);
+               INIT_LIST_HEAD(&c->desc_issued);
+               INIT_LIST_HEAD(&c->node);
+               list_add_tail(&c->chan.device_node, &dmadev->channels);
+       }
+
+       return dma_async_device_register(dmadev);
+}
+
+static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
+       void *data)
+{
+       int irq = platform_get_irq(pdev, nr);
+
+       if (irq <= 0)
+               return -ENXIO;
+
+       return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
+}
+
+static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
+       void *data)
+{
+       int irq = platform_get_irq(pdev, nr);
+       if (irq > 0)
+               free_irq(irq, data);
+}
+
+static void sa11x0_dma_free_channels(struct dma_device *dmadev)
+{
+       struct sa11x0_dma_chan *c, *cn;
+
+       list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) {
+               list_del(&c->chan.device_node);
+               kfree(c);
+       }
+}
+
+static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
+{
+       struct sa11x0_dma_dev *d;
+       struct resource *res;
+       unsigned i;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       d = kzalloc(sizeof(*d), GFP_KERNEL);
+       if (!d) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       spin_lock_init(&d->lock);
+       INIT_LIST_HEAD(&d->chan_pending);
+       INIT_LIST_HEAD(&d->desc_complete);
+
+       d->base = ioremap(res->start, resource_size(res));
+       if (!d->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
+
+       for (i = 0; i < NR_PHY_CHAN; i++) {
+               struct sa11x0_dma_phy *p = &d->phy[i];
+
+               p->dev = d;
+               p->num = i;
+               p->base = d->base + i * DMA_SIZE;
+               writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
+                       DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
+                       p->base + DMA_DCSR_C);
+               writel_relaxed(0, p->base + DMA_DDAR);
+
+               ret = sa11x0_dma_request_irq(pdev, i, p);
+               if (ret) {
+                       while (i) {
+                               i--;
+                               sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+                       }
+                       goto err_irq;
+               }
+       }
+
+       dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+       d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
+       ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
+       if (ret) {
+               dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
+                       ret);
+               goto err_slave_reg;
+       }
+
+       platform_set_drvdata(pdev, d);
+       return 0;
+
+ err_slave_reg:
+       sa11x0_dma_free_channels(&d->slave);
+       for (i = 0; i < NR_PHY_CHAN; i++)
+               sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+ err_irq:
+       tasklet_kill(&d->task);
+       iounmap(d->base);
+ err_ioremap:
+       kfree(d);
+ err_alloc:
+       return ret;
+}
+
+static int __devexit sa11x0_dma_remove(struct platform_device *pdev)
+{
+       struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
+       unsigned pch;
+
+       dma_async_device_unregister(&d->slave);
+
+       sa11x0_dma_free_channels(&d->slave);
+       for (pch = 0; pch < NR_PHY_CHAN; pch++)
+               sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
+       tasklet_kill(&d->task);
+       iounmap(d->base);
+       kfree(d);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sa11x0_dma_suspend(struct device *dev)
+{
+       struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+       unsigned pch;
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               struct sa11x0_dma_phy *p = &d->phy[pch];
+               u32 dcsr, saved_dcsr;
+
+               dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+               if (dcsr & DCSR_RUN) {
+                       writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+                       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+               }
+
+               saved_dcsr &= DCSR_RUN | DCSR_IE;
+               if (dcsr & DCSR_BIU) {
+                       p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
+                       p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
+                       p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
+                       p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
+                       saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
+                                     (dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
+               } else {
+                       p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
+                       p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
+                       p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
+                       p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
+                       saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
+               }
+               p->dcsr = saved_dcsr;
+
+               writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
+       }
+
+       return 0;
+}
+
+static int sa11x0_dma_resume(struct device *dev)
+{
+       struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+       unsigned pch;
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               struct sa11x0_dma_phy *p = &d->phy[pch];
+               struct sa11x0_dma_desc *txd = NULL;
+               u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+               WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
+
+               if (p->txd_done)
+                       txd = p->txd_done;
+               else if (p->txd_load)
+                       txd = p->txd_load;
+
+               if (!txd)
+                       continue;
+
+               writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+               writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
+               writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
+               writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
+               writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
+               writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops sa11x0_dma_pm_ops = {
+       .suspend_noirq = sa11x0_dma_suspend,
+       .resume_noirq = sa11x0_dma_resume,
+       .freeze_noirq = sa11x0_dma_suspend,
+       .thaw_noirq = sa11x0_dma_resume,
+       .poweroff_noirq = sa11x0_dma_suspend,
+       .restore_noirq = sa11x0_dma_resume,
+};
+
+static struct platform_driver sa11x0_dma_driver = {
+       .driver = {
+               .name   = "sa11x0-dma",
+               .owner  = THIS_MODULE,
+               .pm     = &sa11x0_dma_pm_ops,
+       },
+       .probe          = sa11x0_dma_probe,
+       .remove         = __devexit_p(sa11x0_dma_remove),
+};
+
+bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+       if (chan->device->dev->driver == &sa11x0_dma_driver.driver) {
+               struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+               const char *p = param;
+
+               return !strcmp(c->name, p);
+       }
+       return false;
+}
+EXPORT_SYMBOL(sa11x0_dma_filter_fn);
+
+static int __init sa11x0_dma_init(void)
+{
+       return platform_driver_register(&sa11x0_dma_driver);
+}
+subsys_initcall(sa11x0_dma_init);
+
+static void __exit sa11x0_dma_exit(void)
+{
+       platform_driver_unregister(&sa11x0_dma_driver);
+}
+module_exit(sa11x0_dma_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SA-11x0 DMA driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sa11x0-dma");
index 7eecf69..8ea3b33 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
index eeafc30..9d639fa 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <mach/jornada720.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
index 44fc8b4..5ebabe3 100644 (file)
 
 #include <asm/hardware/sa1111.h>
 
+#define PS2CR          0x0000
+#define PS2STAT                0x0004
+#define PS2DATA                0x0008
+#define PS2CLKDIV      0x000c
+#define PS2PRECNT      0x0010
+
+#define PS2CR_ENA      0x08
+#define PS2CR_FKD      0x02
+#define PS2CR_FKC      0x01
+
+#define PS2STAT_STP    0x0100
+#define PS2STAT_TXE    0x0080
+#define PS2STAT_TXB    0x0040
+#define PS2STAT_RXF    0x0020
+#define PS2STAT_RXB    0x0010
+#define PS2STAT_ENA    0x0008
+#define PS2STAT_RXP    0x0004
+#define PS2STAT_KBD    0x0002
+#define PS2STAT_KBC    0x0001
+
 struct ps2if {
        struct serio            *io;
        struct sa1111_dev       *dev;
@@ -45,22 +65,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
        struct ps2if *ps2if = dev_id;
        unsigned int scancode, flag, status;
 
-       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       status = sa1111_readl(ps2if->base + PS2STAT);
        while (status & PS2STAT_RXF) {
                if (status & PS2STAT_STP)
-                       sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
+                       sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
 
                flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
                       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
-               scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
+               scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
 
                if (hweight8(scancode) & 1)
                        flag ^= SERIO_PARITY;
 
                serio_interrupt(ps2if->io, scancode, flag);
 
-               status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+               status = sa1111_readl(ps2if->base + PS2STAT);
         }
 
         return IRQ_HANDLED;
@@ -75,12 +95,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
        unsigned int status;
 
        spin_lock(&ps2if->lock);
-       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       status = sa1111_readl(ps2if->base + PS2STAT);
        if (ps2if->head == ps2if->tail) {
                disable_irq_nosync(irq);
                /* done */
        } else if (status & PS2STAT_TXE) {
-               sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+               sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
                ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
        }
        spin_unlock(&ps2if->lock);
@@ -103,8 +123,8 @@ static int ps2_write(struct serio *io, unsigned char val)
        /*
         * 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);
+       if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
+               sa1111_writel(val, ps2if->base + PS2DATA);
        } else {
                if (ps2if->head == ps2if->tail)
                        enable_irq(ps2if->dev->irq[1]);
@@ -124,13 +144,16 @@ static int ps2_open(struct serio *io)
        struct ps2if *ps2if = io->port_data;
        int ret;
 
-       sa1111_enable_device(ps2if->dev);
+       ret = sa1111_enable_device(ps2if->dev);
+       if (ret)
+               return ret;
 
        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",
                        ps2if->dev->irq[0], ret);
+               sa1111_disable_device(ps2if->dev);
                return ret;
        }
 
@@ -140,6 +163,7 @@ static int ps2_open(struct serio *io)
                printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
                        ps2if->dev->irq[1], ret);
                free_irq(ps2if->dev->irq[0], ps2if);
+               sa1111_disable_device(ps2if->dev);
                return ret;
        }
 
@@ -147,7 +171,7 @@ static int ps2_open(struct serio *io)
 
        enable_irq_wake(ps2if->dev->irq[0]);
 
-       sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
        return 0;
 }
 
@@ -155,7 +179,7 @@ static void ps2_close(struct serio *io)
 {
        struct ps2if *ps2if = io->port_data;
 
-       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(0, ps2if->base + PS2CR);
 
        disable_irq_wake(ps2if->dev->irq[0]);
 
@@ -175,7 +199,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if)
        int maxread = 100;
 
        while (maxread--) {
-               if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
+               if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
                        break;
        }
 }
@@ -185,11 +209,11 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
 {
        unsigned int val;
 
-       sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
 
        udelay(2);
 
-       val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       val = sa1111_readl(ps2if->base + PS2STAT);
        return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 
@@ -220,7 +244,7 @@ static int __devinit ps2_test(struct ps2if *ps2if)
                ret = -ENODEV;
        }
 
-       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(0, ps2if->base + PS2CR);
 
        return ret;
 }
@@ -274,8 +298,8 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
        sa1111_enable_device(ps2if->dev);
 
        /* Incoming clock is 8MHz */
-       sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
-       sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
+       sa1111_writel(0, ps2if->base + PS2CLKDIV);
+       sa1111_writel(127, ps2if->base + PS2PRECNT);
 
        /*
         * Flush any pending input.
@@ -330,6 +354,7 @@ static int __devexit ps2_remove(struct sa1111_dev *dev)
 static struct sa1111_driver ps2_driver = {
        .drv = {
                .name   = "sa1111-ps2",
+               .owner  = THIS_MODULE,
        },
        .devid          = SA1111_DEVID_PS2,
        .probe          = ps2_probe,
index c3848ad..d9be6ea 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <mach/hardware.h>
 #include <mach/jornada720.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
index cd13e9f..28a301b 100644 (file)
@@ -847,8 +847,9 @@ config MCP_SA11X0
 
 # Chip drivers
 config MCP_UCB1200
-       tristate "Support for UCB1200 / UCB1300"
-       depends on MCP
+       bool "Support for UCB1200 / UCB1300"
+       depends on MCP_SA11X0
+       select MCP
 
 config MCP_UCB1200_TS
        tristate "Touchscreen interface support"
index 86cc3f7..6acf2e0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/string.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <asm/system.h>
 
 
@@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev)
        return 0;
 }
 
-static int mcp_bus_suspend(struct device *dev, pm_message_t state)
-{
-       struct mcp *mcp = to_mcp(dev);
-       int ret = 0;
-
-       if (dev->driver) {
-               struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-               ret = drv->suspend(mcp, state);
-       }
-       return ret;
-}
-
-static int mcp_bus_resume(struct device *dev)
-{
-       struct mcp *mcp = to_mcp(dev);
-       int ret = 0;
-
-       if (dev->driver) {
-               struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-               ret = drv->resume(mcp);
-       }
-       return ret;
-}
-
 static struct bus_type mcp_bus_type = {
        .name           = "mcp",
        .match          = mcp_bus_match,
        .probe          = mcp_bus_probe,
        .remove         = mcp_bus_remove,
-       .suspend        = mcp_bus_suspend,
-       .resume         = mcp_bus_resume,
 };
 
 /**
@@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
        mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
        if (mcp) {
                spin_lock_init(&mcp->lock);
+               device_initialize(&mcp->attached_device);
                mcp->attached_device.parent = parent;
                mcp->attached_device.bus = &mcp_bus_type;
                mcp->attached_device.dma_mask = parent->dma_mask;
@@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_add(struct mcp *mcp, void *pdata)
 {
+       mcp->attached_device.platform_data = pdata;
        dev_set_name(&mcp->attached_device, "mcp0");
-       return device_register(&mcp->attached_device);
+       return device_add(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_add);
+
+void mcp_host_del(struct mcp *mcp)
+{
+       device_del(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_register);
+EXPORT_SYMBOL(mcp_host_del);
 
-void mcp_host_unregister(struct mcp *mcp)
+void mcp_host_free(struct mcp *mcp)
 {
-       device_unregister(&mcp->attached_device);
+       put_device(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_unregister);
+EXPORT_SYMBOL(mcp_host_free);
 
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
index 02c53a0..1c0ceac 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/system.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
+#define DRIVER_NAME "sa11x0-mcp"
 
 struct mcp_sa11x0 {
-       u32     mccr0;
-       u32     mccr1;
+       void __iomem    *base0;
+       void __iomem    *base1;
+       u32             mccr0;
+       u32             mccr1;
 };
 
+/* Register offsets */
+#define MCCR0(m)       ((m)->base0 + 0x00)
+#define MCDR0(m)       ((m)->base0 + 0x08)
+#define MCDR1(m)       ((m)->base0 + 0x0c)
+#define MCDR2(m)       ((m)->base0 + 0x10)
+#define MCSR(m)                ((m)->base0 + 0x18)
+#define MCCR1(m)       ((m)->base1 + 0x00)
+
 #define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
 
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *m = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x00007f00;
-       mccr0 |= divisor << 8;
-       Ser4MCCR0 = mccr0;
+       m->mccr0 &= ~0x00007f00;
+       m->mccr0 |= divisor << 8;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *m = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x0000007f;
-       mccr0 |= divisor;
-       Ser4MCCR0 = mccr0;
+       m->mccr0 &= ~0x0000007f;
+       m->mccr0 |= divisor;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 static void
 mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
+       struct mcp_sa11x0 *m = priv(mcp);
        int ret = -ETIME;
        int i;
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CWC) {
+               if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
                        ret = 0;
                        break;
                }
@@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 static unsigned int
 mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
+       struct mcp_sa11x0 *m = priv(mcp);
        int ret = -ETIME;
        int i;
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+       writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CRC) {
-                       ret = Ser4MCDR2 & 0xffff;
+               if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
+                       ret = readl_relaxed(MCDR2(m)) & 0xffff;
                        break;
                }
        }
@@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-       Ser4MCSR = -1;
-       Ser4MCCR0 |= MCCR0_MCE;
+       struct mcp_sa11x0 *m = priv(mcp);
+
+       writel(-1, MCSR(m));
+       m->mccr0 |= MCCR0_MCE;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       struct mcp_sa11x0 *m = priv(mcp);
+
+       m->mccr0 &= ~MCCR0_MCE;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = {
        .disable                = mcp_sa11x0_disable,
 };
 
-static int mcp_sa11x0_probe(struct platform_device *pdev)
+static int mcp_sa11x0_probe(struct platform_device *dev)
 {
-       struct mcp_plat_data *data = pdev->dev.platform_data;
+       struct mcp_plat_data *data = dev->dev.platform_data;
+       struct resource *mem0, *mem1;
+       struct mcp_sa11x0 *m;
        struct mcp *mcp;
        int ret;
 
        if (!data)
                return -ENODEV;
 
-       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
-               return -EBUSY;
+       mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       if (!mem0 || !mem1)
+               return -ENXIO;
+
+       if (!request_mem_region(mem0->start, resource_size(mem0),
+                               DRIVER_NAME)) {
+               ret = -EBUSY;
+               goto err_mem0;
+       }
 
-       mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+       if (!request_mem_region(mem1->start, resource_size(mem1),
+                               DRIVER_NAME)) {
+               ret = -EBUSY;
+               goto err_mem1;
+       }
+
+       mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
        if (!mcp) {
                ret = -ENOMEM;
-               goto release;
+               goto err_alloc;
        }
 
        mcp->owner              = THIS_MODULE;
        mcp->ops                = &mcp_sa11x0;
        mcp->sclk_rate          = data->sclk_rate;
-       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
-       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
-       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
-       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
-       mcp->gpio_base          = data->gpio_base;
 
-       platform_set_drvdata(pdev, mcp);
+       m = priv(mcp);
+       m->mccr0 = data->mccr0 | 0x7f7f;
+       m->mccr1 = data->mccr1;
 
-       if (machine_is_assabet()) {
-               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+       m->base0 = ioremap(mem0->start, resource_size(mem0));
+       m->base1 = ioremap(mem1->start, resource_size(mem1));
+       if (!m->base0 || !m->base1) {
+               ret = -ENOMEM;
+               goto err_ioremap;
        }
 
-       /*
-        * Setup the PPC unit correctly.
-        */
-       PPDR &= ~PPC_RXD4;
-       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-       PSDR |= PPC_RXD4;
-       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       platform_set_drvdata(dev, mcp);
 
        /*
         * Initialise device.  Note that we initially
         * set the sampling rate to minimum.
         */
-       Ser4MCSR = -1;
-       Ser4MCCR1 = data->mccr1;
-       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+       writel_relaxed(-1, MCSR(m));
+       writel_relaxed(m->mccr1, MCCR1(m));
+       writel_relaxed(m->mccr0, MCCR0(m));
 
        /*
         * Calculate the read/write timeout (us) from the bit clock
@@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
                          mcp->sclk_rate;
 
-       ret = mcp_host_register(mcp);
+       ret = mcp_host_add(mcp, data->codec_pdata);
        if (ret == 0)
-               goto out;
+               return 0;
 
- release:
-       release_mem_region(0x80060000, 0x60);
-       platform_set_drvdata(pdev, NULL);
+       platform_set_drvdata(dev, NULL);
 
- out:
+ err_ioremap:
+       iounmap(m->base1);
+       iounmap(m->base0);
+       mcp_host_free(mcp);
+ err_alloc:
+       release_mem_region(mem1->start, resource_size(mem1));
+ err_mem1:
+       release_mem_region(mem0->start, resource_size(mem0));
+ err_mem0:
        return ret;
 }
 
 static int mcp_sa11x0_remove(struct platform_device *dev)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(mcp);
+       struct resource *mem0, *mem1;
+
+       if (m->mccr0 & MCCR0_MCE)
+               dev_warn(&dev->dev,
+                        "device left active (missing disable call?)\n");
+
+       mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
 
        platform_set_drvdata(dev, NULL);
-       mcp_host_unregister(mcp);
-       release_mem_region(0x80060000, 0x60);
+       mcp_host_del(mcp);
+       iounmap(m->base1);
+       iounmap(m->base0);
+       mcp_host_free(mcp);
+       release_mem_region(mem1->start, resource_size(mem1));
+       release_mem_region(mem0->start, resource_size(mem0));
 
        return 0;
 }
 
-static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int mcp_sa11x0_suspend(struct device *dev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
+
+       if (m->mccr0 & MCCR0_MCE)
+               dev_warn(dev, "device left active (missing disable call?)\n");
 
-       priv(mcp)->mccr0 = Ser4MCCR0;
-       priv(mcp)->mccr1 = Ser4MCCR1;
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
 
        return 0;
 }
 
-static int mcp_sa11x0_resume(struct platform_device *dev)
+static int mcp_sa11x0_resume(struct device *dev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
-       Ser4MCCR1 = priv(mcp)->mccr1;
-       Ser4MCCR0 = priv(mcp)->mccr0;
+       writel_relaxed(m->mccr1, MCCR1(m));
+       writel_relaxed(m->mccr0, MCCR0(m));
 
        return 0;
 }
-
-/*
- * The driver for the SA11x0 MCP port.
- */
-MODULE_ALIAS("platform:sa11x0-mcp");
+#endif
+
+static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend = mcp_sa11x0_suspend,
+       .freeze = mcp_sa11x0_suspend,
+       .poweroff = mcp_sa11x0_suspend,
+       .resume_noirq = mcp_sa11x0_resume,
+       .thaw_noirq = mcp_sa11x0_resume,
+       .restore_noirq = mcp_sa11x0_resume,
+#endif
+};
 
 static struct platform_driver mcp_sa11x0_driver = {
        .probe          = mcp_sa11x0_probe,
        .remove         = mcp_sa11x0_remove,
-       .suspend        = mcp_sa11x0_suspend,
-       .resume         = mcp_sa11x0_resume,
        .driver         = {
-               .name   = "sa11x0-mcp",
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &mcp_sa11x0_pm_ops,
        },
 };
 
@@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = {
  */
 module_platform_driver(mcp_sa11x0_driver);
 
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
 MODULE_LICENSE("GPL");
index cea9da6..b63c075 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
-
-
 #define UCB1X00_ATTR(name,input)\
 static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
                           char *buf)   \
@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-       device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
-       device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
-       device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
+       struct ucb1x00 *ucb = dev->ucb;
+       struct platform_device *pdev;
+       struct gpio_keys_platform_data keys;
+       static struct gpio_keys_button buttons[6];
+       unsigned i;
+
+       memset(buttons, 0, sizeof(buttons));
+       memset(&keys, 0, sizeof(keys));
+
+       for (i = 0; i < ARRAY_SIZE(buttons); i++) {
+               buttons[i].code = BTN_0 + i;
+               buttons[i].gpio = ucb->gpio.base + i;
+               buttons[i].type = EV_KEY;
+               buttons[i].can_disable = true;
+       }
+
+       keys.buttons = buttons;
+       keys.nbuttons = ARRAY_SIZE(buttons);
+       keys.poll_interval = 50;
+       keys.name = "ucb1x00";
+
+       pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1,
+               &keys, sizeof(keys));
+
+       device_create_file(&ucb->dev, &dev_attr_vbatt);
+       device_create_file(&ucb->dev, &dev_attr_vcharger);
+       device_create_file(&ucb->dev, &dev_attr_batt_temp);
+
+       dev->priv = pdev;
        return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
+       struct platform_device *pdev = dev->priv;
+
+       if (!IS_ERR(pdev))
+               platform_device_unregister(pdev);
+
        device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
        device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
        device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
index febc90c..70f02da 100644 (file)
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mfd/ucb1x00.h>
+#include <linux/pm.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
-
-#include <mach/dma.h>
-#include <mach/hardware.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
@@ -102,7 +100,7 @@ void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
  *     ucb1x00_enable must have been called to enable the comms
  *     before using this function.
  *
- *     This function does not take any semaphores or spinlocks.
+ *     This function does not take any mutexes or spinlocks.
  */
 unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
 {
@@ -120,14 +118,22 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        else
                ucb->io_out &= ~(1 << offset);
 
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 }
 
 static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
-       return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
+       unsigned val;
+
+       ucb1x00_enable(ucb);
+       val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
+       ucb1x00_disable(ucb);
+
+       return val & (1 << offset);
 }
 
 static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -137,7 +143,9 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&ucb->io_lock, flags);
        ucb->io_dir &= ~(1 << offset);
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 
        return 0;
@@ -157,6 +165,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
        else
                ucb->io_out &= ~mask;
 
+       ucb1x00_enable(ucb);
        if (old != ucb->io_out)
                ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 
@@ -164,11 +173,19 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
                ucb->io_dir |= mask;
                ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
        }
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 
        return 0;
 }
 
+static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+
+       return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
+}
+
 /*
  * UCB1300 data sheet says we must:
  *  1. enable ADC      => 5us (including reference startup time)
@@ -186,7 +203,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
  *     Any code wishing to use the ADC converter must call this
  *     function prior to using it.
  *
- *     This function takes the ADC semaphore to prevent two or more
+ *     This function takes the ADC mutex to prevent two or more
  *     concurrent uses, and therefore may sleep.  As a result, it
  *     can only be called from process context, not interrupt
  *     context.
@@ -196,7 +213,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
  */
 void ucb1x00_adc_enable(struct ucb1x00 *ucb)
 {
-       down(&ucb->adc_sem);
+       mutex_lock(&ucb->adc_mutex);
 
        ucb->adc_cr |= UCB_ADC_ENA;
 
@@ -218,7 +235,7 @@ void ucb1x00_adc_enable(struct ucb1x00 *ucb)
  *     complete (2 frames max without sync).
  *
  *     If called for a synchronised ADC conversion, it may sleep
- *     with the ADC semaphore held.
+ *     with the ADC mutex held.
  */
 unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
 {
@@ -246,7 +263,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
  *     ucb1x00_adc_disable - disable the ADC converter
  *     @ucb: UCB1x00 structure describing chip
  *
- *     Disable the ADC converter and release the ADC semaphore.
+ *     Disable the ADC converter and release the ADC mutex.
  */
 void ucb1x00_adc_disable(struct ucb1x00 *ucb)
 {
@@ -254,7 +271,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
        ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
        ucb1x00_disable(ucb);
 
-       up(&ucb->adc_sem);
+       mutex_unlock(&ucb->adc_mutex);
 }
 
 /*
@@ -265,10 +282,9 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
  * SIBCLK to talk to the chip.  We leave the clock running until
  * we have finished processing all interrupts from the chip.
  */
-static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
+static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct ucb1x00 *ucb = devid;
-       struct ucb1x00_irq *irq;
+       struct ucb1x00 *ucb = irq_desc_get_handler_data(desc);
        unsigned int isr, i;
 
        ucb1x00_enable(ucb);
@@ -276,157 +292,104 @@ static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
        ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
        ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
 
-       for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
-               if (isr & 1 && irq->fn)
-                       irq->fn(i, irq->devid);
+       for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++)
+               if (isr & 1)
+                       generic_handle_irq(ucb->irq_base + i);
        ucb1x00_disable(ucb);
-
-       return IRQ_HANDLED;
 }
 
-/**
- *     ucb1x00_hook_irq - hook a UCB1x00 interrupt
- *     @ucb:   UCB1x00 structure describing chip
- *     @idx:   interrupt index
- *     @fn:    function to call when interrupt is triggered
- *     @devid: device id to pass to interrupt handler
- *
- *     Hook the specified interrupt.  You can only register one handler
- *     for each interrupt source.  The interrupt source is not enabled
- *     by this function; use ucb1x00_enable_irq instead.
- *
- *     Interrupt handlers will be called with other interrupts enabled.
- *
- *     Returns zero on success, or one of the following errors:
- *      -EINVAL if the interrupt index is invalid
- *      -EBUSY if the interrupt has already been hooked
- */
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
+static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask)
 {
-       struct ucb1x00_irq *irq;
-       int ret = -EINVAL;
-
-       if (idx < 16) {
-               irq = ucb->irq_handler + idx;
-               ret = -EBUSY;
-
-               spin_lock_irq(&ucb->lock);
-               if (irq->fn == NULL) {
-                       irq->devid = devid;
-                       irq->fn = fn;
-                       ret = 0;
-               }
-               spin_unlock_irq(&ucb->lock);
-       }
-       return ret;
+       ucb1x00_enable(ucb);
+       if (ucb->irq_ris_enbl & mask)
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+       if (ucb->irq_fal_enbl & mask)
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+       ucb1x00_disable(ucb);
 }
 
-/**
- *     ucb1x00_enable_irq - enable an UCB1x00 interrupt source
- *     @ucb: UCB1x00 structure describing chip
- *     @idx: interrupt index
- *     @edges: interrupt edges to enable
- *
- *     Enable the specified interrupt to trigger on %UCB_RISING,
- *     %UCB_FALLING or both edges.  The interrupt should have been
- *     hooked by ucb1x00_hook_irq.
- */
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_noop(struct irq_data *data)
 {
-       unsigned long flags;
+}
 
-       if (idx < 16) {
-               spin_lock_irqsave(&ucb->lock, flags);
+static void ucb1x00_irq_mask(struct irq_data *data)
+{
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-               ucb1x00_enable(ucb);
-               if (edges & UCB_RISING) {
-                       ucb->irq_ris_enbl |= 1 << idx;
-                       ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               }
-               if (edges & UCB_FALLING) {
-                       ucb->irq_fal_enbl |= 1 << idx;
-                       ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               }
-               ucb1x00_disable(ucb);
-               spin_unlock_irqrestore(&ucb->lock, flags);
-       }
+       raw_spin_lock(&ucb->irq_lock);
+       ucb->irq_mask &= ~mask;
+       ucb1x00_irq_update(ucb, mask);
+       raw_spin_unlock(&ucb->irq_lock);
 }
 
-/**
- *     ucb1x00_disable_irq - disable an UCB1x00 interrupt source
- *     @ucb: UCB1x00 structure describing chip
- *     @edges: interrupt edges to disable
- *
- *     Disable the specified interrupt triggering on the specified
- *     (%UCB_RISING, %UCB_FALLING or both) edges.
- */
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_unmask(struct irq_data *data)
 {
-       unsigned long flags;
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-       if (idx < 16) {
-               spin_lock_irqsave(&ucb->lock, flags);
-
-               ucb1x00_enable(ucb);
-               if (edges & UCB_RISING) {
-                       ucb->irq_ris_enbl &= ~(1 << idx);
-                       ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               }
-               if (edges & UCB_FALLING) {
-                       ucb->irq_fal_enbl &= ~(1 << idx);
-                       ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               }
-               ucb1x00_disable(ucb);
-               spin_unlock_irqrestore(&ucb->lock, flags);
-       }
+       raw_spin_lock(&ucb->irq_lock);
+       ucb->irq_mask |= mask;
+       ucb1x00_irq_update(ucb, mask);
+       raw_spin_unlock(&ucb->irq_lock);
 }
 
-/**
- *     ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
- *     @ucb: UCB1x00 structure describing chip
- *     @idx: interrupt index
- *     @devid: device id.
- *
- *     Disable the interrupt source and remove the handler.  devid must
- *     match the devid passed when hooking the interrupt.
- *
- *     Returns zero on success, or one of the following errors:
- *      -EINVAL if the interrupt index is invalid
- *      -ENOENT if devid does not match
- */
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
+static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
 {
-       struct ucb1x00_irq *irq;
-       int ret;
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-       if (idx >= 16)
-               goto bad;
+       raw_spin_lock(&ucb->irq_lock);
+       if (type & IRQ_TYPE_EDGE_RISING)
+               ucb->irq_ris_enbl |= mask;
+       else
+               ucb->irq_ris_enbl &= ~mask;
 
-       irq = ucb->irq_handler + idx;
-       ret = -ENOENT;
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               ucb->irq_fal_enbl |= mask;
+       else
+               ucb->irq_fal_enbl &= ~mask;
+       if (ucb->irq_mask & mask) {
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+       }
+       raw_spin_unlock(&ucb->irq_lock);
 
-       spin_lock_irq(&ucb->lock);
-       if (irq->devid == devid) {
-               ucb->irq_ris_enbl &= ~(1 << idx);
-               ucb->irq_fal_enbl &= ~(1 << idx);
+       return 0;
+}
 
-               ucb1x00_enable(ucb);
-               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               ucb1x00_disable(ucb);
+static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-               irq->fn = NULL;
-               irq->devid = NULL;
-               ret = 0;
-       }
-       spin_unlock_irq(&ucb->lock);
-       return ret;
+       if (!pdata || !pdata->can_wakeup)
+               return -EINVAL;
 
-bad:
-       printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-       return -EINVAL;
+       raw_spin_lock(&ucb->irq_lock);
+       if (on)
+               ucb->irq_wake |= mask;
+       else
+               ucb->irq_wake &= ~mask;
+       raw_spin_unlock(&ucb->irq_lock);
+
+       return 0;
 }
 
+static struct irq_chip ucb1x00_irqchip = {
+       .name = "ucb1x00",
+       .irq_ack = ucb1x00_irq_noop,
+       .irq_mask = ucb1x00_irq_mask,
+       .irq_unmask = ucb1x00_irq_unmask,
+       .irq_set_type = ucb1x00_irq_set_type,
+       .irq_set_wake = ucb1x00_irq_set_wake,
+};
+
 static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
 {
        struct ucb1x00_dev *dev;
@@ -440,8 +403,8 @@ static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
                ret = drv->add(dev);
 
                if (ret == 0) {
-                       list_add(&dev->dev_node, &ucb->devs);
-                       list_add(&dev->drv_node, &drv->devs);
+                       list_add_tail(&dev->dev_node, &ucb->devs);
+                       list_add_tail(&dev->drv_node, &drv->devs);
                } else {
                        kfree(dev);
                }
@@ -533,98 +496,126 @@ static struct class ucb1x00_class = {
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
-       struct ucb1x00 *ucb;
+       struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
        struct ucb1x00_driver *drv;
-       unsigned int id;
+       struct ucb1x00 *ucb;
+       unsigned id, i, irq_base;
        int ret = -ENODEV;
-       int temp;
+
+       /* Tell the platform to deassert the UCB1x00 reset */
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_PROBE);
 
        mcp_enable(mcp);
        id = mcp_reg_read(mcp, UCB_ID);
+       mcp_disable(mcp);
 
        if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
                printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
-               goto err_disable;
+               goto out;
        }
 
        ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
        ret = -ENOMEM;
        if (!ucb)
-               goto err_disable;
-
+               goto out;
 
+       device_initialize(&ucb->dev);
        ucb->dev.class = &ucb1x00_class;
        ucb->dev.parent = &mcp->attached_device;
        dev_set_name(&ucb->dev, "ucb1x00");
 
-       spin_lock_init(&ucb->lock);
+       raw_spin_lock_init(&ucb->irq_lock);
        spin_lock_init(&ucb->io_lock);
-       sema_init(&ucb->adc_sem, 1);
+       mutex_init(&ucb->adc_mutex);
 
        ucb->id  = id;
        ucb->mcp = mcp;
+
+       ret = device_add(&ucb->dev);
+       if (ret)
+               goto err_dev_add;
+
+       ucb1x00_enable(ucb);
        ucb->irq = ucb1x00_detect_irq(ucb);
+       ucb1x00_disable(ucb);
        if (ucb->irq == NO_IRQ) {
-               printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+               dev_err(&ucb->dev, "IRQ probe failed\n");
                ret = -ENODEV;
-               goto err_free;
+               goto err_no_irq;
        }
 
        ucb->gpio.base = -1;
-       if (mcp->gpio_base != 0) {
+       irq_base = pdata ? pdata->irq_base : 0;
+       ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
+       if (ucb->irq_base < 0) {
+               dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
+                       ucb->irq_base);
+               goto err_irq_alloc;
+       }
+
+       for (i = 0; i < 16; i++) {
+               unsigned irq = ucb->irq_base + i;
+
+               irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
+               irq_set_chip_data(irq, ucb);
+               set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST);
+       }
+
+       irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
+       irq_set_handler_data(ucb->irq, ucb);
+       irq_set_chained_handler(ucb->irq, ucb1x00_irq);
+
+       if (pdata && pdata->gpio_base) {
                ucb->gpio.label = dev_name(&ucb->dev);
-               ucb->gpio.base = mcp->gpio_base;
+               ucb->gpio.dev = &ucb->dev;
+               ucb->gpio.owner = THIS_MODULE;
+               ucb->gpio.base = pdata->gpio_base;
                ucb->gpio.ngpio = 10;
                ucb->gpio.set = ucb1x00_gpio_set;
                ucb->gpio.get = ucb1x00_gpio_get;
                ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
                ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
+               ucb->gpio.to_irq = ucb1x00_to_irq;
                ret = gpiochip_add(&ucb->gpio);
                if (ret)
-                       goto err_free;
+                       goto err_gpio_add;
        } else
                dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
-       ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-                         "UCB1x00", ucb);
-       if (ret) {
-               printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-                       ucb->irq, ret);
-               goto err_gpio;
-       }
-
        mcp_set_drvdata(mcp, ucb);
 
-       ret = device_register(&ucb->dev);
-       if (ret)
-               goto err_irq;
-
+       if (pdata)
+               device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
 
        INIT_LIST_HEAD(&ucb->devs);
        mutex_lock(&ucb1x00_mutex);
-       list_add(&ucb->node, &ucb1x00_devices);
+       list_add_tail(&ucb->node, &ucb1x00_devices);
        list_for_each_entry(drv, &ucb1x00_drivers, node) {
                ucb1x00_add_dev(ucb, drv);
        }
        mutex_unlock(&ucb1x00_mutex);
 
-       goto out;
+       return ret;
 
- err_irq:
-       free_irq(ucb->irq, ucb);
- err_gpio:
-       if (ucb->gpio.base != -1)
-               temp = gpiochip_remove(&ucb->gpio);
- err_free:
-       kfree(ucb);
- err_disable:
-       mcp_disable(mcp);
+ err_gpio_add:
+       irq_set_chained_handler(ucb->irq, NULL);
+ err_irq_alloc:
+       if (ucb->irq_base > 0)
+               irq_free_descs(ucb->irq_base, 16);
+ err_no_irq:
+       device_del(&ucb->dev);
+ err_dev_add:
+       put_device(&ucb->dev);
  out:
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_PROBE_FAIL);
        return ret;
 }
 
 static void ucb1x00_remove(struct mcp *mcp)
 {
+       struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
        struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
        struct list_head *l, *n;
        int ret;
@@ -643,8 +634,12 @@ static void ucb1x00_remove(struct mcp *mcp)
                        dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
        }
 
-       free_irq(ucb->irq, ucb);
+       irq_set_chained_handler(ucb->irq, NULL);
+       irq_free_descs(ucb->irq_base, 16);
        device_unregister(&ucb->dev);
+
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_REMOVE);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
@@ -653,7 +648,7 @@ int ucb1x00_register_driver(struct ucb1x00_driver *drv)
 
        INIT_LIST_HEAD(&drv->devs);
        mutex_lock(&ucb1x00_mutex);
-       list_add(&drv->node, &ucb1x00_drivers);
+       list_add_tail(&drv->node, &ucb1x00_drivers);
        list_for_each_entry(ucb, &ucb1x00_devices, node) {
                ucb1x00_add_dev(ucb, drv);
        }
@@ -674,44 +669,86 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
        mutex_unlock(&ucb1x00_mutex);
 }
 
-static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state)
+static int ucb1x00_suspend(struct device *dev)
 {
-       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-       struct ucb1x00_dev *dev;
+       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00 *ucb = dev_get_drvdata(dev);
+       struct ucb1x00_dev *udev;
 
        mutex_lock(&ucb1x00_mutex);
-       list_for_each_entry(dev, &ucb->devs, dev_node) {
-               if (dev->drv->suspend)
-                       dev->drv->suspend(dev, state);
+       list_for_each_entry(udev, &ucb->devs, dev_node) {
+               if (udev->drv->suspend)
+                       udev->drv->suspend(udev);
        }
        mutex_unlock(&ucb1x00_mutex);
+
+       if (ucb->irq_wake) {
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+               ucb1x00_enable(ucb);
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_wake);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_wake);
+               ucb1x00_disable(ucb);
+               raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+               enable_irq_wake(ucb->irq);
+       } else if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_SUSPEND);
+
        return 0;
 }
 
-static int ucb1x00_resume(struct mcp *mcp)
+static int ucb1x00_resume(struct device *dev)
 {
-       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-       struct ucb1x00_dev *dev;
+       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00 *ucb = dev_get_drvdata(dev);
+       struct ucb1x00_dev *udev;
+
+       if (!ucb->irq_wake && pdata && pdata->reset)
+               pdata->reset(UCB_RST_RESUME);
 
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
        ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+
+       if (ucb->irq_wake) {
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+               raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+               disable_irq_wake(ucb->irq);
+       }
+       ucb1x00_disable(ucb);
+
        mutex_lock(&ucb1x00_mutex);
-       list_for_each_entry(dev, &ucb->devs, dev_node) {
-               if (dev->drv->resume)
-                       dev->drv->resume(dev);
+       list_for_each_entry(udev, &ucb->devs, dev_node) {
+               if (udev->drv->resume)
+                       udev->drv->resume(udev);
        }
        mutex_unlock(&ucb1x00_mutex);
        return 0;
 }
 
+static const struct dev_pm_ops ucb1x00_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
+};
+
 static struct mcp_driver ucb1x00_driver = {
        .drv            = {
                .name   = "ucb1x00",
+               .owner  = THIS_MODULE,
+               .pm     = &ucb1x00_pm_ops,
        },
        .probe          = ucb1x00_probe,
        .remove         = ucb1x00_remove,
-       .suspend        = ucb1x00_suspend,
-       .resume         = ucb1x00_resume,
 };
 
 static int __init ucb1x00_init(void)
@@ -742,14 +779,10 @@ EXPORT_SYMBOL(ucb1x00_adc_enable);
 EXPORT_SYMBOL(ucb1x00_adc_read);
 EXPORT_SYMBOL(ucb1x00_adc_disable);
 
-EXPORT_SYMBOL(ucb1x00_hook_irq);
-EXPORT_SYMBOL(ucb1x00_free_irq);
-EXPORT_SYMBOL(ucb1x00_enable_irq);
-EXPORT_SYMBOL(ucb1x00_disable_irq);
-
 EXPORT_SYMBOL(ucb1x00_register_driver);
 EXPORT_SYMBOL(ucb1x00_unregister_driver);
 
+MODULE_ALIAS("mcp:ucb1x00");
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("UCB1x00 core driver");
 MODULE_LICENSE("GPL");
index 63a3cbd..1e0e20c 100644 (file)
@@ -20,8 +20,9 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/smp.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -32,7 +33,6 @@
 #include <linux/kthread.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
@@ -42,6 +42,8 @@ struct ucb1x00_ts {
        struct input_dev        *idev;
        struct ucb1x00          *ucb;
 
+       spinlock_t              irq_lock;
+       unsigned                irq_disabled;
        wait_queue_head_t       irq_wait;
        struct task_struct      *rtask;
        u16                     x_res;
@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
                if (ucb1x00_ts_pen_down(ts)) {
                        set_current_state(TASK_INTERRUPTIBLE);
 
-                       ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
+                       spin_lock_irq(&ts->irq_lock);
+                       if (ts->irq_disabled) {
+                               ts->irq_disabled = 0;
+                               enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
+                       }
+                       spin_unlock_irq(&ts->irq_lock);
                        ucb1x00_disable(ts->ucb);
 
                        /*
@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
  * We only detect touch screen _touches_ with this interrupt
  * handler, and even then we just schedule our task.
  */
-static void ucb1x00_ts_irq(int idx, void *id)
+static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
 {
        struct ucb1x00_ts *ts = id;
 
-       ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+       spin_lock(&ts->irq_lock);
+       ts->irq_disabled = 1;
+       disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
+       spin_unlock(&ts->irq_lock);
        wake_up(&ts->irq_wait);
+
+       return IRQ_HANDLED;
 }
 
 static int ucb1x00_ts_open(struct input_dev *idev)
 {
        struct ucb1x00_ts *ts = input_get_drvdata(idev);
+       unsigned long flags = 0;
        int ret = 0;
 
        BUG_ON(ts->rtask);
 
+       if (machine_is_collie())
+               flags = IRQF_TRIGGER_RISING;
+       else
+               flags = IRQF_TRIGGER_FALLING;
+
+       ts->irq_disabled = 0;
+
        init_waitqueue_head(&ts->irq_wait);
-       ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+       ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
+                         flags, "ucb1x00-ts", ts);
        if (ret < 0)
                goto out;
 
@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
        if (!IS_ERR(ts->rtask)) {
                ret = 0;
        } else {
-               ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+               free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
                ts->rtask = NULL;
                ret = -EFAULT;
        }
@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
                kthread_stop(ts->rtask);
 
        ucb1x00_enable(ts->ucb);
-       ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+       free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
        ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
        ucb1x00_disable(ts->ucb);
 }
@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        ts->ucb = dev->ucb;
        ts->idev = idev;
        ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
+       spin_lock_init(&ts->irq_lock);
 
        idev->name       = "Touchscreen panel";
        idev->id.product = ts->ucb->id;
        idev->open       = ucb1x00_ts_open;
        idev->close      = ucb1x00_ts_close;
+       idev->dev.parent = &ts->ucb->dev;
 
        idev->evbit[0]   = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
        idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
index 5028219..cbc3b78 100644 (file)
 #include <asm/sizes.h>
 #include <asm/mach/flash.h>
 
-#if 0
-/*
- * This is here for documentation purposes only - until these people
- * submit their machine types.  It will be gone January 2005.
- */
-static struct mtd_partition consus_partitions[] = {
-       {
-               .name           = "Consus boot firmware",
-               .offset         = 0,
-               .size           = 0x00040000,
-               .mask_flags     = MTD_WRITABLE, /* force read-only */
-       }, {
-               .name           = "Consus kernel",
-               .offset         = 0x00040000,
-               .size           = 0x00100000,
-               .mask_flags     = 0,
-       }, {
-               .name           = "Consus disk",
-               .offset         = 0x00140000,
-               /* The rest (up to 16M) for jffs.  We could put 0 and
-                  make it find the size automatically, but right now
-                  i have 32 megs.  jffs will use all 32 megs if given
-                  the chance, and this leads to horrible problems
-                  when you try to re-flash the image because blob
-                  won't erase the whole partition. */
-               .size           = 0x01000000 - 0x00140000,
-               .mask_flags     = 0,
-       }, {
-               /* this disk is a secondary disk, which can be used as
-                  needed, for simplicity, make it the size of the other
-                  consus partition, although realistically it could be
-                  the remainder of the disk (depending on the file
-                  system used) */
-                .name          = "Consus disk2",
-                .offset        = 0x01000000,
-                .size          = 0x01000000 - 0x00140000,
-                .mask_flags    = 0,
-       }
-};
-
-/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
-static struct mtd_partition frodo_partitions[] =
-{
-       {
-               .name           = "bootloader",
-               .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "ramdisk",
-               .size           = 0x00400000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "file system",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND
-       }
-};
-
-static struct mtd_partition jornada56x_partitions[] = {
-       {
-               .name           = "bootldr",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "rootfs",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-static void jornada56x_set_vpp(int vpp)
-{
-       if (vpp)
-               GPSR = GPIO_GPIO26;
-       else
-               GPCR = GPIO_GPIO26;
-       GPDR |= GPIO_GPIO26;
-}
-
-/*
- * Machine        Phys          Size    set_vpp
- * Consus    : SA1100_CS0_PHYS SZ_32M
- * Frodo     : SA1100_CS0_PHYS SZ_32M
- * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
- */
-#endif
-
 struct sa_subdev_info {
        char name[16];
        struct map_info map;
@@ -373,21 +273,9 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static void sa1100_mtd_shutdown(struct platform_device *dev)
-{
-       struct sa_info *info = platform_get_drvdata(dev);
-       if (info && mtd_suspend(info->mtd) == 0)
-               mtd_resume(info->mtd);
-}
-#else
-#define sa1100_mtd_shutdown NULL
-#endif
-
 static struct platform_driver sa1100_mtd_driver = {
        .probe          = sa1100_mtd_probe,
        .remove         = __exit_p(sa1100_mtd_remove),
-       .shutdown       = sa1100_mtd_shutdown,
        .driver         = {
                .name   = "sa1100-mtd",
                .owner  = THIS_MODULE,
index 64ad3ed..0dba050 100644 (file)
@@ -2281,7 +2281,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_release_io;
 #if defined(CONFIG_SA1100_ASSABET)
-       NCR_0 |= NCR_ENET_OSC_EN;
+       neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
        platform_set_drvdata(pdev, ndev);
        ret = smc_enable_device(pdev);
index e535137..4680478 100644 (file)
@@ -356,7 +356,7 @@ config VLSI_FIR
 
 config SA1100_FIR
        tristate "SA1100 Internal IR"
-       depends on ARCH_SA1100 && IRDA
+       depends on ARCH_SA1100 && IRDA && DMA_SA11X0
 
 config VIA_FIR
        tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
index da27050..a0d1913 100644 (file)
@@ -15,7 +15,7 @@
  *  This driver takes one kernel command line parameter, sa1100ir=, with
  *  the following options:
  *     max_rate:baudrate       - set the maximum baud rate
- *     power_leve:level        - set the transmitter power level
+ *     power_level:level       - set the transmitter power level
  *     tx_lpm:0|1              - set transmit low power mode
  */
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sa11x0-dma.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/irda_device.h>
 
-#include <asm/irq.h>
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach/irda.h>
 
@@ -44,8 +44,15 @@ static int power_level = 3;
 static int tx_lpm;
 static int max_rate = 4000000;
 
+struct sa1100_buf {
+       struct device           *dev;
+       struct sk_buff          *skb;
+       struct scatterlist      sg;
+       struct dma_chan         *chan;
+       dma_cookie_t            cookie;
+};
+
 struct sa1100_irda {
-       unsigned char           hscr0;
        unsigned char           utcr4;
        unsigned char           power;
        unsigned char           open;
@@ -53,12 +60,8 @@ struct sa1100_irda {
        int                     speed;
        int                     newspeed;
 
-       struct sk_buff          *txskb;
-       struct sk_buff          *rxskb;
-       dma_addr_t              txbuf_dma;
-       dma_addr_t              rxbuf_dma;
-       dma_regs_t              *txdma;
-       dma_regs_t              *rxdma;
+       struct sa1100_buf       dma_rx;
+       struct sa1100_buf       dma_tx;
 
        struct device           *dev;
        struct irda_platform_data *pdata;
@@ -67,23 +70,103 @@ struct sa1100_irda {
 
        iobuff_t                tx_buff;
        iobuff_t                rx_buff;
+
+       int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
+       irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *);
 };
 
+static int sa1100_irda_set_speed(struct sa1100_irda *, int);
+
 #define IS_FIR(si)             ((si)->speed >= 4000000)
 
 #define HPSIR_MAX_RXLEN                2047
 
+static struct dma_slave_config sa1100_irda_sir_tx = {
+       .direction      = DMA_TO_DEVICE,
+       .dst_addr       = __PREG(Ser2UTDR),
+       .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .dst_maxburst   = 4,
+};
+
+static struct dma_slave_config sa1100_irda_fir_rx = {
+       .direction      = DMA_FROM_DEVICE,
+       .src_addr       = __PREG(Ser2HSDR),
+       .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .src_maxburst   = 8,
+};
+
+static struct dma_slave_config sa1100_irda_fir_tx = {
+       .direction      = DMA_TO_DEVICE,
+       .dst_addr       = __PREG(Ser2HSDR),
+       .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .dst_maxburst   = 8,
+};
+
+static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf)
+{
+       struct dma_chan *chan = buf->chan;
+       struct dma_tx_state state;
+       enum dma_status status;
+
+       status = chan->device->device_tx_status(chan, buf->cookie, &state);
+       if (status != DMA_PAUSED)
+               return 0;
+
+       return sg_dma_len(&buf->sg) - state.residue;
+}
+
+static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf,
+       const char *name, struct dma_slave_config *cfg)
+{
+       dma_cap_mask_t m;
+       int ret;
+
+       dma_cap_zero(m);
+       dma_cap_set(DMA_SLAVE, m);
+
+       buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name);
+       if (!buf->chan) {
+               dev_err(dev, "unable to request DMA channel for %s\n",
+                       name);
+               return -ENOENT;
+       }
+
+       ret = dmaengine_slave_config(buf->chan, cfg);
+       if (ret)
+               dev_warn(dev, "DMA slave_config for %s returned %d\n",
+                       name, ret);
+
+       buf->dev = buf->chan->device->dev;
+
+       return 0;
+}
+
+static void sa1100_irda_dma_start(struct sa1100_buf *buf,
+       enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = buf->chan;
+
+       desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (desc) {
+               desc->callback = cb;
+               desc->callback_param = cb_p;
+               buf->cookie = dmaengine_submit(desc);
+               dma_async_issue_pending(chan);
+       }
+}
+
 /*
  * Allocate and map the receive buffer, unless it is already allocated.
  */
 static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 {
-       if (si->rxskb)
+       if (si->dma_rx.skb)
                return 0;
 
-       si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
-
-       if (!si->rxskb) {
+       si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
+       if (!si->dma_rx.skb) {
                printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
                return -ENOMEM;
        }
@@ -92,11 +175,14 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
         * Align any IP headers that may be contained
         * within the frame.
         */
-       skb_reserve(si->rxskb, 1);
+       skb_reserve(si->dma_rx.skb, 1);
+
+       sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
+       if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
+               dev_kfree_skb_any(si->dma_rx.skb);
+               return -ENOMEM;
+       }
 
-       si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-                                       HPSIR_MAX_RXLEN,
-                                       DMA_FROM_DEVICE);
        return 0;
 }
 
@@ -106,7 +192,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
  */
 static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 {
-       if (!si->rxskb) {
+       if (!si->dma_rx.skb) {
                printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
                return;
        }
@@ -114,254 +200,87 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
        /*
         * First empty receive FIFO
         */
-       Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+       Ser2HSCR0 = HSCR0_HSSP;
 
        /*
         * Enable the DMA, receiver and receive interrupt.
         */
-       sa1100_clear_dma(si->rxdma);
-       sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
-       Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
+       dmaengine_terminate_all(si->dma_rx.chan);
+       sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL);
+
+       Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
 }
 
-/*
- * Set the IrDA communications speed.
- */
-static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
+static void sa1100_irda_check_speed(struct sa1100_irda *si)
 {
-       unsigned long flags;
-       int brd, ret = -EINVAL;
-
-       switch (speed) {
-       case 9600:      case 19200:     case 38400:
-       case 57600:     case 115200:
-               brd = 3686400 / (16 * speed) - 1;
-
-               /*
-                * Stop the receive DMA.
-                */
-               if (IS_FIR(si))
-                       sa1100_stop_dma(si->rxdma);
-
-               local_irq_save(flags);
-
-               Ser2UTCR3 = 0;
-               Ser2HSCR0 = HSCR0_UART;
-
-               Ser2UTCR1 = brd >> 8;
-               Ser2UTCR2 = brd;
-
-               /*
-                * Clear status register
-                */
-               Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-               Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
-
-               if (si->pdata->set_speed)
-                       si->pdata->set_speed(si->dev, speed);
-
-               si->speed = speed;
-
-               local_irq_restore(flags);
-               ret = 0;
-               break;
-
-       case 4000000:
-               local_irq_save(flags);
-
-               si->hscr0 = 0;
-
-               Ser2HSSR0 = 0xff;
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
-               Ser2UTCR3 = 0;
-
-               si->speed = speed;
-
-               if (si->pdata->set_speed)
-                       si->pdata->set_speed(si->dev, speed);
-
-               sa1100_irda_rx_alloc(si);
-               sa1100_irda_rx_dma_start(si);
-
-               local_irq_restore(flags);
-
-               break;
-
-       default:
-               break;
+       if (si->newspeed) {
+               sa1100_irda_set_speed(si, si->newspeed);
+               si->newspeed = 0;
        }
-
-       return ret;
 }
 
 /*
- * Control the power state of the IrDA transmitter.
- * State:
- *  0 - off
- *  1 - short range, lowest power
- *  2 - medium range, medium power
- *  3 - maximum range, high power
- *
- * Currently, only assabet is known to support this.
+ * HP-SIR format support.
  */
-static int
-__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
-{
-       int ret = 0;
-       if (si->pdata->set_power)
-               ret = si->pdata->set_power(si->dev, state);
-       return ret;
-}
-
-static inline int
-sa1100_set_power(struct sa1100_irda *si, unsigned int state)
+static void sa1100_irda_sirtxdma_irq(void *id)
 {
-       int ret;
-
-       ret = __sa1100_irda_set_power(si, state);
-       if (ret == 0)
-               si->power = state;
-
-       return ret;
-}
+       struct net_device *dev = id;
+       struct sa1100_irda *si = netdev_priv(dev);
 
-static int sa1100_irda_startup(struct sa1100_irda *si)
-{
-       int ret;
+       dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE);
+       dev_kfree_skb(si->dma_tx.skb);
+       si->dma_tx.skb = NULL;
 
-       /*
-        * Ensure that the ports for this device are setup correctly.
-        */
-       if (si->pdata->startup) {
-               ret = si->pdata->startup(si->dev);
-               if (ret)
-                       return ret;
-       }
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
 
-       /*
-        * Configure PPC for IRDA - we want to drive TXD2 low.
-        * We also want to drive this pin low during sleep.
-        */
-       PPSR &= ~PPC_TXD2;
-       PSDR &= ~PPC_TXD2;
-       PPDR |= PPC_TXD2;
-
-       /*
-        * Enable HP-SIR modulation, and ensure that the port is disabled.
-        */
-       Ser2UTCR3 = 0;
-       Ser2HSCR0 = HSCR0_UART;
-       Ser2UTCR4 = si->utcr4;
-       Ser2UTCR0 = UTCR0_8BitData;
-       Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
+       /* We need to ensure that the transmitter has finished. */
+       do
+               rmb();
+       while (Ser2UTSR1 & UTSR1_TBY);
 
        /*
-        * Clear status register
+        * Ok, we've finished transmitting.  Now enable the receiver.
+        * Sometimes we get a receive IRQ immediately after a transmit...
         */
        Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+       Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
 
-       ret = sa1100_irda_set_speed(si, si->speed = 9600);
-       if (ret) {
-               Ser2UTCR3 = 0;
-               Ser2HSCR0 = 0;
+       sa1100_irda_check_speed(si);
 
-               if (si->pdata->shutdown)
-                       si->pdata->shutdown(si->dev);
-       }
-
-       return ret;
-}
-
-static void sa1100_irda_shutdown(struct sa1100_irda *si)
-{
-       /*
-        * Stop all DMA activity.
-        */
-       sa1100_stop_dma(si->rxdma);
-       sa1100_stop_dma(si->txdma);
-
-       /* Disable the port. */
-       Ser2UTCR3 = 0;
-       Ser2HSCR0 = 0;
-
-       if (si->pdata->shutdown)
-               si->pdata->shutdown(si->dev);
+       /* I'm hungry! */
+       netif_wake_queue(dev);
 }
 
-#ifdef CONFIG_PM
-/*
- * Suspend the IrDA interface.
- */
-static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
+static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
+       struct sa1100_irda *si)
 {
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct sa1100_irda *si;
-
-       if (!dev)
-               return 0;
-
-       si = netdev_priv(dev);
-       if (si->open) {
-               /*
-                * Stop the transmit queue
-                */
-               netif_device_detach(dev);
-               disable_irq(dev->irq);
-               sa1100_irda_shutdown(si);
-               __sa1100_irda_set_power(si, 0);
+       si->tx_buff.data = si->tx_buff.head;
+       si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
+                                         si->tx_buff.truesize);
+
+       si->dma_tx.skb = skb;
+       sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len);
+       if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+               si->dma_tx.skb = NULL;
+               netif_wake_queue(dev);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
        }
 
-       return 0;
-}
-
-/*
- * Resume the IrDA interface.
- */
-static int sa1100_irda_resume(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct sa1100_irda *si;
-
-       if (!dev)
-               return 0;
-
-       si = netdev_priv(dev);
-       if (si->open) {
-               /*
-                * If we missed a speed change, initialise at the new speed
-                * directly.  It is debatable whether this is actually
-                * required, but in the interests of continuing from where
-                * we left off it is desirable.  The converse argument is
-                * that we should re-negotiate at 9600 baud again.
-                */
-               if (si->newspeed) {
-                       si->speed = si->newspeed;
-                       si->newspeed = 0;
-               }
-
-               sa1100_irda_startup(si);
-               __sa1100_irda_set_power(si, si->power);
-               enable_irq(dev->irq);
+       sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev);
 
-               /*
-                * This automatically wakes up the queue
-                */
-               netif_device_attach(dev);
-       }
+       /*
+        * The mean turn-around time is enforced by XBOF padding,
+        * so we don't have to do anything special here.
+        */
+       Ser2UTCR3 = UTCR3_TXE;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
-#else
-#define sa1100_irda_suspend    NULL
-#define sa1100_irda_resume     NULL
-#endif
 
-/*
- * HP-SIR format interrupt service routines.
- */
-static void sa1100_irda_hpsir_irq(struct net_device *dev)
+static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
 {
-       struct sa1100_irda *si = netdev_priv(dev);
        int status;
 
        status = Ser2UTSR0;
@@ -414,51 +333,96 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
 
        }
 
-       if (status & UTSR0_TFS && si->tx_buff.len) {
-               /*
-                * Transmitter FIFO is not full
-                */
-               do {
-                       Ser2UTDR = *si->tx_buff.data++;
-                       si->tx_buff.len -= 1;
-               } while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len);
+       return IRQ_HANDLED;
+}
 
-               if (si->tx_buff.len == 0) {
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += si->tx_buff.data -
-                                             si->tx_buff.head;
+/*
+ * FIR format support.
+ */
+static void sa1100_irda_firtxdma_irq(void *id)
+{
+       struct net_device *dev = id;
+       struct sa1100_irda *si = netdev_priv(dev);
+       struct sk_buff *skb;
 
-                       /*
-                        * We need to ensure that the transmitter has
-                        * finished.
-                        */
-                       do
-                               rmb();
-                       while (Ser2UTSR1 & UTSR1_TBY);
+       /*
+        * Wait for the transmission to complete.  Unfortunately,
+        * the hardware doesn't give us an interrupt to indicate
+        * "end of frame".
+        */
+       do
+               rmb();
+       while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
 
-                       /*
-                        * Ok, we've finished transmitting.  Now enable
-                        * the receiver.  Sometimes we get a receive IRQ
-                        * immediately after a transmit...
-                        */
-                       Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-                       Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
+       /*
+        * Clear the transmit underrun bit.
+        */
+       Ser2HSSR0 = HSSR0_TUR;
 
-                       if (si->newspeed) {
-                               sa1100_irda_set_speed(si, si->newspeed);
-                               si->newspeed = 0;
-                       }
+       /*
+        * Do we need to change speed?  Note that we're lazy
+        * here - we don't free the old dma_rx.skb.  We don't need
+        * to allocate a buffer either.
+        */
+       sa1100_irda_check_speed(si);
 
-                       /* I'm hungry! */
-                       netif_wake_queue(dev);
-               }
+       /*
+        * Start reception.  This disables the transmitter for
+        * us.  This will be using the existing RX buffer.
+        */
+       sa1100_irda_rx_dma_start(si);
+
+       /* Account and free the packet. */
+       skb = si->dma_tx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+                            DMA_TO_DEVICE);
+               dev->stats.tx_packets ++;
+               dev->stats.tx_bytes += skb->len;
+               dev_kfree_skb_irq(skb);
+               si->dma_tx.skb = NULL;
        }
+
+       /*
+        * Make sure that the TX queue is available for sending
+        * (for retries).  TX has priority over RX at all times.
+        */
+       netif_wake_queue(dev);
+}
+
+static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
+       struct sa1100_irda *si)
+{
+       int mtt = irda_get_mtt(skb);
+
+       si->dma_tx.skb = skb;
+       sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
+       if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+               si->dma_tx.skb = NULL;
+               netif_wake_queue(dev);
+               dev->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev);
+
+       /*
+        * If we have a mean turn-around time, impose the specified
+        * specified delay.  We could shorten this by timing from
+        * the point we received the packet.
+        */
+       if (mtt)
+               udelay(mtt);
+
+       Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
+
+       return NETDEV_TX_OK;
 }
 
 static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
 {
-       struct sk_buff *skb = si->rxskb;
-       dma_addr_t dma_addr;
+       struct sk_buff *skb = si->dma_rx.skb;
        unsigned int len, stat, data;
 
        if (!skb) {
@@ -469,11 +433,10 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
        /*
         * Get the current data position.
         */
-       dma_addr = sa1100_get_dma_pos(si->rxdma);
-       len = dma_addr - si->rxbuf_dma;
+       len = sa1100_irda_dma_xferred(&si->dma_rx);
        if (len > HPSIR_MAX_RXLEN)
                len = HPSIR_MAX_RXLEN;
-       dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
+       dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 
        do {
                /*
@@ -501,7 +464,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
        } while (Ser2HSSR0 & HSSR0_EIF);
 
        if (stat & HSSR1_EOF) {
-               si->rxskb = NULL;
+               si->dma_rx.skb = NULL;
 
                skb_put(skb, len);
                skb->dev = dev;
@@ -518,28 +481,23 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
                netif_rx(skb);
        } else {
                /*
-                * Remap the buffer.
+                * Remap the buffer - it was previously mapped, and we
+                * hope that this succeeds.
                 */
-               si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-                                               HPSIR_MAX_RXLEN,
-                                               DMA_FROM_DEVICE);
+               dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
        }
 }
 
 /*
- * FIR format interrupt service routine.  We only have to
- * handle RX events; transmit events go via the TX DMA handler.
- *
- * No matter what, we disable RX, process, and the restart RX.
+ * We only have to handle RX events here; transmit events go via the TX
+ * DMA handler. We disable RX, process, and the restart RX.
  */
-static void sa1100_irda_fir_irq(struct net_device *dev)
+static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
 {
-       struct sa1100_irda *si = netdev_priv(dev);
-
        /*
         * Stop RX DMA
         */
-       sa1100_stop_dma(si->rxdma);
+       dmaengine_pause(si->dma_rx.chan);
 
        /*
         * Framing error - we throw away the packet completely.
@@ -555,7 +513,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
                /*
                 * Clear out the DMA...
                 */
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+               Ser2HSCR0 = HSCR0_HSSP;
 
                /*
                 * Clear selected status bits now, so we
@@ -577,74 +535,124 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
         * No matter what happens, we must restart reception.
         */
        sa1100_irda_rx_dma_start(si);
+
+       return IRQ_HANDLED;
 }
 
-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+/*
+ * Set the IrDA communications speed.
+ */
+static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 {
-       struct net_device *dev = dev_id;
-       if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev))))
-               sa1100_irda_fir_irq(dev);
-       else
-               sa1100_irda_hpsir_irq(dev);
-       return IRQ_HANDLED;
+       unsigned long flags;
+       int brd, ret = -EINVAL;
+
+       switch (speed) {
+       case 9600:      case 19200:     case 38400:
+       case 57600:     case 115200:
+               brd = 3686400 / (16 * speed) - 1;
+
+               /* Stop the receive DMA, and configure transmit. */
+               if (IS_FIR(si)) {
+                       dmaengine_terminate_all(si->dma_rx.chan);
+                       dmaengine_slave_config(si->dma_tx.chan,
+                                               &sa1100_irda_sir_tx);
+               }
+
+               local_irq_save(flags);
+
+               Ser2UTCR3 = 0;
+               Ser2HSCR0 = HSCR0_UART;
+
+               Ser2UTCR1 = brd >> 8;
+               Ser2UTCR2 = brd;
+
+               /*
+                * Clear status register
+                */
+               Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+               Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
+
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
+
+               si->speed = speed;
+               si->tx_start = sa1100_irda_sir_tx_start;
+               si->irq = sa1100_irda_sir_irq;
+
+               local_irq_restore(flags);
+               ret = 0;
+               break;
+
+       case 4000000:
+               if (!IS_FIR(si))
+                       dmaengine_slave_config(si->dma_tx.chan,
+                                               &sa1100_irda_fir_tx);
+
+               local_irq_save(flags);
+
+               Ser2HSSR0 = 0xff;
+               Ser2HSCR0 = HSCR0_HSSP;
+               Ser2UTCR3 = 0;
+
+               si->speed = speed;
+               si->tx_start = sa1100_irda_fir_tx_start;
+               si->irq = sa1100_irda_fir_irq;
+
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
+
+               sa1100_irda_rx_alloc(si);
+               sa1100_irda_rx_dma_start(si);
+
+               local_irq_restore(flags);
+
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
 }
 
 /*
- * TX DMA completion handler.
+ * Control the power state of the IrDA transmitter.
+ * State:
+ *  0 - off
+ *  1 - short range, lowest power
+ *  2 - medium range, medium power
+ *  3 - maximum range, high power
+ *
+ * Currently, only assabet is known to support this.
  */
-static void sa1100_irda_txdma_irq(void *id)
+static int
+__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
 {
-       struct net_device *dev = id;
-       struct sa1100_irda *si = netdev_priv(dev);
-       struct sk_buff *skb = si->txskb;
-
-       si->txskb = NULL;
-
-       /*
-        * Wait for the transmission to complete.  Unfortunately,
-        * the hardware doesn't give us an interrupt to indicate
-        * "end of frame".
-        */
-       do
-               rmb();
-       while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
+       int ret = 0;
+       if (si->pdata->set_power)
+               ret = si->pdata->set_power(si->dev, state);
+       return ret;
+}
 
-       /*
-        * Clear the transmit underrun bit.
-        */
-       Ser2HSSR0 = HSSR0_TUR;
+static inline int
+sa1100_set_power(struct sa1100_irda *si, unsigned int state)
+{
+       int ret;
 
-       /*
-        * Do we need to change speed?  Note that we're lazy
-        * here - we don't free the old rxskb.  We don't need
-        * to allocate a buffer either.
-        */
-       if (si->newspeed) {
-               sa1100_irda_set_speed(si, si->newspeed);
-               si->newspeed = 0;
-       }
+       ret = __sa1100_irda_set_power(si, state);
+       if (ret == 0)
+               si->power = state;
 
-       /*
-        * Start reception.  This disables the transmitter for
-        * us.  This will be using the existing RX buffer.
-        */
-       sa1100_irda_rx_dma_start(si);
+       return ret;
+}
 
-       /*
-        * Account and free the packet.
-        */
-       if (skb) {
-               dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
-               dev->stats.tx_packets ++;
-               dev->stats.tx_bytes += skb->len;
-               dev_kfree_skb_irq(skb);
-       }
+static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct sa1100_irda *si = netdev_priv(dev);
 
-       /*
-        * Make sure that the TX queue is available for sending
-        * (for retries).  TX has priority over RX at all times.
-        */
-       netif_wake_queue(dev);
+       return si->irq(dev, si);
 }
 
 static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -660,62 +668,19 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        if (speed != si->speed && speed != -1)
                si->newspeed = speed;
 
-       /*
-        * If this is an empty frame, we can bypass a lot.
-        */
+       /* If this is an empty frame, we can bypass a lot. */
        if (skb->len == 0) {
-               if (si->newspeed) {
-                       si->newspeed = 0;
-                       sa1100_irda_set_speed(si, speed);
-               }
+               sa1100_irda_check_speed(si);
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
 
-       if (!IS_FIR(si)) {
-               netif_stop_queue(dev);
-
-               si->tx_buff.data = si->tx_buff.head;
-               si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
-                                                 si->tx_buff.truesize);
-
-               /*
-                * Set the transmit interrupt enable.  This will fire
-                * off an interrupt immediately.  Note that we disable
-                * the receiver so we won't get spurious characteres
-                * received.
-                */
-               Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
-
-               dev_kfree_skb(skb);
-       } else {
-               int mtt = irda_get_mtt(skb);
-
-               /*
-                * We must not be transmitting...
-                */
-               BUG_ON(si->txskb);
-
-               netif_stop_queue(dev);
-
-               si->txskb = skb;
-               si->txbuf_dma = dma_map_single(si->dev, skb->data,
-                                        skb->len, DMA_TO_DEVICE);
-
-               sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
-
-               /*
-                * If we have a mean turn-around time, impose the specified
-                * specified delay.  We could shorten this by timing from
-                * the point we received the packet.
-                */
-               if (mtt)
-                       udelay(mtt);
+       netif_stop_queue(dev);
 
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
-       }
+       /* We must not already have a skb to transmit... */
+       BUG_ON(si->dma_tx.skb);
 
-       return NETDEV_TX_OK;
+       return si->tx_start(skb, dev, si);
 }
 
 static int
@@ -762,6 +727,69 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
        return ret;
 }
 
+static int sa1100_irda_startup(struct sa1100_irda *si)
+{
+       int ret;
+
+       /*
+        * Ensure that the ports for this device are setup correctly.
+        */
+       if (si->pdata->startup) {
+               ret = si->pdata->startup(si->dev);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Configure PPC for IRDA - we want to drive TXD2 low.
+        * We also want to drive this pin low during sleep.
+        */
+       PPSR &= ~PPC_TXD2;
+       PSDR &= ~PPC_TXD2;
+       PPDR |= PPC_TXD2;
+
+       /*
+        * Enable HP-SIR modulation, and ensure that the port is disabled.
+        */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = HSCR0_UART;
+       Ser2UTCR4 = si->utcr4;
+       Ser2UTCR0 = UTCR0_8BitData;
+       Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
+
+       /*
+        * Clear status register
+        */
+       Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+
+       ret = sa1100_irda_set_speed(si, si->speed = 9600);
+       if (ret) {
+               Ser2UTCR3 = 0;
+               Ser2HSCR0 = 0;
+
+               if (si->pdata->shutdown)
+                       si->pdata->shutdown(si->dev);
+       }
+
+       return ret;
+}
+
+static void sa1100_irda_shutdown(struct sa1100_irda *si)
+{
+       /*
+        * Stop all DMA activity.
+        */
+       dmaengine_terminate_all(si->dma_rx.chan);
+       dmaengine_terminate_all(si->dma_tx.chan);
+
+       /* Disable the port. */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = 0;
+
+       if (si->pdata->shutdown)
+               si->pdata->shutdown(si->dev);
+}
+
 static int sa1100_irda_start(struct net_device *dev)
 {
        struct sa1100_irda *si = netdev_priv(dev);
@@ -769,26 +797,17 @@ static int sa1100_irda_start(struct net_device *dev)
 
        si->speed = 9600;
 
-       err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
-       if (err)
-               goto err_irq;
-
-       err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
-                                NULL, NULL, &si->rxdma);
+       err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc",
+                               &sa1100_irda_fir_rx);
        if (err)
                goto err_rx_dma;
 
-       err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
-                                sa1100_irda_txdma_irq, dev, &si->txdma);
+       err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
+                               &sa1100_irda_sir_tx);
        if (err)
                goto err_tx_dma;
 
        /*
-        * The interrupt must remain disabled for now.
-        */
-       disable_irq(dev->irq);
-
-       /*
         * Setup the serial port for the specified speed.
         */
        err = sa1100_irda_startup(si);
@@ -803,44 +822,60 @@ static int sa1100_irda_start(struct net_device *dev)
        if (!si->irlap)
                goto err_irlap;
 
+       err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
+       if (err)
+               goto err_irq;
+
        /*
         * Now enable the interrupt and start the queue
         */
        si->open = 1;
        sa1100_set_power(si, power_level); /* low power mode */
-       enable_irq(dev->irq);
+
        netif_start_queue(dev);
        return 0;
 
+err_irq:
+       irlap_close(si->irlap);
 err_irlap:
        si->open = 0;
        sa1100_irda_shutdown(si);
 err_startup:
-       sa1100_free_dma(si->txdma);
+       dma_release_channel(si->dma_tx.chan);
 err_tx_dma:
-       sa1100_free_dma(si->rxdma);
+       dma_release_channel(si->dma_rx.chan);
 err_rx_dma:
-       free_irq(dev->irq, dev);
-err_irq:
        return err;
 }
 
 static int sa1100_irda_stop(struct net_device *dev)
 {
        struct sa1100_irda *si = netdev_priv(dev);
+       struct sk_buff *skb;
 
-       disable_irq(dev->irq);
+       netif_stop_queue(dev);
+
+       si->open = 0;
        sa1100_irda_shutdown(si);
 
        /*
-        * If we have been doing DMA receive, make sure we
+        * If we have been doing any DMA activity, make sure we
         * tidy that up cleanly.
         */
-       if (si->rxskb) {
-               dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
-                                DMA_FROM_DEVICE);
-               dev_kfree_skb(si->rxskb);
-               si->rxskb = NULL;
+       skb = si->dma_rx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
+                            DMA_FROM_DEVICE);
+               dev_kfree_skb(skb);
+               si->dma_rx.skb = NULL;
+       }
+
+       skb = si->dma_tx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+                            DMA_TO_DEVICE);
+               dev_kfree_skb(skb);
+               si->dma_tx.skb = NULL;
        }
 
        /* Stop IrLAP */
@@ -849,14 +884,11 @@ static int sa1100_irda_stop(struct net_device *dev)
                si->irlap = NULL;
        }
 
-       netif_stop_queue(dev);
-       si->open = 0;
-
        /*
         * Free resources
         */
-       sa1100_free_dma(si->txdma);
-       sa1100_free_dma(si->rxdma);
+       dma_release_channel(si->dma_tx.chan);
+       dma_release_channel(si->dma_rx.chan);
        free_irq(dev->irq, dev);
 
        sa1100_set_power(si, 0);
@@ -888,11 +920,15 @@ static int sa1100_irda_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct sa1100_irda *si;
        unsigned int baudrate_mask;
-       int err;
+       int err, irq;
 
        if (!pdev->dev.platform_data)
                return -EINVAL;
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return irq < 0 ? irq : -ENXIO;
+
        err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
        if (err)
                goto err_mem_1;
@@ -907,22 +943,27 @@ static int sa1100_irda_probe(struct platform_device *pdev)
        if (!dev)
                goto err_mem_4;
 
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
        si = netdev_priv(dev);
        si->dev = &pdev->dev;
        si->pdata = pdev->dev.platform_data;
 
+       sg_init_table(&si->dma_rx.sg, 1);
+       sg_init_table(&si->dma_tx.sg, 1);
+
        /*
         * Initialise the HP-SIR buffers
         */
        err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
        if (err)
                goto err_mem_5;
-       err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);
+       err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME);
        if (err)
                goto err_mem_5;
 
        dev->netdev_ops = &sa1100_irda_netdev_ops;
-       dev->irq        = IRQ_Ser2ICP;
+       dev->irq        = irq;
 
        irda_init_max_qos_capabilies(&si->qos);
 
@@ -996,6 +1037,74 @@ static int sa1100_irda_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct sa1100_irda *si;
+
+       if (!dev)
+               return 0;
+
+       si = netdev_priv(dev);
+       if (si->open) {
+               /*
+                * Stop the transmit queue
+                */
+               netif_device_detach(dev);
+               disable_irq(dev->irq);
+               sa1100_irda_shutdown(si);
+               __sa1100_irda_set_power(si, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int sa1100_irda_resume(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct sa1100_irda *si;
+
+       if (!dev)
+               return 0;
+
+       si = netdev_priv(dev);
+       if (si->open) {
+               /*
+                * If we missed a speed change, initialise at the new speed
+                * directly.  It is debatable whether this is actually
+                * required, but in the interests of continuing from where
+                * we left off it is desirable.  The converse argument is
+                * that we should re-negotiate at 9600 baud again.
+                */
+               if (si->newspeed) {
+                       si->speed = si->newspeed;
+                       si->newspeed = 0;
+               }
+
+               sa1100_irda_startup(si);
+               __sa1100_irda_set_power(si, si->power);
+               enable_irq(dev->irq);
+
+               /*
+                * This automatically wakes up the queue
+                */
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+#else
+#define sa1100_irda_suspend    NULL
+#define sa1100_irda_resume     NULL
+#endif
+
 static struct platform_driver sa1100ir_driver = {
        .probe          = sa1100_irda_probe,
        .remove         = sa1100_irda_remove,
index c95639b..4300a7f 100644 (file)
@@ -94,12 +94,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
 
        ret = sa1111_pcmcia_configure_socket(skt, state);
        if (ret == 0) {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
-
-               local_irq_restore(flags);
+               neponset_ncr_frob(ncr_mask, ncr_set);
                sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
        }
 
index 27f2fe3..33568e1 100644 (file)
 
 #include "sa1111_generic.h"
 
+/*
+ * These are offsets from the above base.
+ */
+#define PCCR   0x0000
+#define PCSSR  0x0004
+#define PCSR   0x0008
+
+#define PCSR_S0_READY  (1<<0)
+#define PCSR_S1_READY  (1<<1)
+#define PCSR_S0_DETECT (1<<2)
+#define PCSR_S1_DETECT (1<<3)
+#define PCSR_S0_VS1    (1<<4)
+#define PCSR_S0_VS2    (1<<5)
+#define PCSR_S1_VS1    (1<<6)
+#define PCSR_S1_VS2    (1<<7)
+#define PCSR_S0_WP     (1<<8)
+#define PCSR_S1_WP     (1<<9)
+#define PCSR_S0_BVD1   (1<<10)
+#define PCSR_S0_BVD2   (1<<11)
+#define PCSR_S1_BVD1   (1<<12)
+#define PCSR_S1_BVD2   (1<<13)
+
+#define PCCR_S0_RST    (1<<0)
+#define PCCR_S1_RST    (1<<1)
+#define PCCR_S0_FLT    (1<<2)
+#define PCCR_S1_FLT    (1<<3)
+#define PCCR_S0_PWAITEN        (1<<4)
+#define PCCR_S1_PWAITEN        (1<<5)
+#define PCCR_S0_PSE    (1<<6)
+#define PCCR_S1_PSE    (1<<7)
+
+#define PCSSR_S0_SLEEP (1<<0)
+#define PCSSR_S1_SLEEP (1<<1)
+
 #define IDX_IRQ_S0_READY_NINT  (0)
 #define IDX_IRQ_S0_CD_VALID    (1)
 #define IDX_IRQ_S0_BVD1_STSCHG (2)
@@ -49,7 +83,7 @@ static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
        struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR);
+       unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
 
        switch (skt->nr) {
        case 0:
@@ -105,10 +139,10 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
                pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
 
        local_irq_save(flags);
-       val = sa1111_readl(s->dev->mapbase + SA1111_PCCR);
+       val = sa1111_readl(s->dev->mapbase + PCCR);
        val &= ~pccr_skt_mask;
        val |= pccr_set_mask & pccr_skt_mask;
-       sa1111_writel(val, s->dev->mapbase + SA1111_PCCR);
+       sa1111_writel(val, s->dev->mapbase + PCCR);
        local_irq_restore(flags);
 
        return 0;
@@ -163,12 +197,18 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 static int pcmcia_probe(struct sa1111_dev *dev)
 {
        void __iomem *base;
+       int ret;
+
+       ret = sa1111_enable_device(dev);
+       if (ret)
+               return ret;
 
        dev_set_drvdata(&dev->dev, NULL);
 
-       if (!request_mem_region(dev->res.start, 512,
-                               SA1111_DRIVER_NAME(dev)))
+       if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
+               sa1111_disable_device(dev);
                return -EBUSY;
+       }
 
        base = dev->mapbase;
 
@@ -181,8 +221,8 @@ static int pcmcia_probe(struct sa1111_dev *dev)
        /*
         * 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);
+       sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
+       sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
 
 #ifdef CONFIG_SA1100_BADGE4
        pcmcia_badge4_init(&dev->dev);
@@ -212,6 +252,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
        }
 
        release_mem_region(dev->res.start, 512);
+       sa1111_disable_device(dev);
        return 0;
 }
 
index cb9a585..e8f1add 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/bitops.h>
 
 #include <mach/hardware.h>
-#include <asm/irq.h>
+#include <mach/irqs.h>
 
 #ifdef CONFIG_ARCH_PXA
 #include <mach/regs-rtc.h>
index ef7a21a..2ca5959 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/serial_sa1100.h>
 
 /* We've been assigned a range on the "Low-density serial ports" major */
index 4bde4f9..e1004fb 100644 (file)
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/assabet.h>
-#include <mach/badge4.h>
 #include <asm/hardware/sa1111.h>
 
 #ifndef CONFIG_SA1111
 #error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
 #endif
 
-extern int usb_disabled(void);
+#define USB_STATUS     0x0118
+#define USB_RESET      0x011c
+#define USB_IRQTEST    0x0120
+
+#define USB_RESET_FORCEIFRESET (1 << 0)
+#define USB_RESET_FORCEHCRESET (1 << 1)
+#define USB_RESET_CLKGENRESET  (1 << 2)
+#define USB_RESET_SIMSCALEDOWN (1 << 3)
+#define USB_RESET_USBINTTEST   (1 << 4)
+#define USB_RESET_SLEEPSTBYEN  (1 << 5)
+#define USB_RESET_PWRSENSELOW  (1 << 6)
+#define USB_RESET_PWRCTRLLOW   (1 << 7)
+
+#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
+#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
+#define USB_STATUS_NIRQHCIM       (1 <<  9)
+#define USB_STATUS_NHCIMFCLR      (1 << 10)
+#define USB_STATUS_USBPWRSENSE    (1 << 11)
 
-/*-------------------------------------------------------------------------*/
+#if 0
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
+{
+       unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
+
+       dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+            ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+            ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+            ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+            ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+            ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
 
-static void sa1111_start_hc(struct sa1111_dev *dev)
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
 {
-       unsigned int usb_rst = 0;
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci_hcd_init(ohci);
+       return ohci_init(ohci);
+}
 
-       printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
-              __FILE__);
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int ret;
 
-#ifdef CONFIG_SA1100_BADGE4
-       if (machine_is_badge4()) {
-               badge4_set_5V(BADGE4_5V_USB, 1);
+       ret = ohci_run(ohci);
+       if (ret < 0) {
+               ohci_err(ohci, "can't start\n");
+               ohci_stop(hcd);
        }
+       return ret;
+}
+
+static const struct hc_driver ohci_sa1111_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "SA-1111 OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ohci_sa1111_reset,
+       .start =                ohci_sa1111_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
 #endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+static int sa1111_start_hc(struct sa1111_dev *dev)
+{
+       unsigned int usb_rst = 0;
+       int ret;
+
+       dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
 
        if (machine_is_xp860() ||
            machine_has_neponset() ||
@@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
         * host controller in reset.
         */
        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-                     dev->mapbase + SA1111_USB_RESET);
+                     dev->mapbase + USB_RESET);
 
        /*
         * Now, carefully enable the USB clock, and take
         * the USB host controller out of reset.
         */
-       sa1111_enable_device(dev);
-       udelay(11);
-       sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
+       ret = sa1111_enable_device(dev);
+       if (ret == 0) {
+               udelay(11);
+               sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
+       }
+
+       return ret;
 }
 
 static void sa1111_stop_hc(struct sa1111_dev *dev)
 {
        unsigned int usb_rst;
-       printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
-              __FILE__);
+
+       dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
 
        /*
         * Put the USB host controller into reset.
         */
-       usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+       usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-                     dev->mapbase + SA1111_USB_RESET);
+                     dev->mapbase + USB_RESET);
 
        /*
         * Stop the USB clock.
         */
        sa1111_disable_device(dev);
-
-#ifdef CONFIG_SA1100_BADGE4
-       if (machine_is_badge4()) {
-               /* Disable power to the USB bus */
-               badge4_set_5V(BADGE4_5V_USB, 0);
-       }
-#endif
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-#if 0
-static void dump_hci_status(struct usb_hcd *hcd, const char *label)
-{
-       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 " : ""),
-            ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
-            ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
-            ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
-            ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
 }
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
 
 /**
- * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
- * Context: !in_interrupt()
+ * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
  *
  * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
+ * then invokes the start() method for the HCD associated with it.
  */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver,
-                         struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
 {
        struct usb_hcd *hcd;
-       int retval;
+       int ret;
 
-       hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
        if (!hcd)
                return -ENOMEM;
+
        hcd->rsrc_start = dev->res.start;
        hcd->rsrc_len = resource_size(&dev->res);
 
        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
                dbg("request_mem_region failed");
-               retval = -EBUSY;
+               ret = -EBUSY;
                goto err1;
        }
+
        hcd->regs = dev->mapbase;
 
-       sa1111_start_hc(dev);
-       ohci_hcd_init(hcd_to_ohci(hcd));
+       ret = sa1111_start_hc(dev);
+       if (ret)
+               goto err2;
 
-       retval = usb_add_hcd(hcd, dev->irq[1], 0);
-       if (retval == 0)
-               return retval;
+       ret = usb_add_hcd(hcd, dev->irq[1], 0);
+       if (ret == 0)
+               return ret;
 
        sa1111_stop_hc(dev);
+ err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
        usb_put_hcd(hcd);
-       return retval;
+       return ret;
 }
 
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
 /**
- * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
  * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
  *
+ * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.
  */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 {
+       struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
        usb_remove_hcd(hcd);
        sa1111_stop_hc(dev);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
-}
-
-/*-------------------------------------------------------------------------*/
 
-static int __devinit
-ohci_sa1111_start (struct usb_hcd *hcd)
-{
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ret;
-
-       if ((ret = ohci_init(ohci)) < 0)
-               return ret;
-
-       if ((ret = ohci_run (ohci)) < 0) {
-               err ("can't start %s", hcd->self.bus_name);
-               ohci_stop (hcd);
-               return ret;
-       }
        return 0;
 }
 
-/*-------------------------------------------------------------------------*/
-
-static const struct hc_driver ohci_sa1111_hc_driver = {
-       .description =          hcd_name,
-       .product_desc =         "SA-1111 OHCI",
-       .hcd_priv_size =        sizeof(struct ohci_hcd),
-
-       /*
-        * generic hardware linkage
-        */
-       .irq =                  ohci_irq,
-       .flags =                HCD_USB11 | HCD_MEMORY,
-
-       /*
-        * basic lifecycle operations
-        */
-       .start =                ohci_sa1111_start,
-       .stop =                 ohci_stop,
-
-       /*
-        * managing i/o requests and associated device resources
-        */
-       .urb_enqueue =          ohci_urb_enqueue,
-       .urb_dequeue =          ohci_urb_dequeue,
-       .endpoint_disable =     ohci_endpoint_disable,
-
-       /*
-        * scheduling support
-        */
-       .get_frame_number =     ohci_get_frame,
-
-       /*
-        * root hub support
-        */
-       .hub_status_data =      ohci_hub_status_data,
-       .hub_control =          ohci_hub_control,
-#ifdef CONFIG_PM
-       .bus_suspend =          ohci_bus_suspend,
-       .bus_resume =           ohci_bus_resume,
-#endif
-       .start_port_reset =     ohci_start_port_reset,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
-{
-       int ret;
-
-       if (usb_disabled())
-               return -ENODEV;
-
-       ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
-       return ret;
-}
-
-static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
 {
        struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 
-       usb_hcd_sa1111_remove(hcd, dev);
-       return 0;
+       if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+               hcd->driver->shutdown(hcd);
+               sa1111_stop_hc(dev);
+       }
 }
 
 static struct sa1111_driver ohci_hcd_sa1111_driver = {
        .drv = {
                .name   = "sa1111-ohci",
+               .owner  = THIS_MODULE,
        },
        .devid          = SA1111_DEVID_USB,
-       .probe          = ohci_hcd_sa1111_drv_probe,
-       .remove         = ohci_hcd_sa1111_drv_remove,
+       .probe          = ohci_hcd_sa1111_probe,
+       .remove         = ohci_hcd_sa1111_remove,
+       .shutdown       = ohci_hcd_sa1111_shutdown,
 };
-
index 98d55d0..b632584 100644 (file)
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <mach/assabet.h>
 #include <mach/shannon.h>
 
 /*
- * debugging?
- */
-#define DEBUG 0
-/*
  * Complain if VAR is out of range.
  */
 #define DEBUG_VAR 1
 
-#undef ASSABET_PAL_VIDEO
-
 #include "sa1100fb.h"
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
-static struct sa1100fb_rgb rgb_4 = {
+static const struct sa1100fb_rgb rgb_4 = {
        .red    = { .offset = 0,  .length = 4, },
        .green  = { .offset = 0,  .length = 4, },
        .blue   = { .offset = 0,  .length = 4, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb rgb_8 = {
+static const struct sa1100fb_rgb rgb_8 = {
        .red    = { .offset = 0,  .length = 8, },
        .green  = { .offset = 0,  .length = 8, },
        .blue   = { .offset = 0,  .length = 8, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb def_rgb_16 = {
+static const struct sa1100fb_rgb def_rgb_16 = {
        .red    = { .offset = 11, .length = 5, },
        .green  = { .offset = 5,  .length = 6, },
        .blue   = { .offset = 0,  .length = 5, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-#ifdef CONFIG_SA1100_ASSABET
-#ifndef ASSABET_PAL_VIDEO
-/*
- * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
- * takes an RGB666 signal, but we provide it with an RGB565 signal
- * instead (def_rgb_16).
- */
-static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
-       .pixclock       = 171521,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 5,            .vsync_len      = 1,
-       .left_margin    = 61,           .upper_margin   = 3,
-       .right_margin   = 9,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#else
-static struct sa1100fb_mach_info pal_info __initdata = {
-       .pixclock       = 67797,        .bpp            = 16,
-       .xres           = 640,          .yres           = 512,
-
-       .hsync_len      = 64,           .vsync_len      = 6,
-       .left_margin    = 125,          .upper_margin   = 70,
-       .right_margin   = 115,          .lower_margin   = 36,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#endif
-
-#ifdef CONFIG_SA1100_H3600
-static struct sa1100fb_mach_info h3600_info __initdata = {
-       .pixclock       = 174757,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 3,            .vsync_len      = 3,
-       .left_margin    = 12,           .upper_margin   = 10,
-       .right_margin   = 17,           .lower_margin   = 1,
-
-       .cmap_static    = 1,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-
-static struct sa1100fb_rgb h3600_rgb_16 = {
-       .red    = { .offset = 12, .length = 4, },
-       .green  = { .offset = 7,  .length = 4, },
-       .blue   = { .offset = 1,  .length = 4, },
-       .transp = { .offset = 0,  .length = 0, },
-};
-#endif
-
-#ifdef CONFIG_SA1100_H3100
-static struct sa1100fb_mach_info h3100_info __initdata = {
-       .pixclock       = 406977,       .bpp            = 4,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 26,           .vsync_len      = 41,
-       .left_margin    = 4,            .upper_margin   = 0,
-       .right_margin   = 4,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-       .cmap_greyscale = 1,
-       .cmap_inverse   = 1,
-
-       .lccr0          = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef CONFIG_SA1100_COLLIE
-static struct sa1100fb_mach_info collie_info __initdata = {
-       .pixclock       = 171521,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 5,            .vsync_len      = 1,
-       .left_margin    = 11,           .upper_margin   = 2,
-       .right_margin   = 30,           .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef LART_GREY_LCD
-static struct sa1100fb_mach_info lart_grey_info __initdata = {
-       .pixclock       = 150000,       .bpp            = 4,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 1,            .vsync_len      = 1,
-       .left_margin    = 4,            .upper_margin   = 0,
-       .right_margin   = 2,            .lower_margin   = 0,
-
-       .cmap_greyscale = 1,
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_COLOR_LCD
-static struct sa1100fb_mach_info lart_color_info __initdata = {
-       .pixclock       = 150000,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 2,            .vsync_len      = 3,
-       .left_margin    = 69,           .upper_margin   = 14,
-       .right_margin   = 8,            .lower_margin   = 4,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_VIDEO_OUT
-static struct sa1100fb_mach_info lart_video_info __initdata = {
-       .pixclock       = 39721,        .bpp            = 16,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 95,           .vsync_len      = 2,
-       .left_margin    = 40,           .upper_margin   = 32,
-       .right_margin   = 24,           .lower_margin   = 11,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-
-#ifdef LART_KIT01_LCD
-static struct sa1100fb_mach_info lart_kit01_info __initdata = {
-       .pixclock       = 63291,        .bpp            = 16,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 64,           .vsync_len      = 3,
-       .left_margin    = 122,          .upper_margin   = 45,
-       .right_margin   = 10,           .lower_margin   = 10,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg
-};
-#endif
-
-#ifdef CONFIG_SA1100_SHANNON
-static struct sa1100fb_mach_info shannon_info __initdata = {
-       .pixclock       = 152500,       .bpp            = 8,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 4,            .vsync_len      = 3,
-       .left_margin    = 2,            .upper_margin   = 0,
-       .right_margin   = 1,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-       .lccr3          = LCCR3_ACBsDiv(512),
-};
-#endif
-
 
 
-static struct sa1100fb_mach_info * __init
-sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
-{
-       struct sa1100fb_mach_info *inf = NULL;
-
-       /*
-        *            R        G       B       T
-        * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
-        * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
-        * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
-        */
-#ifdef CONFIG_SA1100_ASSABET
-       if (machine_is_assabet()) {
-#ifndef ASSABET_PAL_VIDEO
-               inf = &lq039q2ds54_info;
-#else
-               inf = &pal_info;
-#endif
-       }
-#endif
-#ifdef CONFIG_SA1100_H3100
-       if (machine_is_h3100()) {
-               inf = &h3100_info;
-       }
-#endif
-#ifdef CONFIG_SA1100_H3600
-       if (machine_is_h3600()) {
-               inf = &h3600_info;
-               fbi->rgb[RGB_16] = &h3600_rgb_16;
-       }
-#endif
-#ifdef CONFIG_SA1100_COLLIE
-       if (machine_is_collie()) {
-               inf = &collie_info;
-       }
-#endif
-#ifdef CONFIG_SA1100_LART
-       if (machine_is_lart()) {
-#ifdef LART_GREY_LCD
-               inf = &lart_grey_info;
-#endif
-#ifdef LART_COLOR_LCD
-               inf = &lart_color_info;
-#endif
-#ifdef LART_VIDEO_OUT
-               inf = &lart_video_info;
-#endif
-#ifdef LART_KIT01_LCD
-               inf = &lart_kit01_info;
-#endif
-       }
-#endif
-#ifdef CONFIG_SA1100_SHANNON
-       if (machine_is_shannon()) {
-               inf = &shannon_info;
-       }
-#endif
-       return inf;
-}
-
 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
 static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
 
@@ -533,7 +299,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
         * is what you poke into the framebuffer to produce the
         * colour you requested.
         */
-       if (fbi->cmap_inverse) {
+       if (fbi->inf->cmap_inverse) {
                red   = 0xffff - red;
                green = 0xffff - green;
                blue  = 0xffff - blue;
@@ -607,14 +373,14 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                var->xres = MIN_XRES;
        if (var->yres < MIN_YRES)
                var->yres = MIN_YRES;
-       if (var->xres > fbi->max_xres)
-               var->xres = fbi->max_xres;
-       if (var->yres > fbi->max_yres)
-               var->yres = fbi->max_yres;
+       if (var->xres > fbi->inf->xres)
+               var->xres = fbi->inf->xres;
+       if (var->yres > fbi->inf->yres)
+               var->yres = fbi->inf->yres;
        var->xres_virtual = max(var->xres_virtual, var->xres);
        var->yres_virtual = max(var->yres_virtual, var->yres);
 
-       DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+       dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
        switch (var->bits_per_pixel) {
        case 4:
                rgbidx = RGB_4;
@@ -638,16 +404,16 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        var->blue   = fbi->rgb[rgbidx]->blue;
        var->transp = fbi->rgb[rgbidx]->transp;
 
-       DPRINTK("RGBT length = %d:%d:%d:%d\n",
+       dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
                var->red.length, var->green.length, var->blue.length,
                var->transp.length);
 
-       DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+       dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
                var->red.offset, var->green.offset, var->blue.offset,
                var->transp.offset);
 
 #ifdef CONFIG_CPU_FREQ
-       printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
+       dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
                sa1100fb_display_dma_period(var),
                cpufreq_get(smp_processor_id()));
 #endif
@@ -655,22 +421,10 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-static inline void sa1100fb_set_truecolor(u_int is_true_color)
+static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
 {
-       if (machine_is_assabet()) {
-#if 1          // phase 4 or newer Assabet's
-               if (is_true_color)
-                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-               else
-                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-#else
-               // older Assabet's
-               if (is_true_color)
-                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-               else
-                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-#endif
-       }
+       if (fbi->inf->set_visual)
+               fbi->inf->set_visual(visual);
 }
 
 /*
@@ -683,11 +437,11 @@ static int sa1100fb_set_par(struct fb_info *info)
        struct fb_var_screeninfo *var = &info->var;
        unsigned long palette_mem_size;
 
-       DPRINTK("set_par\n");
+       dev_dbg(fbi->dev, "set_par\n");
 
        if (var->bits_per_pixel == 16)
                fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-       else if (!fbi->cmap_static)
+       else if (!fbi->inf->cmap_static)
                fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
        else {
                /*
@@ -704,7 +458,7 @@ static int sa1100fb_set_par(struct fb_info *info)
 
        palette_mem_size = fbi->palette_size * sizeof(u16);
 
-       DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+       dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
 
        fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
        fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
@@ -712,7 +466,7 @@ static int sa1100fb_set_par(struct fb_info *info)
        /*
         * Set (any) board control register to handle new color depth
         */
-       sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+       sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
        sa1100fb_activate_var(var, fbi);
 
        return 0;
@@ -728,7 +482,7 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        /*
         * Make sure the user isn't doing something stupid.
         */
-       if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
+       if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
                return -EINVAL;
 
        return gen_set_cmap(cmap, kspc, con, info);
@@ -775,7 +529,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
        struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
        int i;
 
-       DPRINTK("sa1100fb_blank: blank=%d\n", blank);
+       dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
 
        switch (blank) {
        case FB_BLANK_POWERDOWN:
@@ -863,43 +617,43 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
        u_int half_screen_size, yres, pcd;
        u_long flags;
 
-       DPRINTK("Configuring SA1100 LCD\n");
+       dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
 
-       DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+       dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
                var->xres, var->hsync_len,
                var->left_margin, var->right_margin);
-       DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+       dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
                var->yres, var->vsync_len,
                var->upper_margin, var->lower_margin);
 
 #if DEBUG_VAR
        if (var->xres < 16        || var->xres > 1024)
-               printk(KERN_ERR "%s: invalid xres %d\n",
+               dev_err(fbi->dev, "%s: invalid xres %d\n",
                        fbi->fb.fix.id, var->xres);
        if (var->hsync_len < 1    || var->hsync_len > 64)
-               printk(KERN_ERR "%s: invalid hsync_len %d\n",
+               dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
                        fbi->fb.fix.id, var->hsync_len);
        if (var->left_margin < 1  || var->left_margin > 255)
-               printk(KERN_ERR "%s: invalid left_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid left_margin %d\n",
                        fbi->fb.fix.id, var->left_margin);
        if (var->right_margin < 1 || var->right_margin > 255)
-               printk(KERN_ERR "%s: invalid right_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid right_margin %d\n",
                        fbi->fb.fix.id, var->right_margin);
        if (var->yres < 1         || var->yres > 1024)
-               printk(KERN_ERR "%s: invalid yres %d\n",
+               dev_err(fbi->dev, "%s: invalid yres %d\n",
                        fbi->fb.fix.id, var->yres);
        if (var->vsync_len < 1    || var->vsync_len > 64)
-               printk(KERN_ERR "%s: invalid vsync_len %d\n",
+               dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
                        fbi->fb.fix.id, var->vsync_len);
        if (var->upper_margin < 0 || var->upper_margin > 255)
-               printk(KERN_ERR "%s: invalid upper_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
                        fbi->fb.fix.id, var->upper_margin);
        if (var->lower_margin < 0 || var->lower_margin > 255)
-               printk(KERN_ERR "%s: invalid lower_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
                        fbi->fb.fix.id, var->lower_margin);
 #endif
 
-       new_regs.lccr0 = fbi->lccr0 |
+       new_regs.lccr0 = fbi->inf->lccr0 |
                LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
                LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
 
@@ -914,7 +668,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
         * the YRES parameter.
         */
        yres = var->yres;
-       if (fbi->lccr0 & LCCR0_Dual)
+       if (fbi->inf->lccr0 & LCCR0_Dual)
                yres /= 2;
 
        new_regs.lccr2 =
@@ -924,14 +678,14 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
                LCCR2_EndFrmDel(var->lower_margin);
 
        pcd = get_pcd(var->pixclock, cpufreq_get(0));
-       new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
+       new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
                (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
                (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 
-       DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
-       DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
-       DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
-       DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
+       dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
+       dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
+       dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
+       dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
 
        half_screen_size = var->bits_per_pixel;
        half_screen_size = half_screen_size * var->xres * var->yres / 16;
@@ -951,9 +705,12 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
         * Only update the registers if the controller is enabled
         * and something has changed.
         */
-       if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
-           (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
-           (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
+       if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
+           readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
+           readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
+           readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
+           readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
+           readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
                sa1100fb_schedule_work(fbi, C_REENABLE);
 
        return 0;
@@ -967,18 +724,18 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
  */
 static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
 {
-       DPRINTK("backlight o%s\n", on ? "n" : "ff");
+       dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
 
-       if (sa1100fb_backlight_power)
-               sa1100fb_backlight_power(on);
+       if (fbi->inf->backlight_power)
+               fbi->inf->backlight_power(on);
 }
 
 static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
 {
-       DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+       dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
 
-       if (sa1100fb_lcd_power)
-               sa1100fb_lcd_power(on);
+       if (fbi->inf->lcd_power)
+               fbi->inf->lcd_power(on);
 }
 
 static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
@@ -1008,14 +765,25 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
        }
 
        if (mask) {
+               unsigned long flags;
+
+               /*
+                * SA-1100 requires the GPIO direction register set
+                * appropriately for the alternate function.  Hence
+                * we set it here via bitmask rather than excessive
+                * fiddling via the GPIO subsystem - and even then
+                * we'll still have to deal with GAFR.
+                */
+               local_irq_save(flags);
                GPDR |= mask;
                GAFR |= mask;
+               local_irq_restore(flags);
        }
 }
 
 static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 {
-       DPRINTK("Enabling LCD controller\n");
+       dev_dbg(fbi->dev, "Enabling LCD controller\n");
 
        /*
         * Make sure the mode bits are present in the first palette entry
@@ -1024,43 +792,46 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
        fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
        /* Sequence from 11.7.10 */
-       LCCR3 = fbi->reg_lccr3;
-       LCCR2 = fbi->reg_lccr2;
-       LCCR1 = fbi->reg_lccr1;
-       LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
-       DBAR1 = fbi->dbar1;
-       DBAR2 = fbi->dbar2;
-       LCCR0 |= LCCR0_LEN;
-
-       if (machine_is_shannon()) {
-               GPDR |= SHANNON_GPIO_DISP_EN;
-               GPSR |= SHANNON_GPIO_DISP_EN;
-       }
-
-       DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
-       DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
-       DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
-       DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
-       DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
-       DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
+       writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
+       writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
+       writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
+       writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
+       writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
+       writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
+       writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
+
+       if (machine_is_shannon())
+               gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
+
+       dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
+       dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
+       dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
+       dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
+       dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
+       dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
 }
 
 static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 {
        DECLARE_WAITQUEUE(wait, current);
+       u32 lccr0;
 
-       DPRINTK("Disabling LCD controller\n");
+       dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
-       if (machine_is_shannon()) {
-               GPCR |= SHANNON_GPIO_DISP_EN;
-       }       
+       if (machine_is_shannon())
+               gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&fbi->ctrlr_wait, &wait);
 
-       LCSR = 0xffffffff;      /* Clear LCD Status Register */
-       LCCR0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
-       LCCR0 &= ~LCCR0_LEN;    /* Disable LCD Controller */
+       /* Clear LCD Status Register */
+       writel_relaxed(~0, fbi->base + LCSR);
+
+       lccr0 = readl_relaxed(fbi->base + LCCR0);
+       lccr0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
+       writel_relaxed(lccr0, fbi->base + LCCR0);
+       lccr0 &= ~LCCR0_LEN;    /* Disable LCD Controller */
+       writel_relaxed(lccr0, fbi->base + LCCR0);
 
        schedule_timeout(20 * HZ / 1000);
        remove_wait_queue(&fbi->ctrlr_wait, &wait);
@@ -1072,14 +843,15 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
 {
        struct sa1100fb_info *fbi = dev_id;
-       unsigned int lcsr = LCSR;
+       unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
 
        if (lcsr & LCSR_LDD) {
-               LCCR0 |= LCCR0_LDM;
+               u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
+               writel_relaxed(lccr0, fbi->base + LCCR0);
                wake_up(&fbi->ctrlr_wait);
        }
 
-       LCSR = lcsr;
+       writel_relaxed(lcsr, fbi->base + LCSR);
        return IRQ_HANDLED;
 }
 
@@ -1268,7 +1040,7 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
        switch (val) {
        case CPUFREQ_ADJUST:
        case CPUFREQ_INCOMPATIBLE:
-               printk(KERN_DEBUG "min dma period: %d ps, "
+               dev_dbg(fbi->dev, "min dma period: %d ps, "
                        "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
                        policy->max);
                /* todo: fill in min/max values */
@@ -1318,7 +1090,7 @@ static int sa1100fb_resume(struct platform_device *dev)
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
+static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 {
        /*
         * We reserve one page for the palette, plus the size
@@ -1344,7 +1116,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __initdata = {
+static struct fb_monspecs monspecs __devinitdata = {
        .hfmin  = 30000,
        .hfmax  = 70000,
        .vfmin  = 50,
@@ -1352,10 +1124,11 @@ static struct fb_monspecs monspecs __initdata = {
 };
 
 
-static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
+static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 {
-       struct sa1100fb_mach_info *inf;
+       struct sa1100fb_mach_info *inf = dev->platform_data;
        struct sa1100fb_info *fbi;
+       unsigned i;
 
        fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
                      GFP_KERNEL);
@@ -1390,8 +1163,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
        fbi->rgb[RGB_8]         = &rgb_8;
        fbi->rgb[RGB_16]        = &def_rgb_16;
 
-       inf = sa1100fb_get_machine_info(fbi);
-
        /*
         * People just don't seem to get this.  We don't support
         * anything but correct entries now, so panic if someone
@@ -1402,13 +1173,10 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
                panic("sa1100fb error: invalid LCCR3 fields set or zero "
                        "pixclock.");
 
-       fbi->max_xres                   = inf->xres;
        fbi->fb.var.xres                = inf->xres;
        fbi->fb.var.xres_virtual        = inf->xres;
-       fbi->max_yres                   = inf->yres;
        fbi->fb.var.yres                = inf->yres;
        fbi->fb.var.yres_virtual        = inf->yres;
-       fbi->max_bpp                    = inf->bpp;
        fbi->fb.var.bits_per_pixel      = inf->bpp;
        fbi->fb.var.pixclock            = inf->pixclock;
        fbi->fb.var.hsync_len           = inf->hsync_len;
@@ -1419,14 +1187,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
        fbi->fb.var.lower_margin        = inf->lower_margin;
        fbi->fb.var.sync                = inf->sync;
        fbi->fb.var.grayscale           = inf->cmap_greyscale;
-       fbi->cmap_inverse               = inf->cmap_inverse;
-       fbi->cmap_static                = inf->cmap_static;
-       fbi->lccr0                      = inf->lccr0;
-       fbi->lccr3                      = inf->lccr3;
        fbi->state                      = C_STARTUP;
        fbi->task_state                 = (u_char)-1;
-       fbi->fb.fix.smem_len            = fbi->max_xres * fbi->max_yres *
-                                         fbi->max_bpp / 8;
+       fbi->fb.fix.smem_len            = inf->xres * inf->yres *
+                                         inf->bpp / 8;
+       fbi->inf                        = inf;
+
+       /* Copy the RGB bitfield overrides */
+       for (i = 0; i < NR_RGB; i++)
+               if (inf->rgb[i])
+                       fbi->rgb[i] = inf->rgb[i];
 
        init_waitqueue_head(&fbi->ctrlr_wait);
        INIT_WORK(&fbi->task, sa1100fb_task);
@@ -1438,13 +1208,20 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
 static int __devinit sa1100fb_probe(struct platform_device *pdev)
 {
        struct sa1100fb_info *fbi;
+       struct resource *res;
        int ret, irq;
 
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "no platform LCD data\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
+       if (irq < 0 || !res)
                return -EINVAL;
 
-       if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
+       if (!request_mem_region(res->start, resource_size(res), "LCD"))
                return -EBUSY;
 
        fbi = sa1100fb_init_fbinfo(&pdev->dev);
@@ -1452,6 +1229,10 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
        if (!fbi)
                goto failed;
 
+       fbi->base = ioremap(res->start, resource_size(res));
+       if (!fbi->base)
+               goto failed;
+
        /* Initialize video memory */
        ret = sa1100fb_map_video_memory(fbi);
        if (ret)
@@ -1459,14 +1240,16 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 
        ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
        if (ret) {
-               printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
+               dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
                goto failed;
        }
 
-#ifdef ASSABET_PAL_VIDEO
-       if (machine_is_assabet())
-               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
-#endif
+       if (machine_is_shannon()) {
+               ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
+                       GPIOF_OUT_INIT_LOW, "display enable");
+               if (ret)
+                       goto err_free_irq;
+       }
 
        /*
         * This makes sure that our colour bitfield
@@ -1478,7 +1261,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 
        ret = register_framebuffer(&fbi->fb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_reg_fb;
 
 #ifdef CONFIG_CPU_FREQ
        fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
@@ -1490,12 +1273,17 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
        /* This driver cannot be unloaded at the moment */
        return 0;
 
+ err_reg_fb:
+       if (machine_is_shannon())
+               gpio_free(SHANNON_GPIO_DISP_EN);
  err_free_irq:
        free_irq(irq, fbi);
  failed:
+       if (fbi)
+               iounmap(fbi->base);
        platform_set_drvdata(pdev, NULL);
        kfree(fbi);
-       release_mem_region(0xb0100000, 0x10000);
+       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
@@ -1505,6 +1293,7 @@ static struct platform_driver sa1100fb_driver = {
        .resume         = sa1100fb_resume,
        .driver         = {
                .name   = "sa11x0-fb",
+               .owner  = THIS_MODULE,
        },
 };
 
index 1c3b459..fc5d429 100644 (file)
  * for more details.
  */
 
-/*
- * These are the bitfields for each
- * display depth that we support.
- */
-struct sa1100fb_rgb {
-       struct fb_bitfield      red;
-       struct fb_bitfield      green;
-       struct fb_bitfield      blue;
-       struct fb_bitfield      transp;
-};
-
-/*
- * This structure describes the machine which we are running on.
- */
-struct sa1100fb_mach_info {
-       u_long          pixclock;
-
-       u_short         xres;
-       u_short         yres;
-
-       u_char          bpp;
-       u_char          hsync_len;
-       u_char          left_margin;
-       u_char          right_margin;
-
-       u_char          vsync_len;
-       u_char          upper_margin;
-       u_char          lower_margin;
-       u_char          sync;
-
-       u_int           cmap_greyscale:1,
-                       cmap_inverse:1,
-                       cmap_static:1,
-                       unused:29;
-
-       u_int           lccr0;
-       u_int           lccr3;
-};
+#define LCCR0           0x0000          /* LCD Control Reg. 0 */
+#define LCSR            0x0004          /* LCD Status Reg. */
+#define DBAR1           0x0010          /* LCD DMA Base Address Reg. channel 1 */
+#define DCAR1           0x0014          /* LCD DMA Current Address Reg. channel 1 */
+#define DBAR2           0x0018          /* LCD DMA Base Address Reg.  channel 2 */
+#define DCAR2           0x001C          /* LCD DMA Current Address Reg. channel 2 */
+#define LCCR1           0x0020          /* LCD Control Reg. 1 */
+#define LCCR2           0x0024          /* LCD Control Reg. 2 */
+#define LCCR3           0x0028          /* LCD Control Reg. 3 */
 
 /* Shadows for LCD controller registers */
 struct sa1100fb_lcd_reg {
@@ -57,19 +28,11 @@ struct sa1100fb_lcd_reg {
        unsigned long lccr3;
 };
 
-#define RGB_4  (0)
-#define RGB_8  (1)
-#define RGB_16 (2)
-#define NR_RGB 3
-
 struct sa1100fb_info {
        struct fb_info          fb;
        struct device           *dev;
-       struct sa1100fb_rgb     *rgb[NR_RGB];
-
-       u_int                   max_bpp;
-       u_int                   max_xres;
-       u_int                   max_yres;
+       const struct sa1100fb_rgb *rgb[NR_RGB];
+       void __iomem            *base;
 
        /*
         * These are the addresses we mapped
@@ -88,12 +51,6 @@ struct sa1100fb_info {
        dma_addr_t              dbar1;
        dma_addr_t              dbar2;
 
-       u_int                   lccr0;
-       u_int                   lccr3;
-       u_int                   cmap_inverse:1,
-                               cmap_static:1,
-                               unused:30;
-
        u_int                   reg_lccr0;
        u_int                   reg_lccr1;
        u_int                   reg_lccr2;
@@ -109,6 +66,8 @@ struct sa1100fb_info {
        struct notifier_block   freq_transition;
        struct notifier_block   freq_policy;
 #endif
+
+       const struct sa1100fb_mach_info *inf;
 };
 
 #define TO_INF(ptr,member)     container_of(ptr,struct sa1100fb_info,member)
@@ -130,15 +89,6 @@ struct sa1100fb_info {
 #define SA1100_NAME    "SA1100"
 
 /*
- *  Debug macros 
- */
-#if DEBUG
-#  define DPRINTK(fmt, args...)        printk("%s: " fmt, __func__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
-
-/*
  * Minimum X and Y resolutions
  */
 #define MIN_XRES       64
index f88c1cc..a9e8bd1 100644 (file)
@@ -10,8 +10,6 @@
 #ifndef MCP_H
 #define MCP_H
 
-#include <mach/dma.h>
-
 struct mcp_ops;
 
 struct mcp {
@@ -21,12 +19,7 @@ struct mcp {
        int             use_count;
        unsigned int    sclk_rate;
        unsigned int    rw_timeout;
-       dma_device_t    dma_audio_rd;
-       dma_device_t    dma_audio_wr;
-       dma_device_t    dma_telco_rd;
-       dma_device_t    dma_telco_wr;
        struct device   attached_device;
-       int             gpio_base;
 };
 
 struct mcp_ops {
@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *);
 #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
 
 struct mcp *mcp_host_alloc(struct device *, size_t);
-int mcp_host_register(struct mcp *);
-void mcp_host_unregister(struct mcp *);
+int mcp_host_add(struct mcp *, void *);
+void mcp_host_del(struct mcp *);
+void mcp_host_free(struct mcp *);
 
 struct mcp_driver {
        struct device_driver drv;
        int (*probe)(struct mcp *);
        void (*remove)(struct mcp *);
-       int (*suspend)(struct mcp *, pm_message_t);
-       int (*resume)(struct mcp *);
 };
 
 int mcp_driver_register(struct mcp_driver *);
index 4321f04..28af417 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/mfd/mcp.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
 
 #define UCB_IO_DATA    0x00
 #define UCB_IO_DIR     0x01
 #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
 #define UCB_MODE_AUD_OFF_CAN   (1 << 13)
 
+enum ucb1x00_reset {
+       UCB_RST_PROBE,
+       UCB_RST_RESUME,
+       UCB_RST_SUSPEND,
+       UCB_RST_REMOVE,
+       UCB_RST_PROBE_FAIL,
+};
 
-struct ucb1x00_irq {
-       void *devid;
-       void (*fn)(int, void *);
+struct ucb1x00_plat_data {
+       void                    (*reset)(enum ucb1x00_reset);
+       unsigned                irq_base;
+       int                     gpio_base;
+       unsigned                can_wakeup;
 };
 
 struct ucb1x00 {
-       spinlock_t              lock;
+       raw_spinlock_t          irq_lock;
        struct mcp              *mcp;
        unsigned int            irq;
-       struct semaphore        adc_sem;
+       int                     irq_base;
+       struct mutex            adc_mutex;
        spinlock_t              io_lock;
        u16                     id;
        u16                     io_dir;
@@ -122,7 +132,8 @@ struct ucb1x00 {
        u16                     adc_cr;
        u16                     irq_fal_enbl;
        u16                     irq_ris_enbl;
-       struct ucb1x00_irq      irq_handler[16];
+       u16                     irq_mask;
+       u16                     irq_wake;
        struct device           dev;
        struct list_head        node;
        struct list_head        devs;
@@ -144,7 +155,7 @@ struct ucb1x00_driver {
        struct list_head        devs;
        int     (*add)(struct ucb1x00_dev *dev);
        void    (*remove)(struct ucb1x00_dev *dev);
-       int     (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
+       int     (*suspend)(struct ucb1x00_dev *dev);
        int     (*resume)(struct ucb1x00_dev *dev);
 };
 
@@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
 void ucb1x00_adc_enable(struct ucb1x00 *ucb);
 void ucb1x00_adc_disable(struct ucb1x00 *ucb);
 
-/*
- * Which edges of the IRQ do you want to control today?
- */
-#define UCB_RISING     (1 << 0)
-#define UCB_FALLING    (1 << 1)
-
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
-
 #endif
diff --git a/include/linux/sa11x0-dma.h b/include/linux/sa11x0-dma.h
new file mode 100644 (file)
index 0000000..65839a5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SA11x0 DMA Engine support
+ *
+ * Copyright (C) 2012 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_SA11X0_DMA_H
+#define __LINUX_SA11X0_DMA_H
+
+struct dma_chan;
+
+#if defined(CONFIG_DMA_SA11X0) || defined(CONFIG_DMA_SA11X0_MODULE)
+bool sa11x0_dma_filter_fn(struct dma_chan *, void *);
+#else
+static inline bool sa11x0_dma_filter_fn(struct dma_chan *c, void *d)
+{
+       return false;
+}
+#endif
+
+#endif
diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h
new file mode 100644 (file)
index 0000000..4ab4096
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ *  Based on acornfb.c Copyright (C) Russell King.
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _VIDEO_SA1100FB_H
+#define _VIDEO_SA1100FB_H
+
+#include <linux/fb.h>
+#include <linux/types.h>
+
+#define RGB_4  0
+#define RGB_8  1
+#define RGB_16 2
+#define NR_RGB 3
+
+/* These are the bitfields for each display depth that we support. */
+struct sa1100fb_rgb {
+       struct fb_bitfield      red;
+       struct fb_bitfield      green;
+       struct fb_bitfield      blue;
+       struct fb_bitfield      transp;
+};
+
+/* This structure describes the machine which we are running on. */
+struct sa1100fb_mach_info {
+       u_long          pixclock;
+
+       u_short         xres;
+       u_short         yres;
+
+       u_char          bpp;
+       u_char          hsync_len;
+       u_char          left_margin;
+       u_char          right_margin;
+
+       u_char          vsync_len;
+       u_char          upper_margin;
+       u_char          lower_margin;
+       u_char          sync;
+
+       u_int           cmap_greyscale:1,
+                       cmap_inverse:1,
+                       cmap_static:1,
+                       unused:29;
+
+       u_int           lccr0;
+       u_int           lccr3;
+
+       /* Overrides for the default RGB maps */
+       const struct sa1100fb_rgb *rgb[NR_RGB];
+
+       void (*backlight_power)(int);
+       void (*lcd_power)(int);
+       void (*set_visual)(u32);
+};
+
+#endif