Merge branch 'sa11x0-ir' into sa11x0
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 61691cd..9173d11 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -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>
@@ -86,8 +86,10 @@
 #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 @@
 	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 @@
 struct sa1111_dev_info {
 	unsigned long	offset;
 	unsigned long	skpcr_mask;
+	bool		dma;
 	unsigned int	devid;
 	unsigned int	irq[6];
 };
@@ -126,6 +130,7 @@
 	{
 		.offset		= SA1111_USB,
 		.skpcr_mask	= SKPCR_UCLKEN,
+		.dma		= true,
 		.devid		= SA1111_DEVID_USB,
 		.irq = {
 			IRQ_USBPWR,
@@ -139,6 +144,7 @@
 	{
 		.offset		= 0x0600,
 		.skpcr_mask	= SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+		.dma		= true,
 		.devid		= SA1111_DEVID_SAC,
 		.irq = {
 			AUDXMTDMADONEA,
@@ -155,7 +161,7 @@
 	{
 		.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 @@
 	{
 		.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 @@
 	.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 @@
 	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 @@
 	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 @@
 }
 #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 @@
 		      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));
+
+	for (i = 0; i < ARRAY_SIZE(info->irq); i++)
+		dev->irq[i] = sachip->irq_base + info->irq[i];
+
+	/*
+	 * If the parent device has a DMA mask associated with it, and
+	 * this child supports DMA, propagate it down to the children.
+	 */
+	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;
+	}
 
 	ret = request_resource(parent, &dev->res);
 	if (ret) {
-		printk("SA1111: failed to allocate resource for %s\n",
+		dev_err(sachip->dev, "failed to allocate resource for %s\n",
 			dev->res.name);
-		dev_set_name(&dev->dev, NULL);
-		kfree(dev);
-		goto out;
+		goto err_resource;
 	}
 
+	ret = device_add(&dev->dev);
+	if (ret)
+		goto err_add;
+	return 0;
 
-	ret = device_register(&dev->dev);
-	if (ret) {
-		release_resource(&dev->res);
-		kfree(dev);
-		goto out;
-	}
-
-#ifdef CONFIG_DMABOUNCE
-	/*
-	 * If the parent device has a DMA mask associated with it,
-	 * propagate it down to the children.
-	 */
-	if (sachip->dev->dma_mask) {
-		dev->dma_mask = *sachip->dev->dma_mask;
-		dev->dev.dma_mask = &dev->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);
-			}
-		}
-	}
-#endif
-
-out:
+ err_add:
+	release_resource(&dev->res);
+ err_resource:
+	put_device(&dev->dev);
+ err_alloc:
 	return ret;
 }
 
@@ -698,16 +683,21 @@
  *	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 @@
 	sachip->dev = me;
 	dev_set_drvdata(sachip->dev, sachip);
 
+	sachip->pdata = pd;
 	sachip->phys = mem->start;
 	sachip->irq = irq;
 
@@ -759,6 +750,16 @@
 	 */
 	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 @@
 	}
 #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 @@
 
 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 @@
 	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 @@
 	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 @@
 	 */
 	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 @@
 	 */
 	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 @@
 	.resume		= sa1111_resume,
 	.driver		= {
 		.name	= "sa1111",
+		.owner	= THIS_MODULE,
 	},
 };
 
@@ -1238,16 +1244,23 @@
  *	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 @@
 	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 @@
 	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 @@
 	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 @@
 	.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 @@
 }
 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 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);
 }
 
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 92ed254..7c2bbc7 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -132,34 +132,10 @@
 #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
@@ -327,22 +303,6 @@
  *    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)
@@ -425,106 +385,30 @@
 #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
+/* PCMCIA Interface */
+#define SA1111_PCMCIA		0x1600
 
-#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
- *
- * 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 @@
 	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 @@
 #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 @@
 
 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 */
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6ebd276..6bb3f47 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -223,6 +223,7 @@
 
 static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= LUBBOCK_SA1111_IRQ_BASE,
+	.disable_devs	= SA1111_DEVID_SAC,
 };
 
 static struct platform_device sa1111_device = {
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 0c4b76a..e2d411a 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -40,13 +40,13 @@
 #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 | \
@@ -152,15 +152,8 @@
 };
 
 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),
 };
 
 
@@ -204,13 +197,22 @@
 	.sclk_rate	= 11981000,
 };
 
+#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 +220,16 @@
 	 * 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.
@@ -246,6 +256,9 @@
 #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
 	}
 
@@ -412,21 +425,8 @@
 	 */
 	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
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b07a2c0..5839c9d8 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -39,20 +39,28 @@
 #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 +129,8 @@
 	.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 +274,6 @@
 		.pfn		= __phys_to_pfn(0x10000000),
 		.length		= 0x00100000,
 		.type		= MT_DEVICE
-	}, {	/* SA-1111      */
-		.virtual	= 0xf4000000,
-		.pfn		= __phys_to_pfn(0x48000000),
-		.length		= 0x00100000,
-		.type		= MT_DEVICE
 	}
 };
 
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 11bb6d0..c2f9ba3 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -33,11 +33,7 @@
 #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 @@
 	.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)
 {
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index fd56521..dbe5cf7 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -48,11 +48,7 @@
 #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 = {
@@ -221,16 +217,8 @@
 
 
 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 +291,7 @@
 };
 
 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 void __init collie_init(void)
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 52ea622..1752686 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -150,16 +150,8 @@
 
 
 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;
@@ -176,16 +168,8 @@
 };
 
 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 = {
@@ -196,16 +180,8 @@
 };
 
 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 = {
@@ -216,16 +192,8 @@
 };
 
 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_IRQ(IRQ_Ser4MCP),
 };
 
 static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
@@ -247,16 +215,8 @@
 }
 
 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;
@@ -273,16 +233,8 @@
 };
 
 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 = {
@@ -315,23 +267,10 @@
 }
 
 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 = {
@@ -453,7 +392,7 @@
  * 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;
 
@@ -472,7 +411,7 @@
  * 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;
 
diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c
index b0784c9..63150e1 100644
--- a/arch/arm/mach-sa1100/h3xxx.c
+++ b/arch/arm/mach-sa1100/h3xxx.c
@@ -109,11 +109,8 @@
 	.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 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[] = {
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index c01bb36..37d381a 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -179,11 +179,8 @@
 	.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)
 {
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index d18f21a..9e07634 100644
--- a/arch/arm/mach-sa1100/include/mach/irqs.h
+++ b/arch/arm/mach-sa1100/include/mach/irqs.h
@@ -82,11 +82,3 @@
 #else
 #define NR_IRQS			(IRQ_BOARD_START)
 #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)
diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h
index ffe2bc4..5516a52 100644
--- a/arch/arm/mach-sa1100/include/mach/neponset.h
+++ b/arch/arm/mach-sa1100/include/mach/neponset.h
@@ -15,54 +15,6 @@
 /*
  * 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
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index dfbf824..5d12a30 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -221,11 +221,8 @@
 	.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;
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index ee121d6..8be8130 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -46,7 +46,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 +174,8 @@
 };
 
 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 +189,13 @@
 };
 
 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 @@
 		.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 @@
 	.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)
 {
diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
index 85f6ee6..3923911 100644
--- a/arch/arm/mach-sa1100/nanoengine.c
+++ b/arch/arm/mach-sa1100/nanoengine.c
@@ -58,15 +58,8 @@
 };
 
 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 = {
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b4fa53a..3297aa2 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -1,89 +1,103 @@
 /*
  * 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)
+#include <mach/hardware.h>
+#include <mach/assabet.h>
+#include <mach/neponset.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)
+
+extern void sa1110_mb_disable(void);
+
+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
+};
+
+static void __iomem *nep_base;
+
+void neponset_ncr_frob(unsigned int mask, unsigned int val)
 {
-	unsigned int irr;
+	void __iomem *base = nep_base;
 
-	while (1) {
-		/*
-		 * Acknowledge the parent IRQ.
-		 */
-		desc->irq_data.chip->irq_ack(&desc->irq_data);
+	if (base) {
+		unsigned long flags;
+		unsigned v;
 
-		/*
-		 * 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);
-
-			if (irr & IRR_ETHERNET) {
-				generic_handle_irq(IRQ_NEPONSET_SMC9196);
-			}
-
-			if (irr & IRR_USAR) {
-				generic_handle_irq(IRQ_NEPONSET_USAR);
-			}
-
-			desc->irq_data.chip->irq_unmask(&desc->irq_data);
-		}
-
-		if (irr & IRR_SA1111) {
-			generic_handle_irq(IRQ_NEPONSET_SA1111);
-		}
+		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 +120,19 @@
 			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 +157,279 @@
 	.get_mctrl	= neponset_get_mctrl,
 };
 
-static int __devinit neponset_probe(struct platform_device *dev)
-{
-	sa1100_register_uart_fns(&neponset_port_fns);
-
-	/*
-	 * Install handler for GPIO25.
-	 */
-	irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
-	irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
-
-	/*
-	 * 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
-
-	/*
-	 * 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);
-
-	/*
-	 * Disable GPIO 0/1 drivers so the buttons work on the module.
-	 */
-	NCR_0 = NCR_GP01_OFF;
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-
 /*
- * LDM power management.
+ * 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 unsigned int neponset_saved_state;
-
-static int neponset_suspend(struct platform_device *dev, pm_message_t state)
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	/*
-	 * Save state.
-	 */
-	neponset_saved_state = NCR_0;
+	struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
+	unsigned int irr;
 
-	return 0;
+	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 = readb_relaxed(d->base + 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);
+
+			if (irr & IRR_ETHERNET)
+				generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
+
+			if (irr & IRR_USAR)
+				generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
+
+			desc->irq_data.chip->irq_unmask(&desc->irq_data);
+		}
+
+		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;
 
-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,
+	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;
+	}
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	d->base = ioremap(nep_res->start, SZ_4K);
+	if (!d->base) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	d->irq_base = ret;
+
+	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);
+
+	irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+	irq_set_handler_data(irq, d);
+	irq_set_chained_handler(irq, neponset_irq_handler);
+
+	/*
+	 * 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();
+
+	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
+	writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
+
+	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 0;
+
+ err_irq_alloc:
+ err_id:
+	iounmap(d->base);
+ err_ioremap:
+	kfree(d);
+ err_alloc:
+	return ret;
+}
+
+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);
+
+	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 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,
+static struct platform_driver neponset_device_driver = {
+	.probe		= neponset_probe,
+	.remove		= __devexit_p(neponset_remove),
+	.driver		= {
+		.name	= "neponset",
+		.owner	= THIS_MODULE,
+		.pm	= PM_OPS,
 	},
 };
 
-static struct platform_device smc91x_device = {
-	.name		= "smc91x",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(smc91x_resources),
-	.resource	= smc91x_resources,
-};
-
-static struct platform_device *devices[] __initdata = {
-	&neponset_device,
-	&sa1111_device,
-	&smc91x_device,
-};
-
-extern void sa1110_mb_disable(void);
-
 static int __init neponset_init(void)
 {
-	platform_driver_register(&neponset_device_driver);
-
-	/*
-	 * The Neponset is only present on the Assabet machine type.
-	 */
-	if (!machine_is_assabet())
-		return -ENODEV;
-
-	/*
-	 * 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.
-	 */
-	sa1110_mb_disable();
-
-	if (!machine_has_neponset()) {
-		printk(KERN_DEBUG "Neponset expansion board not present\n");
-		return -ENODEV;
-	}
-
-	if (WHOAMI != 0x11) {
-		printk(KERN_WARNING "Neponset board detected, but "
-			"wrong ID: %02x\n", WHOAMI);
-		return -ENODEV;
-	}
-
-	return platform_add_devices(devices, ARRAY_SIZE(devices));
+	return platform_driver_register(&neponset_device_driver);
 }
 
 subsys_initcall(neponset_init);
-
-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
-	}
-};
-
-void __init neponset_map_io(void)
-{
-	iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
-}
diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c
index 0d01ca7..41bb018 100644
--- a/arch/arm/mach-sa1100/pci-nanoengine.c
+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
@@ -135,12 +135,8 @@
 				 &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",
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 9307df0..ca5d33b 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -37,17 +37,9 @@
 #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 @@
  * 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),
 };
 
 
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 318b2b7..5fd6156 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -46,11 +46,8 @@
 	.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,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index e17c04d..cdb9d19 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -176,15 +176,8 @@
 
 
 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 mcp_plat_data simpad_mcp_data = {
diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
index e822331..30cc672 100644
--- a/arch/arm/mach-sa1100/sleep.S
+++ b/arch/arm/mach-sa1100/sleep.S
@@ -26,27 +26,36 @@
  *
  * 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 @@
 	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]
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 44fc8b4..5ebabe3 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -24,6 +24,26 @@
 
 #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 @@
 	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 @@
 	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 @@
 	/*
 	 * 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 @@
 	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 @@
 		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 @@
 
 	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 @@
 {
 	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 @@
 	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 @@
 {
 	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 @@
 		ret = -ENODEV;
 	}
 
-	sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+	sa1111_writel(0, ps2if->base + PS2CR);
 
 	return ret;
 }
@@ -274,8 +298,8 @@
 	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 struct sa1111_driver ps2_driver = {
 	.drv = {
 		.name	= "sa1111-ps2",
+		.owner	= THIS_MODULE,
 	},
 	.devid		= SA1111_DEVID_PS2,
 	.probe		= ps2_probe,
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 64ad3ed..0dba050 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2281,7 +2281,7 @@
 	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);
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index c95639b..4300a7f 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -94,12 +94,7 @@
 
 	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);
 	}
 
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 27f2fe3..33568e1 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -22,6 +22,40 @@
 
 #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 @@
 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 @@
 		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 @@
 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 @@
 	/*
 	 * 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 @@
 	}
 
 	release_mem_region(dev->res.start, 512);
+	sa1111_disable_device(dev);
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4bde4f9..e1004fb 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -16,87 +16,37 @@
 #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)
 
-static void sa1111_start_hc(struct sa1111_dev *dev)
-{
-	unsigned int usb_rst = 0;
-
-	printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
-	       __FILE__);
-
-#ifdef CONFIG_SA1100_BADGE4
-	if (machine_is_badge4()) {
-		badge4_set_5V(BADGE4_5V_USB, 1);
-	}
-#endif
-
-	if (machine_is_xp860() ||
-	    machine_has_neponset() ||
-	    machine_is_pfs168() ||
-	    machine_is_badge4())
-		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
-
-	/*
-	 * Configure the power sense and control lines.  Place the USB
-	 * host controller in reset.
-	 */
-	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-		      dev->mapbase + SA1111_USB_RESET);
-
-	/*
-	 * Now, carefully enable the USB clock, and take
-	 * the USB host controller out of reset.
-	 */
-	sa1111_enable_device(dev);
-	udelay(11);
-	sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
-}
-
-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__);
-
-	/*
-	 * Put the USB host controller into reset.
-	 */
-	usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
-	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-		      dev->mapbase + SA1111_USB_RESET);
-
-	/*
-	 * Stop the USB clock.
-	 */
-	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
-}
-
-
-/*-------------------------------------------------------------------------*/
+#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 + SA1111_USB_STATUS);
+	unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
 
-	dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
+	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 "),
@@ -105,98 +55,27 @@
 }
 #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()
- *
- * 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().
- */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver,
-			  struct sa1111_dev *dev)
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
 {
-	struct usb_hcd *hcd;
-	int retval;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 
-	hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
-	if (!hcd)
-		return -ENOMEM;
-	hcd->rsrc_start = dev->res.start;
-	hcd->rsrc_len = resource_size(&dev->res);
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dbg("request_mem_region failed");
-		retval = -EBUSY;
-		goto err1;
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	ret = ohci_run(ohci);
+	if (ret < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
 	}
-	hcd->regs = dev->mapbase;
-
-	sa1111_start_hc(dev);
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	retval = usb_add_hcd(hcd, dev->irq[1], 0);
-	if (retval == 0)
-		return retval;
-
-	sa1111_stop_hc(dev);
-	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
- * @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.
- *
- */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *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",
@@ -211,8 +90,10 @@
 	/*
 	 * 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
@@ -238,33 +119,139 @@
 	.start_port_reset =	ohci_start_port_reset,
 };
 
-/*-------------------------------------------------------------------------*/
-
-static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
+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() ||
+	    machine_is_pfs168() ||
+	    machine_is_badge4())
+		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
+
+	/*
+	 * Configure the power sense and control lines.  Place the USB
+	 * host controller in reset.
+	 */
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + USB_RESET);
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of 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;
+
+	dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + USB_RESET);
+
+	/*
+	 * Stop the USB clock.
+	 */
+	sa1111_disable_device(dev);
+}
+
+/**
+ * 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.
+ */
+static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd;
 	int ret;
 
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
+	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");
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = dev->mapbase;
+
+	ret = sa1111_start_hc(dev);
+	if (ret)
+		goto err2;
+
+	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 ret;
 }
 
-static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+/**
+ * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * @dev: USB Host Controller being removed
+ *
+ * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.
+ */
+static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 {
 	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 
-	usb_hcd_sa1111_remove(hcd, dev);
+	usb_remove_hcd(hcd);
+	sa1111_stop_hc(dev);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
 	return 0;
 }
 
+static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
+	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,
 };
-