From bcbbf908e3c6d60f8efb7e2e8f09285bbda9e11e Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 10 Jun 2011 11:13:05 +0100
Subject: [PATCH 001/115] ARM: ebsa110: move platform definitions out of
 mach/hardware.h

Stop exposing platform definitions to the entire kernel tree, move
them into a private header file instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ebsa110/core.c                  |  5 +--
 arch/arm/mach-ebsa110/core.h                  | 37 ++++++++++++++++++
 arch/arm/mach-ebsa110/include/mach/hardware.h | 39 -------------------
 arch/arm/mach-ebsa110/io.c                    | 20 ++++++++++
 arch/arm/mach-ebsa110/leds.c                  |  2 +
 5 files changed, 60 insertions(+), 43 deletions(-)
 create mode 100644 arch/arm/mach-ebsa110/core.h

diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 294aad07f7a0..d7f83e912bd7 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -30,10 +30,7 @@
 
 #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)
 {
diff --git a/arch/arm/mach-ebsa110/core.h b/arch/arm/mach-ebsa110/core.h
new file mode 100644
index 000000000000..61f675426eb8
--- /dev/null
+++ b/arch/arm/mach-ebsa110/core.h
@@ -0,0 +1,37 @@
+/*
+ *  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 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
+
+/* 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
diff --git a/arch/arm/mach-ebsa110/include/mach/hardware.h b/arch/arm/mach-ebsa110/include/mach/hardware.h
index 4b2fb7743909..f4e5407bd004 100644
--- a/arch/arm/mach-ebsa110/include/mach/hardware.h
+++ b/arch/arm/mach-ebsa110/include/mach/hardware.h
@@ -12,48 +12,9 @@
 #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
  */
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index c52e3047a7eb..756cc377a73d 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -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) || \
diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c
index 6a6ea57c2a4e..d43121a30aa7 100644
--- a/arch/arm/mach-ebsa110/leds.c
+++ b/arch/arm/mach-ebsa110/leds.c
@@ -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)

From 5eca8f3a8048235d7fa3faa9ee4fc292d25a7425 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 10 Jun 2011 12:35:45 +0100
Subject: [PATCH 002/115] ARM: ebsa110: provide TRICK?_SIZE macros

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ebsa110/core.c | 8 ++++----
 arch/arm/mach-ebsa110/core.h | 4 ++++
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index d7f83e912bd7..6235efb0ccd4 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -76,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
index 61f675426eb8..c93c9e43012d 100644
--- a/arch/arm/mach-ebsa110/core.h
+++ b/arch/arm/mach-ebsa110/core.h
@@ -18,10 +18,14 @@
 #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

From 30816ac0495cb4f33fc8d748f64ac3cc880cb3c1 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 22:51:07 +0000
Subject: [PATCH 003/115] MFD: mcp-core: sanitize host creation/removal

host_unregister() gives us no chance between removing the device
and the mcp data structure being freed to access the data inbetween,
which drivers may need to do if they need to iounmap() pointers in
their private data structures.

Therefore, re-jig the interfaces, which are now, on creation:

	mcp = mcp_host_alloc()
	if (mcp) {
		ret = mcp_host_add(mcp, data);

		if (!ret)
			mcp_host_free(mcp);
	}

and on removal:

	mcp_host_del(mcp);
	... access mcp ...
	mcp_host_free(mcp);

The free does the final put_device() on the struct device as one would
expect.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-core.c   | 19 +++++++++++++------
 drivers/mfd/mcp-sa11x0.c |  6 ++++--
 include/linux/mfd/mcp.h  |  5 +++--
 3 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 86cc3f7841cd..cc7643177841 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -208,6 +208,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 +218,24 @@ 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)
 {
 	dev_set_name(&mcp->attached_device, "mcp0");
-	return device_register(&mcp->attached_device);
+	return device_add(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_register);
+EXPORT_SYMBOL(mcp_host_add);
 
-void mcp_host_unregister(struct mcp *mcp)
+void mcp_host_del(struct mcp *mcp)
 {
-	device_unregister(&mcp->attached_device);
+	device_del(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_unregister);
+EXPORT_SYMBOL(mcp_host_del);
+
+void mcp_host_free(struct mcp *mcp)
+{
+	put_device(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_free);
 
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 02c53a0766c4..33cadc0ec121 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -195,10 +195,11 @@ 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);
 	if (ret == 0)
 		goto out;
 
+	mcp_host_free(mcp);
  release:
 	release_mem_region(0x80060000, 0x60);
 	platform_set_drvdata(pdev, NULL);
@@ -212,7 +213,8 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
 	struct mcp *mcp = platform_get_drvdata(dev);
 
 	platform_set_drvdata(dev, NULL);
-	mcp_host_unregister(mcp);
+	mcp_host_del(mcp);
+	mcp_host_free(mcp);
 	release_mem_region(0x80060000, 0x60);
 
 	return 0;
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index f88c1cc0cb0f..79a6b13ba20c 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -47,8 +47,9 @@ 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 mcp_host_del(struct mcp *);
+void mcp_host_free(struct mcp *);
 
 struct mcp_driver {
 	struct device_driver drv;

From 7658e7f9a8122b0678e4b4280308560aa5444bd5 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 19:04:43 +0000
Subject: [PATCH 004/115] MFD: mcp-sa11x0: remove DMA initializers and
 variables

The dma_device_t variables are only ever written to by mcp-sa11x0 and
never read.  As the old SA11x0 DMA support will be removed, remove
these so that it no longer depends on the old SA11x0 DMA definitions.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-core.c        | 1 -
 drivers/mfd/mcp-sa11x0.c      | 5 -----
 drivers/mfd/ucb1x00-assabet.c | 3 ---
 drivers/mfd/ucb1x00-core.c    | 1 -
 drivers/mfd/ucb1x00-ts.c      | 1 -
 include/linux/mfd/mcp.h       | 6 ------
 6 files changed, 17 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index cc7643177841..280a4f8a7876 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -19,7 +19,6 @@
 #include <linux/string.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <asm/system.h>
 
 
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 33cadc0ec121..d2ebc641b014 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -20,7 +20,6 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/system.h>
@@ -158,10 +157,6 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	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);
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index cea9da60850d..b7be613cb503 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -16,9 +16,6 @@
 #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)	\
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index febc90cdef7e..f2fb4205467c 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -29,7 +29,6 @@
 #include <linux/gpio.h>
 #include <linux/semaphore.h>
 
-#include <mach/dma.h>
 #include <mach/hardware.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 63a3cbdfa3f3..ec6ffb6e287d 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -32,7 +32,6 @@
 #include <linux/kthread.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index 79a6b13ba20c..dfe7e517ad9b 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -10,8 +10,6 @@
 #ifndef MCP_H
 #define MCP_H
 
-#include <mach/dma.h>
-
 struct mcp_ops;
 
 struct mcp {
@@ -21,10 +19,6 @@ 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;
 };

From e36e26a8b761d1a601e284e2b5d8aff84de3b756 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 22:24:07 +0000
Subject: [PATCH 005/115] MFD: mcp-sa11x0: move setup of PPC unit out of
 mcp-sa11x0.c

Patch taken from af9081ae64 (ARM: sa1100: Refactor mcp-sa11x0 to use
platform resources.) by Jochen Friedrich <jochen@scram.de>, and
consolidated to use a common function.

Move the setup of the PPC unit out of mcp-sa11x0 into the core SA11x0
code, and call it from each platforms initialization file.  This
centralizes the setup of the PPC unit while not polluting the mcp-sa11x0
driver with these details.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c |  2 ++
 arch/arm/mach-sa1100/cerf.c    |  1 +
 arch/arm/mach-sa1100/collie.c  |  2 ++
 arch/arm/mach-sa1100/generic.c | 10 ++++++++++
 arch/arm/mach-sa1100/generic.h |  1 +
 arch/arm/mach-sa1100/lart.c    |  1 +
 arch/arm/mach-sa1100/shannon.c |  1 +
 arch/arm/mach-sa1100/simpad.c  |  1 +
 drivers/mfd/mcp-sa11x0.c       |  9 ---------
 9 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 0c4b76ab4d8e..3a1914568374 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -231,6 +231,8 @@ static void __init assabet_init(void)
 	PPDR |= PPC_TXD3 | PPC_TXD1;
 	PPSR |= PPC_TXD3 | PPC_TXD1;
 
+	sa11x0_ppc_configure_mcp();
+
 	sa1100fb_lcd_power = assabet_lcd_power;
 	sa1100fb_backlight_power = assabet_backlight_power;
 
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 11bb6d0b9be3..bc11879f80c8 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -128,6 +128,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);
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index b9060e236def..efa2bc132cbf 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -341,6 +341,8 @@ static void __init collie_init(void)
 
 	GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
 
+	sa11x0_ppc_configure_mcp();
+
 
 	platform_scoop_config = &collie_pcmcia_config;
 
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 480d2ea46b00..1416094cc013 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -240,6 +240,16 @@ 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);
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index 33268cf6be36..9236ff42bd1f 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -39,4 +39,5 @@ 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);
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index af4e2761f3db..eba64b781500 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -28,6 +28,7 @@ static struct mcp_plat_data lart_mcp_data = {
 
 static void __init lart_init(void)
 {
+	sa11x0_ppc_configure_mcp();
 	sa11x0_register_mcp(&lart_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 318b2b766a0b..3efb4ac62240 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -59,6 +59,7 @@ static struct mcp_plat_data shannon_mcp_data = {
 
 static void __init shannon_init(void)
 {
+	sa11x0_ppc_configure_mcp();
 	sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
 	sa11x0_register_mcp(&shannon_mcp_data);
 }
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index e17c04d6e324..3aa36ec21039 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -376,6 +376,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);
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index d2ebc641b014..5373a7a835c6 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -165,15 +165,6 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
 	}
 
-	/*
-	 * 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);
-
 	/*
 	 * Initialise device.  Note that we initially
 	 * set the sampling rate to minimum.

From c4592ce4e8f69d78711d53f0a42ec1b4dbf00cde Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 22:30:15 +0000
Subject: [PATCH 006/115] MFD: mcp-sa11x0: add .owner initializer

Patch partly taken from af9081ae64 (ARM: sa1100: Refactor mcp-sa11x0 to
use platform resources.) by Jochen Friedrich <jochen@scram.de>

Move the MODULE_ALIAS() alongside the other MODULE_* definitions, and
use DRIVER_NAME to ensure that the driver is consistently named.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 5373a7a835c6..703e76a77005 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -27,6 +27,7 @@
 
 #include <mach/assabet.h>
 
+#define DRIVER_NAME "sa11x0-mcp"
 
 struct mcp_sa11x0 {
 	u32	mccr0;
@@ -227,18 +228,14 @@ static int mcp_sa11x0_resume(struct platform_device *dev)
 	return 0;
 }
 
-/*
- * The driver for the SA11x0 MCP port.
- */
-MODULE_ALIAS("platform:sa11x0-mcp");
-
 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,
 	},
 };
 
@@ -247,6 +244,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");

From 45c7f75fd4b57035cd35954986a2faefb07dac9d Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 23:09:42 +0000
Subject: [PATCH 007/115] MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform
 resources

Patch taken from af9081ae64 (ARM: sa1100: Refactor mcp-sa11x0 to use
platform resources.) by Jochen Friedrich <jochen@scram.de>, and fixes
applied.

We can safely do this now that we have sanitized host removal; the
original patch had use-after-free bugs in the removal code.  Not only
that, but there was no checking of the ioremap() return.

The final change over Jochen's patch is that we wrap the base pointer
selection inside the various register indexes, which reduces the
possibility of the wrong register index being used.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/generic.c |   5 ++
 drivers/mfd/mcp-sa11x0.c       | 141 +++++++++++++++++++++++----------
 2 files changed, 104 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 1416094cc013..9379c53d3018 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -221,6 +221,11 @@ static struct resource sa11x0mcp_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
+		.start	= __PREG(Ser4MCCR1),
+		.end	= __PREG(Ser4MCCR1) + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
 		.start	= IRQ_Ser4MCP,
 		.end	= IRQ_Ser4MCP,
 		.flags	= IORESOURCE_IRQ,
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 703e76a77005..4d06db72bb9c 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -13,6 +13,7 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -30,34 +31,44 @@
 #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 +80,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 +107,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 +129,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,22 +156,38 @@ 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;
 
-	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+	if (!request_mem_region(mem0->start, resource_size(mem0),
+				DRIVER_NAME)) {
+		ret = -EBUSY;
+		goto err_mem0;
+	}
+
+	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;
@@ -160,7 +195,18 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	mcp->sclk_rate		= data->sclk_rate;
 	mcp->gpio_base		= data->gpio_base;
 
-	platform_set_drvdata(pdev, mcp);
+	m = priv(mcp);
+	m->mccr0 = data->mccr0 | 0x7f7f;
+	m->mccr1 = data->mccr1;
+
+	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;
+	}
+
+	platform_set_drvdata(dev, mcp);
 
 	if (machine_is_assabet()) {
 		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
@@ -170,9 +216,9 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	 * 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
@@ -184,46 +230,57 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 
 	ret = mcp_host_add(mcp);
 	if (ret == 0)
-		goto out;
+		return 0;
 
+	platform_set_drvdata(dev, NULL);
+
+ err_ioremap:
+	iounmap(m->base1);
+	iounmap(m->base0);
 	mcp_host_free(mcp);
- release:
-	release_mem_region(0x80060000, 0x60);
-	platform_set_drvdata(pdev, NULL);
-
- out:
+ 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;
+
+	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
 
 	platform_set_drvdata(dev, NULL);
 	mcp_host_del(mcp);
+	iounmap(m->base1);
+	iounmap(m->base0);
 	mcp_host_free(mcp);
-	release_mem_region(0x80060000, 0x60);
+	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)
 {
-	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(platform_get_drvdata(dev));
 
-	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)
 {
-	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(platform_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;
 }

From 2796e397373a15ece69267ed1bbb9f61435a3ac7 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 09:34:30 +0000
Subject: [PATCH 008/115] MFD: mcp-sa11x0: convert to use dev_pm_ops

Convert the sa11x0 MCP driver to use dev_pm_ops rather than the legacy
members in the platform driver.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 4d06db72bb9c..46167f676129 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mfd/mcp.h>
 
 #include <mach/hardware.h>
@@ -266,33 +267,38 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
 	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_sa11x0 *m = priv(platform_get_drvdata(dev));
+	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
 	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_sa11x0 *m = priv(platform_get_drvdata(dev));
+	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
 	writel_relaxed(m->mccr1, MCCR1(m));
 	writel_relaxed(m->mccr0, MCCR0(m));
 
 	return 0;
 }
+#endif
+
+static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mcp_sa11x0_suspend, mcp_sa11x0_resume)
+};
 
 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	= DRIVER_NAME,
 		.owner	= THIS_MODULE,
+		.pm	= &mcp_sa11x0_pm_ops,
 	},
 };
 

From a6aecae29affdd1a84198afe45ef9e13ecbf9826 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 18:03:00 +0000
Subject: [PATCH 009/115] MFD: mcp-sa11x0: use _noirq resume methods

The genirq code requires early access to interrupt controllers.  In
order to allow this, we need to resume the MCP via the _noirq methods
instead of the standard methods.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 46167f676129..420710b19f2d 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -289,7 +289,14 @@ static int mcp_sa11x0_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(mcp_sa11x0_suspend, mcp_sa11x0_resume)
+#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 = {

From 366a3591e0c1e8c1544cd8690368658a837a0846 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 19 Dec 2011 13:50:21 +0000
Subject: [PATCH 010/115] MTD: sa11x0: Remove shutdown handler

Commit c4a9f88daf ([MTD] [NOR] fix ctrl-alt-del can't reboot for
intel flash bug) interferes with this work-around, causing MTD to
issue this warning:

	Flash device refused suspend due to active operation (state 0)

The commit makes our work-around in the map driver unnecessary, so
let's remove it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mtd/maps/sa1100-flash.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 502821997707..c7355692ea85 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -373,21 +373,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,

From a6e68168f1c8a303116778d7213d64e0f67b9340 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 15:51:07 +0000
Subject: [PATCH 011/115] MTD: sa11x0: remove definitions and code left for
 documentation purposes

/*
 * This is here for documentation purposes only - until these people
 * submit their machine types.  It will be gone January 2005.
 */

It's now seven years after that date, so let's remove this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mtd/maps/sa1100-flash.c | 100 --------------------------------
 1 file changed, 100 deletions(-)

diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index c7355692ea85..cbc3b7867910 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -23,106 +23,6 @@
 #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;

From cb5e2399f9e504dc78525988c85882643e915da4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 10:59:21 +0000
Subject: [PATCH 012/115] ARM: sa11x0: fix off-by-one resource sizes

Hackkit defined its flash memory resource to be 32M + 1 byte.
Jornada defined the Epson video controller resources to be one byte
larger than they should be, and mis-mapped the SA-1111 companion
chip one byte smaller than it should be.

Fix these.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/hackkit.c    | 2 +-
 arch/arm/mach-sa1100/jornada720.c | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index c01bb36db940..9092b3aff534 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -181,7 +181,7 @@ static struct flash_platform_data hackkit_flash_data = {
 
 static struct resource hackkit_flash_resource = {
 	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_32M,
+	.end		= SA1100_CS0_PHYS + SZ_32M - 1,
 	.flags		= IORESOURCE_MEM,
 };
 
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index ee121d6f0480..5393b06ee2d2 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
@@ -176,12 +176,12 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
 static struct resource s1d13xxxfb_resources[] = {
 	[0] = {
 		.start	= EPSONFBSTART,
-		.end	= EPSONFBSTART + EPSONFBLEN,
+		.end	= EPSONFBSTART + EPSONFBLEN - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
 		.start	= EPSONREGSTART,
-		.end	= EPSONREGSTART + EPSONREGLEN,
+		.end	= EPSONREGSTART + EPSONREGLEN - 1,
 		.flags	= IORESOURCE_MEM,
 	}
 };
@@ -199,7 +199,7 @@ static struct platform_device s1d13xxxfb_device = {
 static struct resource sa1111_resources[] = {
 	[0] = {
 		.start		= SA1111REGSTART,
-		.end		= SA1111REGSTART + SA1111REGLEN,
+		.end		= SA1111REGSTART + SA1111REGLEN - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {

From f3bb3d7422b4161df31e2fd2e503897926d8ffe7 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 23 Jan 2012 18:39:21 +0000
Subject: [PATCH 013/115] ARM: sa11x0: fix sleep entry

Sometimes, we get stuck while trying to enter sleep.  This seems
to occur if we do not have udelay() in the instruction cache. Avoid
this by requesting a short delay prior to modifying the SDRAM timings.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/sleep.S | 37 +++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
index e8223315b442..30cc6721665b 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 @@ 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]

From 80ea2065e186d8d69b617770ae7fe51dfea6ba90 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 3 Feb 2012 18:16:45 +0000
Subject: [PATCH 014/115] ARM: sa11x0: fix section mismatch warnings

Neponset calls sa1110_mb_disable() from __devinit code, but
sa1110_mb_disable() is marked __init, and so causes a section
mismatch warning.

As sa1110_mb_enable() and sa1110_mb_disable() need to be callable
from suspend/resume paths as well, they must not be marked __init
or __devinit.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c       | 2 +-
 arch/arm/mach-sa1100/generic.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 61691cdbdcf2..bf508a78aa33 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -87,7 +87,7 @@
 #define IRQ_S0_BVD1_STSCHG	(53)
 #define IRQ_S1_BVD1_STSCHG	(54)
 
-extern void __init sa1110_mb_enable(void);
+extern void sa1110_mb_enable(void);
 
 /*
  * We keep the following data for the overall SA1111.  Note that the
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index bb10ee2cb89f..0e356bb89fb7 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -428,7 +428,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 +447,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;
 

From a181099e2f74dffe45487704cf0e97fd007b2628 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 10:25:29 +0000
Subject: [PATCH 015/115] ARM: sa11x0: convert to use DEFINE_RES_xxx macros

Convert StrongARM-11x0 platforms and core SoC code to use the
DEFINE_RES_xxx macros.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c        | 11 +---
 arch/arm/mach-sa1100/badge4.c         | 19 ++----
 arch/arm/mach-sa1100/cerf.c           | 13 +---
 arch/arm/mach-sa1100/collie.c         | 24 ++-----
 arch/arm/mach-sa1100/generic.c        | 93 +++++----------------------
 arch/arm/mach-sa1100/h3xxx.c          | 13 +---
 arch/arm/mach-sa1100/hackkit.c        |  7 +-
 arch/arm/mach-sa1100/irq.c            |  7 +-
 arch/arm/mach-sa1100/jornada720.c     | 31 ++-------
 arch/arm/mach-sa1100/nanoengine.c     | 11 +---
 arch/arm/mach-sa1100/neponset.c       | 39 ++---------
 arch/arm/mach-sa1100/pci-nanoengine.c |  8 +--
 arch/arm/mach-sa1100/pleb.c           | 24 ++-----
 arch/arm/mach-sa1100/shannon.c        |  7 +-
 arch/arm/mach-sa1100/simpad.c         | 11 +---
 15 files changed, 61 insertions(+), 257 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 0c4b76ab4d8e..642f3b3df215 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -152,15 +152,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),
 };
 
 
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b07a2c024cb7..ce2dbdf4ba1a 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -39,16 +39,8 @@
 #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 struct sa1111_platform_data sa1111_info = {
@@ -121,11 +113,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;
 
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 11bb6d0b9be3..c2f9ba3a9578 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 @@ 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)
 {
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index fd5652118ed1..dbe5cf719f7e 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 @@ 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 +291,7 @@ 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 void __init collie_init(void)
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 0e356bb89fb7..2b33b4597468 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -149,16 +149,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 +167,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 +179,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 +191,8 @@ 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_IRQ(IRQ_Ser4MCP),
 };
 
 static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
@@ -246,16 +214,8 @@ void sa11x0_register_mcp(struct mcp_plat_data *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 +232,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 = {
@@ -314,23 +266,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 = {
diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c
index b0784c974c2d..63150e1ffe9e 100644
--- a/arch/arm/mach-sa1100/h3xxx.c
+++ b/arch/arm/mach-sa1100/h3xxx.c
@@ -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[] = {
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 9092b3aff534..37d381ad5464 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -179,11 +179,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 - 1,
-	.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/irq.c b/arch/arm/mach-sa1100/irq.c
index dfbf824a69fa..5d12a305f53e 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -221,11 +221,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;
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 5393b06ee2d2..8512cfcc0d9b 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -174,16 +174,8 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
 };
 
 static struct resource s1d13xxxfb_resources[] = {
-	[0] = {
-		.start	= EPSONFBSTART,
-		.end	= EPSONFBSTART + EPSONFBLEN - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= EPSONREGSTART,
-		.end	= EPSONREGSTART + EPSONREGLEN - 1,
-		.flags	= IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
+	[1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
 };
 
 static struct platform_device s1d13xxxfb_device = {
@@ -197,16 +189,8 @@ static struct platform_device s1d13xxxfb_device = {
 };
 
 static struct resource sa1111_resources[] = {
-	[0] = {
-		.start		= SA1111REGSTART,
-		.end		= SA1111REGSTART + SA1111REGLEN - 1,
-		.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 = {
@@ -352,11 +336,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)
 {
diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
index 85f6ee672225..3923911000de 100644
--- a/arch/arm/mach-sa1100/nanoengine.c
+++ b/arch/arm/mach-sa1100/nanoengine.c
@@ -58,15 +58,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 = {
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b4fa53a1427e..abbe859b265d 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -213,11 +213,7 @@ static struct platform_driver neponset_device_driver = {
 };
 
 static struct resource neponset_resources[] = {
-	[0] = {
-		.start	= 0x10000000,
-		.end	= 0x17ffffff,
-		.flags	= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM(0x10000000, 0x08000000),
 };
 
 static struct platform_device neponset_device = {
@@ -228,16 +224,8 @@ static struct platform_device neponset_device = {
 };
 
 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,
-	},
+	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
+	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111),
 };
 
 static struct sa1111_platform_data sa1111_info = {
@@ -259,23 +247,10 @@ static struct platform_device sa1111_device = {
 };
 
 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,
-	},
+	[0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
+	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
+	[2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
+			0x02000000, "smc91x-attrib"),
 };
 
 static struct platform_device smc91x_device = {
diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c
index 0d01ca788922..41bb018b3103 100644
--- a/arch/arm/mach-sa1100/pci-nanoengine.c
+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
@@ -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",
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 9307df053533..ca5d33b6041a 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 @@ 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),
 };
 
 
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 318b2b766a0b..5fd615649847 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -46,11 +46,8 @@ 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,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index e17c04d6e324..cdb9d197c092 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -176,15 +176,8 @@ 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 mcp_plat_data simpad_mcp_data = {

From 7186fb9fd79d6209fe7aea9dbe06b629c61b389e Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 21:17:06 +0000
Subject: [PATCH 016/115] ARM: sa11x0: assabet: deassert QMUTE to codec while
 codec is unpowered

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 642f3b3df215..3a3282e08a70 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 | \

From 4f592e6d1a6711b2ef140b5c76342dbe2506c8cb Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 09:23:19 +0000
Subject: [PATCH 017/115] ARM: sa11x0: assabet: avoid glitching GPIOs when
 setting outputs

Avoid glitching the GPIO signals during initialization, which can
have undesirable effects.  Ensure that the desired pin state is set
before we change the GPIO pin direction to be an output.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 3a3282e08a70..6356896587bf 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -202,8 +202,8 @@ 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
@@ -211,8 +211,8 @@ 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;
 
 	/*
 	 * Set up registers for sleep mode.

From 49e01e3fb6efe1b0abfa2d5675f88f07989d621f Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 09:25:57 +0000
Subject: [PATCH 018/115] ARM: sa11x0: assabet: ensure that GPIO27 is driven

GPIO27 is just connected to a CPLD input without any pull-ups or pull-
downs.  If GPIO27 is left as an input, it will float around mid-supply,
which for CMOS inputs is the worst place for a pin to be.  Ensure that
this pin is driven.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 6356896587bf..e3805d4c052a 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -214,6 +214,14 @@ static void __init assabet_init(void)
 	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.
 	 */

From 710455201f6690841e9a40bedba09ddd0a7e0620 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 00:17:41 +0000
Subject: [PATCH 019/115] ARM: sa11x0: neponset: fix interrupt setup

Since ARM was converted to genirq, the neponset IRQ implementation has
gradually broken as a result of various subtle changes being introduced
into genirq.

It used to be that simple IRQs did not need an IRQ chip.  This is no
longer the case, and genirq barfs in irq_set_handler().  Fix this by
introducing a dummy no-op chip, and registering it along with the flow
handler.

Neponset IRQs really don't have any masking ability - all we have is a
status register to allow us to decode the source, and a three input OR
gate inside a CPLD.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index abbe859b265d..6a14d3760ccd 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -138,6 +138,20 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
 	.get_mctrl	= neponset_get_mctrl,
 };
 
+/*
+ * Yes, we really do not have any kind of masking or unmasking
+ */
+static void nochip_noop(struct irq_data *irq)
+{
+}
+
+static struct irq_chip nochip = {
+	.name = "neponset",
+	.irq_ack = nochip_noop,
+	.irq_mask = nochip_noop,
+	.irq_unmask = nochip_noop,
+};
+
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	sa1100_register_uart_fns(&neponset_port_fns);
@@ -161,10 +175,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	 * Setup other Neponset IRQs.  SA1111 will be done by the
 	 * generic SA1111 code.
 	 */
-	irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq);
+	irq_set_chip_and_handler(IRQ_NEPONSET_SMC9196, &nochip,
+		handle_simple_irq);
 	set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
-	irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq);
+	irq_set_chip_and_handler(IRQ_NEPONSET_USAR, &nochip,
+		handle_simple_irq);
 	set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
+	irq_set_chip(IRQ_NEPONSET_SA1111, &nochip);
 
 	/*
 	 * Disable GPIO 0/1 drivers so the buttons work on the module.

From 6ad1b614007c556129989b9f6b020d0d2e058121 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 09:31:47 +0000
Subject: [PATCH 020/115] ARM: sa11x0: neponset: provide function to manipulate
 NCR_0

Rather than having direct register accesses to NCR_0 scattered amongst
the code, provide a function instead.  This contains the necessary
race protection for this platform, ensuring that updates to this
register are safe.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/include/mach/neponset.h | 4 ++++
 arch/arm/mach-sa1100/neponset.c              | 9 +++++++++
 drivers/net/ethernet/smsc/smc91x.c           | 2 +-
 drivers/pcmcia/sa1100_neponset.c             | 7 +------
 4 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h
index ffe2bc45eed0..6032216e1830 100644
--- a/arch/arm/mach-sa1100/include/mach/neponset.h
+++ b/arch/arm/mach-sa1100/include/mach/neponset.h
@@ -71,4 +71,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/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 6a14d3760ccd..10be07e2bd56 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -20,6 +20,15 @@
 #include <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
 
+void neponset_ncr_frob(unsigned int mask, unsigned int val)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	NCR_0 = (NCR_0 & ~mask) | val;
+	local_irq_restore(flags);
+}
+
 /*
  * 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
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 64ad3ed74495..0dba0501b712 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -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);
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index c95639b5f2a0..4300a7fb3edb 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -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);
 	}
 

From 92e617d9e6f148b8301968c8b78e3cbc7bd5172e Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 22:13:00 +0000
Subject: [PATCH 021/115] ARM: sa11x0: neponset: shuffle some code around

Move the IRQ handler along side the rest of the IRQ code, and rearrange
the include files.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 206 ++++++++++++++++----------------
 1 file changed, 103 insertions(+), 103 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 10be07e2bd56..8fcd542d46f7 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -2,24 +2,24 @@
  * linux/arch/arm/mach-sa1100/neponset.c
  *
  */
-#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
-#include <linux/serial_core.h>
+#include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/serial_core.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>
 
+#include <mach/hardware.h>
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+
 void neponset_ncr_frob(unsigned int mask, unsigned int val)
 {
 	unsigned long flags;
@@ -29,66 +29,6 @@ void neponset_ncr_frob(unsigned int mask, unsigned int val)
 	local_irq_restore(flags);
 }
 
-/*
- * 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);
-
-			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);
-		}
-	}
-}
-
 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
 {
 	u_int mdm_ctl0 = MDM_CTL_0;
@@ -147,6 +87,66 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
 	.get_mctrl	= neponset_get_mctrl,
 };
 
+/*
+ * 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);
+
+			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);
+		}
+	}
+}
+
 /*
  * Yes, we really do not have any kind of masking or unmasking
  */
@@ -161,6 +161,43 @@ static struct irq_chip nochip = {
 	.irq_unmask = nochip_noop,
 };
 
+static struct resource sa1111_resources[] = {
+	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
+	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111),
+};
+
+static struct sa1111_platform_data sa1111_info = {
+	.irq_base	= IRQ_BOARD_END,
+};
+
+static u64 sa1111_dmamask = 0xffffffffUL;
+
+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,
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
+	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
+	[2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
+			0x02000000, "smc91x-attrib"),
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	sa1100_register_uart_fns(&neponset_port_fns);
@@ -249,43 +286,6 @@ static struct platform_device neponset_device = {
 	.resource	= neponset_resources,
 };
 
-static struct resource sa1111_resources[] = {
-	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
-	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111),
-};
-
-static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
-};
-
-static u64 sa1111_dmamask = 0xffffffffUL;
-
-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,
-};
-
-static struct resource smc91x_resources[] = {
-	[0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
-	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
-	[2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
-			0x02000000, "smc91x-attrib"),
-};
-
-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,

From 398e58d09d9ca024ecbf9b67dac57a995865bfcd Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 23:33:28 +0000
Subject: [PATCH 022/115] ARM: sa11x0: neponset: add driver .owner initializer

Ensure that the driver .owner field is properly initialized.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 8fcd542d46f7..1beaa0e5bf3f 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -272,6 +272,7 @@ static struct platform_driver neponset_device_driver = {
 	.resume		= neponset_resume,
 	.driver		= {
 		.name	= "neponset",
+		.owner	= THIS_MODULE,
 	},
 };
 

From ae14c2e28cd6d78a975dda853d2fdb00a3219c16 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 22:10:02 +0000
Subject: [PATCH 023/115] ARM: sa11x0: neponset: save and restore MDM_CTL_0

Save and restore the modem output control register across a suspend/
resume, as well as the NCR register.  Place these in a locally
allocated data structure rather than needing a new static variable.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 55 ++++++++++++++++++++++++++-------
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 1beaa0e5bf3f..6f0aa91d5d34 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -1,12 +1,13 @@
 /*
  * linux/arch/arm/mach-sa1100/neponset.c
- *
  */
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/slab.h>
 
 #include <asm/mach-types.h>
 #include <asm/irq.h>
@@ -20,6 +21,13 @@
 #include <mach/assabet.h>
 #include <mach/neponset.h>
 
+struct neponset_drvdata {
+#ifdef CONFIG_PM_SLEEP
+	u32 ncr0;
+	u32 mdm_ctl_0;
+#endif
+};
+
 void neponset_ncr_frob(unsigned int mask, unsigned int val)
 {
 	unsigned long flags;
@@ -200,6 +208,15 @@ static struct platform_device smc91x_device = {
 
 static int __devinit neponset_probe(struct platform_device *dev)
 {
+	struct neponset_drvdata *d;
+	int ret;
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
 	sa1100_register_uart_fns(&neponset_port_fns);
 
 	/*
@@ -234,29 +251,42 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	 */
 	NCR_0 = NCR_GP01_OFF;
 
+	platform_set_drvdata(dev, d);
+
+	return 0;
+
+ err_alloc:
+	return ret;
+}
+
+static int __devexit neponset_remove(struct platform_device *dev)
+{
+	struct neponset_drvdata *d = platform_get_drvdata(dev);
+
+	irq_set_chained_handler(IRQ_GPIO25, NULL);
+
+	kfree(d);
+
 	return 0;
 }
 
 #ifdef CONFIG_PM
-
-/*
- * LDM power management.
- */
-static unsigned int neponset_saved_state;
-
 static int neponset_suspend(struct platform_device *dev, pm_message_t state)
 {
-	/*
-	 * Save state.
-	 */
-	neponset_saved_state = NCR_0;
+	struct neponset_drvdata *d = platform_get_drvdata(dev);
+
+	d->ncr0 = NCR_0;
+	d->mdm_ctl_0 = MDM_CTL_0;
 
 	return 0;
 }
 
 static int neponset_resume(struct platform_device *dev)
 {
-	NCR_0 = neponset_saved_state;
+	struct neponset_drvdata *d = platform_get_drvdata(dev);
+
+	NCR_0 = d->ncr0;
+	MDM_CTL_0 = d->mdm_ctl_0;
 
 	return 0;
 }
@@ -268,6 +298,7 @@ static int neponset_resume(struct platform_device *dev)
 
 static struct platform_driver neponset_device_driver = {
 	.probe		= neponset_probe,
+	.remove		= __devexit_p(neponset_remove),
 	.suspend	= neponset_suspend,
 	.resume		= neponset_resume,
 	.driver		= {

From 9590e898742cd6cd50aab1109a115faf42befaf7 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 22:36:47 +0000
Subject: [PATCH 024/115] ARM: sa11x0: neponset: dynamically create neponset
 child devices

Use platform_device_register_full() to dynamically create the various
neponset child platform devices, and place them below the neponset
device itself to ensure proper PM ordering and device structure.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 56 ++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 6f0aa91d5d34..164bc9801ed7 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -1,6 +1,7 @@
 /*
  * linux/arch/arm/mach-sa1100/neponset.c
  */
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
@@ -22,6 +23,8 @@
 #include <mach/neponset.h>
 
 struct neponset_drvdata {
+	struct platform_device *sa1111;
+	struct platform_device *smc91x;
 #ifdef CONFIG_PM_SLEEP
 	u32 ncr0;
 	u32 mdm_ctl_0;
@@ -178,20 +181,6 @@ static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= IRQ_BOARD_END,
 };
 
-static u64 sa1111_dmamask = 0xffffffffUL;
-
-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,
-};
-
 static struct resource smc91x_resources[] = {
 	[0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
 	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
@@ -199,16 +188,26 @@ static struct resource smc91x_resources[] = {
 			0x02000000, "smc91x-attrib"),
 };
 
-static struct platform_device smc91x_device = {
-	.name		= "smc91x",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(smc91x_resources),
-	.resource	= smc91x_resources,
-};
-
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	struct neponset_drvdata *d;
+	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 platform_device_info smc91x_devinfo = {
+		.parent = &dev->dev,
+		.name = "smc91x",
+		.id = 0,
+		.res = smc91x_resources,
+		.num_res = ARRAY_SIZE(smc91x_resources),
+	};
 	int ret;
 
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
@@ -251,6 +250,9 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	 */
 	NCR_0 = NCR_GP01_OFF;
 
+	d->sa1111 = platform_device_register_full(&sa1111_devinfo);
+	d->smc91x = platform_device_register_full(&smc91x_devinfo);
+
 	platform_set_drvdata(dev, d);
 
 	return 0;
@@ -263,6 +265,10 @@ static int __devexit neponset_remove(struct platform_device *dev)
 {
 	struct neponset_drvdata *d = platform_get_drvdata(dev);
 
+	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_GPIO25, NULL);
 
 	kfree(d);
@@ -318,12 +324,6 @@ static struct platform_device neponset_device = {
 	.resource	= neponset_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)
@@ -354,7 +354,7 @@ static int __init neponset_init(void)
 		return -ENODEV;
 	}
 
-	return platform_add_devices(devices, ARRAY_SIZE(devices));
+	return platform_device_register(&neponset_device);
 }
 
 subsys_initcall(neponset_init);

From ced8d21cf104c9924e98f78954e873577366d156 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 22:22:18 +0000
Subject: [PATCH 025/115] ARM: sa11x0: neponset: implement support for sparse
 IRQs

Implement the necessary allocation/freeing functionality to support
sparse IRQs with the Neponset device.  On non-sparse IRQ platforms,
this allows us to dynamically allocate from within the available IRQ
number space.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/include/mach/irqs.h |   8 --
 arch/arm/mach-sa1100/neponset.c          | 111 +++++++++++++----------
 2 files changed, 61 insertions(+), 58 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index d18f21abef80..9e07634a4670 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/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 164bc9801ed7..47681960783b 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -4,6 +4,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -11,9 +12,7 @@
 #include <linux/slab.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 <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
@@ -22,9 +21,15 @@
 #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
+
 struct neponset_drvdata {
 	struct platform_device *sa1111;
 	struct platform_device *smc91x;
+	unsigned irq_base;
 #ifdef CONFIG_PM_SLEEP
 	u32 ncr0;
 	u32 mdm_ctl_0;
@@ -104,9 +109,9 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
  * 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)
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
+	struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
 	unsigned int irr;
 
 	while (1) {
@@ -141,26 +146,21 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 			 */
 			desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-			if (irr & IRR_ETHERNET) {
-				generic_handle_irq(IRQ_NEPONSET_SMC9196);
-			}
+			if (irr & IRR_ETHERNET)
+				generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
 
-			if (irr & IRR_USAR) {
-				generic_handle_irq(IRQ_NEPONSET_USAR);
-			}
+			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(IRQ_NEPONSET_SA1111);
-		}
+		if (irr & IRR_SA1111)
+			generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
 	}
 }
 
-/*
- * Yes, we really do not have any kind of masking or unmasking
- */
+/* Yes, we really do not have any kind of masking or unmasking */
 static void nochip_noop(struct irq_data *irq)
 {
 }
@@ -172,25 +172,17 @@ static struct irq_chip nochip = {
 	.irq_unmask = nochip_noop,
 };
 
-static struct resource sa1111_resources[] = {
-	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
-	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111),
-};
-
 static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= IRQ_BOARD_END,
 };
 
-static struct resource smc91x_resources[] = {
-	[0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
-	[1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
-	[2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
-			0x02000000, "smc91x-attrib"),
-};
-
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	struct neponset_drvdata *d;
+	struct resource sa1111_resources[] = {
+		DEFINE_RES_MEM(0x40000000, SZ_8K),
+		{ .flags = IORESOURCE_IRQ },
+	};
 	struct platform_device_info sa1111_devinfo = {
 		.parent = &dev->dev,
 		.name = "sa1111",
@@ -201,6 +193,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 		.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",
@@ -216,47 +215,59 @@ static int __devinit neponset_probe(struct platform_device *dev)
 		goto err_alloc;
 	}
 
-	sa1100_register_uart_fns(&neponset_port_fns);
+	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);
 
-	/*
-	 * Install handler for GPIO25.
-	 */
 	irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
+	irq_set_handler_data(IRQ_GPIO25, d);
 	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?)
+	 * 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_GPIO25);
 #endif
 
-	/*
-	 * Setup other Neponset IRQs.  SA1111 will be done by the
-	 * generic SA1111 code.
-	 */
-	irq_set_chip_and_handler(IRQ_NEPONSET_SMC9196, &nochip,
-		handle_simple_irq);
-	set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
-	irq_set_chip_and_handler(IRQ_NEPONSET_USAR, &nochip,
-		handle_simple_irq);
-	set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
-	irq_set_chip(IRQ_NEPONSET_SA1111, &nochip);
+	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
+		 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
 
-	/*
-	 * Disable GPIO 0/1 drivers so the buttons work on the module.
-	 */
+	sa1100_register_uart_fns(&neponset_port_fns);
+
+	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
 	NCR_0 = NCR_GP01_OFF;
 
+	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[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:
+	kfree(d);
  err_alloc:
 	return ret;
 }
@@ -270,7 +281,7 @@ static int __devexit neponset_remove(struct platform_device *dev)
 	if (!IS_ERR(d->smc91x))
 		platform_device_unregister(d->smc91x);
 	irq_set_chained_handler(IRQ_GPIO25, NULL);
-
+	irq_free_descs(d->irq_base, NEP_IRQ_NR);
 	kfree(d);
 
 	return 0;

From b6bdfcf5ae634fcb9dce0c16972cf39d90be6f74 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 23:05:08 +0000
Subject: [PATCH 026/115] ARM: sa11x0: neponset: get parent IRQ from neponset
 device resource

Obtain the parent IRQ from the neponset device resource rather than
hard-coding it into the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 47681960783b..f4d587151770 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -207,7 +207,11 @@ static int __devinit neponset_probe(struct platform_device *dev)
 		.res = smc91x_resources,
 		.num_res = ARRAY_SIZE(smc91x_resources),
 	};
-	int ret;
+	int ret, irq;
+
+	irq = ret = platform_get_irq(dev, 0);
+	if (ret < 0)
+		goto err_alloc;
 
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d) {
@@ -234,16 +238,16 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	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_GPIO25, IRQ_TYPE_EDGE_RISING);
-	irq_set_handler_data(IRQ_GPIO25, d);
-	irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
+	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_GPIO25);
+	enable_irq_wake(irq);
 #endif
 
 	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
@@ -275,12 +279,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 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_GPIO25, NULL);
+	irq_set_chained_handler(irq, NULL);
 	irq_free_descs(d->irq_base, NEP_IRQ_NR);
 	kfree(d);
 
@@ -325,7 +330,8 @@ static struct platform_driver neponset_device_driver = {
 };
 
 static struct resource neponset_resources[] = {
-	[0] = DEFINE_RES_MEM(0x10000000, 0x08000000),
+	DEFINE_RES_MEM(0x10000000, 0x08000000),
+	DEFINE_RES_IRQ(IRQ_GPIO25),
 };
 
 static struct platform_device neponset_device = {

From d2e539a5ebd6b204037deb44c416a9e20b5d2354 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 23:17:37 +0000
Subject: [PATCH 027/115] ARM: sa11x0: neponset: place smc91x and sa1111
 resources in neponset device

Complete the neponset device resources by covering the children's
memory resources in the parent neponset device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index f4d587151770..2451a38aa2f0 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -179,6 +179,7 @@ static struct sa1111_platform_data sa1111_info = {
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	struct neponset_drvdata *d;
+	struct resource *sa1111_res, *smc91x_res;
 	struct resource sa1111_resources[] = {
 		DEFINE_RES_MEM(0x40000000, SZ_8K),
 		{ .flags = IORESOURCE_IRQ },
@@ -213,6 +214,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	if (ret < 0)
 		goto err_alloc;
 
+	smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+	sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
+	if (!smc91x_res || !sa1111_res) {
+		ret = -ENXIO;
+		goto err_alloc;
+	}
+
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d) {
 		ret = -ENOMEM;
@@ -258,10 +266,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
 	NCR_0 = NCR_GP01_OFF;
 
+	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);
@@ -331,6 +342,8 @@ static struct platform_driver neponset_device_driver = {
 
 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),
 };
 

From 51f93390c21a4154b0520c3a8a34733e4072a7db Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 23:29:47 +0000
Subject: [PATCH 028/115] ARM: sa11x0: neponset: suspend/resume in _noirq state

Suspend and resume in the _noirq state, so that we're saving the
state of the modem control signals as late as possible, and restoring
them as early as possible.  There's nothing to do in thaw/poweroff
methods as we've already saved the necessary state.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 2451a38aa2f0..59223baa7c1d 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -8,6 +8,7 @@
 #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>
 
@@ -303,10 +304,10 @@ static int __devexit neponset_remove(struct platform_device *dev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int neponset_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int neponset_suspend(struct device *dev)
 {
-	struct neponset_drvdata *d = platform_get_drvdata(dev);
+	struct neponset_drvdata *d = dev_get_drvdata(dev);
 
 	d->ncr0 = NCR_0;
 	d->mdm_ctl_0 = MDM_CTL_0;
@@ -314,9 +315,9 @@ static int neponset_suspend(struct platform_device *dev, pm_message_t state)
 	return 0;
 }
 
-static int neponset_resume(struct platform_device *dev)
+static int neponset_resume(struct device *dev)
 {
-	struct neponset_drvdata *d = platform_get_drvdata(dev);
+	struct neponset_drvdata *d = dev_get_drvdata(dev);
 
 	NCR_0 = d->ncr0;
 	MDM_CTL_0 = d->mdm_ctl_0;
@@ -324,19 +325,24 @@ static int neponset_resume(struct platform_device *dev)
 	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 neponset_suspend NULL
-#define neponset_resume  NULL
+#define PM_OPS NULL
 #endif
 
 static struct platform_driver neponset_device_driver = {
 	.probe		= neponset_probe,
 	.remove		= __devexit_p(neponset_remove),
-	.suspend	= neponset_suspend,
-	.resume		= neponset_resume,
 	.driver		= {
 		.name	= "neponset",
 		.owner	= THIS_MODULE,
+		.pm	= PM_OPS,
 	},
 };
 

From bab50a35ee703955bd708a4a44cd56ed30e601c8 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 11:50:23 +0000
Subject: [PATCH 029/115] ARM: sa11x0: assabet/neponest: create neponset device
 in assabet.c

The neponset board is a daughter board for the Assabet.  Create the
neponset platform device in assabet.c, where we don't have to wrap
it with machine_is_assabet() stuff.  We also create this device
dynamically rather than keeping it as a static device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c  | 12 +++++++
 arch/arm/mach-sa1100/neponset.c | 56 ++++++++-------------------------
 2 files changed, 25 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index e3805d4c052a..f2030bc22cde 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -197,6 +197,15 @@ static struct mcp_plat_data assabet_mcp_data = {
 	.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)
 {
 	/*
@@ -247,6 +256,9 @@ 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
 	}
 
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 59223baa7c1d..2a9e1e2223f0 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -27,6 +27,8 @@
 #define NEP_IRQ_SA1111	2
 #define NEP_IRQ_NR	3
 
+extern void sa1110_mb_disable(void);
+
 struct neponset_drvdata {
 	struct platform_device *sa1111;
 	struct platform_device *smc91x;
@@ -222,6 +224,13 @@ static int __devinit neponset_probe(struct platform_device *dev)
 		goto err_alloc;
 	}
 
+	if (WHOAMI != 0x11) {
+		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
+			 WHOAMI);
+		ret = -ENODEV;
+		goto err_alloc;
+	}
+
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d) {
 		ret = -ENOMEM;
@@ -264,6 +273,9 @@ static int __devinit neponset_probe(struct platform_device *dev)
 
 	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 */
 	NCR_0 = NCR_GP01_OFF;
 
@@ -346,51 +358,9 @@ static struct platform_driver neponset_device_driver = {
 	},
 };
 
-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),
-};
-
-static struct platform_device neponset_device = {
-	.name		= "neponset",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(neponset_resources),
-	.resource	= neponset_resources,
-};
-
-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_device_register(&neponset_device);
+	return platform_driver_register(&neponset_device_driver);
 }
 
 subsys_initcall(neponset_init);

From f942b0fd6c81416bb8d52bc26a76a58c02d87bc2 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 11:19:06 +0000
Subject: [PATCH 030/115] ARM: sa11x0: neponset: move register definitions to
 neponset.c

Move the board specific neponset register definitions to the board
file, rather than mach/neponset.h.  However, as the NCR_0 register
definitions are used by some drivers, leave these behind.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/include/mach/neponset.h |  48 --------
 arch/arm/mach-sa1100/neponset.c              | 112 +++++++++++++++----
 2 files changed, 90 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h
index 6032216e1830..5516a52a329d 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)
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 2a9e1e2223f0..3c0d4b837adb 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -27,9 +27,40 @@
 #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;
@@ -39,19 +70,34 @@ struct neponset_drvdata {
 #endif
 };
 
+static void __iomem *nep_base;
+
 void neponset_ncr_frob(unsigned int mask, unsigned int val)
 {
-	unsigned long flags;
+	void __iomem *base = nep_base;
 
-	local_irq_save(flags);
-	NCR_0 = (NCR_0 & ~mask) | val;
-	local_irq_restore(flags);
+	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;
@@ -74,14 +120,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;
@@ -128,7 +179,8 @@ static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 		 * 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);
+		irr = readb_relaxed(d->base + IRR);
+		irr ^= IRR_ETHERNET | IRR_USAR;
 
 		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
 			break;
@@ -182,7 +234,7 @@ static struct sa1111_platform_data sa1111_info = {
 static int __devinit neponset_probe(struct platform_device *dev)
 {
 	struct neponset_drvdata *d;
-	struct resource *sa1111_res, *smc91x_res;
+	struct resource *nep_res, *sa1111_res, *smc91x_res;
 	struct resource sa1111_resources[] = {
 		DEFINE_RES_MEM(0x40000000, SZ_8K),
 		{ .flags = IORESOURCE_IRQ },
@@ -213,30 +265,40 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	};
 	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 (!smc91x_res || !sa1111_res) {
+	if (!nep_res || !smc91x_res || !sa1111_res) {
 		ret = -ENXIO;
 		goto err_alloc;
 	}
 
-	if (WHOAMI != 0x11) {
-		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
-			 WHOAMI);
-		ret = -ENODEV;
-		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",
@@ -270,6 +332,7 @@ static int __devinit neponset_probe(struct platform_device *dev)
 
 	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);
 
@@ -277,7 +340,7 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	sa1110_mb_disable();
 
 	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
-	NCR_0 = NCR_GP01_OFF;
+	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;
@@ -295,6 +358,9 @@ static int __devinit neponset_probe(struct platform_device *dev)
 	return 0;
 
  err_irq_alloc:
+ err_id:
+	iounmap(d->base);
+ err_ioremap:
 	kfree(d);
  err_alloc:
 	return ret;
@@ -311,6 +377,8 @@ static int __devexit neponset_remove(struct platform_device *dev)
 		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;
@@ -321,8 +389,8 @@ static int neponset_suspend(struct device *dev)
 {
 	struct neponset_drvdata *d = dev_get_drvdata(dev);
 
-	d->ncr0 = NCR_0;
-	d->mdm_ctl_0 = MDM_CTL_0;
+	d->ncr0 = readb_relaxed(d->base + NCR_0);
+	d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0);
 
 	return 0;
 }
@@ -331,8 +399,8 @@ static int neponset_resume(struct device *dev)
 {
 	struct neponset_drvdata *d = dev_get_drvdata(dev);
 
-	NCR_0 = d->ncr0;
-	MDM_CTL_0 = d->mdm_ctl_0;
+	writeb_relaxed(d->ncr0, d->base + NCR_0);
+	writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0);
 
 	return 0;
 }

From fbae0f8912dc12b284433c05417ea76311205bbf Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 11:23:33 +0000
Subject: [PATCH 031/115] ARM: sa11x0: neponset: don't static map neponset
 registers

Now that we ioremap() the neponset register space, there's no need
to static map the neponset registers.  Get rid of this static mapping.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/neponset.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 3c0d4b837adb..7ffa631eede4 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -434,12 +434,7 @@ static int __init neponset_init(void)
 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 */
+	{	/* SA-1111 */
 		.virtual	=  0xf4000000,
 		.pfn		= __phys_to_pfn(0x40000000),
 		.length		= SZ_1M,

From 29c140b623ce2c55131c6d1c26a2f3e455723b81 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 3 Feb 2012 19:03:31 +0000
Subject: [PATCH 032/115] ARM: sa1111: fix memory request/grant setup on PM
 events

We weren't re-enabling the memory request/grant signals on resume,
causing DMA devices on the sa1111 to fail.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 61691cdbdcf2..c7bed309b3aa 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -87,7 +87,8 @@
 #define IRQ_S0_BVD1_STSCHG	(53)
 #define IRQ_S1_BVD1_STSCHG	(54)
 
-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
@@ -926,6 +927,10 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
 
 	spin_unlock_irqrestore(&sachip->lock, flags);
 
+#ifdef CONFIG_ARCH_SA1100
+	sa1110_mb_disable();
+#endif
+
 	return 0;
 }
 
@@ -966,6 +971,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!

From a22db0f38243f68957c89b1b9689a2064507bed6 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 3 Feb 2012 19:05:13 +0000
Subject: [PATCH 033/115] ARM: sa1111: fix PWM state on suspend

We should not write to the SA1111 registers after setting the SLEEP
bit.  Moreover, the manual says that the PWM registers should be
disabled before we enter sleep.  So, move the clearing of these
registers earlier in the suspend sequence.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index c7bed309b3aa..f0d9faadcc3f 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -905,6 +905,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);
@@ -920,8 +923,6 @@ 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);
 

From 4d5d11285c78691efb17148dfc3d56642bee6204 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 16:09:22 +0000
Subject: [PATCH 034/115] ARM: sa1111: add sa1111 core driver .owner
 initializer

Add an initializer for the struct device_driver .owner member.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index f0d9faadcc3f..957f6e3c4280 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -1064,6 +1064,7 @@ static struct platform_driver sa1111_device_driver = {
 	.resume		= sa1111_resume,
 	.driver		= {
 		.name	= "sa1111",
+		.owner	= THIS_MODULE,
 	},
 };
 

From 1ebcd7654e4e391a36945c937c125995c737c446 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 11:19:48 +0000
Subject: [PATCH 035/115] ARM: sa1111: add .owner initializer to sa1111 driver
 structures

Add a .owner initializer to the sa1111 driver structures to allow
allow the modules to be associated with their driver structures.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/input/serio/sa1111ps2.c | 1 +
 drivers/usb/host/ohci-sa1111.c  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 44fc8b4bcd81..40ec545fbd40 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -330,6 +330,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,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4bde4f9821ba..7d2aa62ea613 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -262,6 +262,7 @@ static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *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,

From f03ecaa0aa3a3b74b9b9e8341cf7919516c902d5 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 00:09:22 +0000
Subject: [PATCH 036/115] ARM: sa1111: finish "allow cascaded IRQs to be used
 by platforms"

Commit 19851c58e680 (sa1111: allow cascaded IRQs to be used by platforms)
moved the IRQ definitions to the .c file, and added an irq_base member
to the private data structure.

The inerrupt demultiplexer uses irq_base, but the interrupt setup code
does not.  Also, although the commit adds a private data structure to
pass this data, it isn't even referenced, resulting in irq_base being
zero.

We also copied the IRQ numbers from the device info array into the actual
devices, resulting in wrong interrupt numbers passed to the sub-devices.

The net effect of this is that we always overwrite IRQs 0-54, even if
they are allocated elsewhere in the system.

Add the code necessary to setup the private irq_base, and use it in the
IRQ setup code.  Make the SA-1111 probe fail with -EINVAL if there is no
platform data provided.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 957f6e3c4280..d3a8f5e26487 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -438,7 +438,7 @@ static struct irq_chip sa1111_high_chip = {
 static void sa1111_setup_irq(struct sa1111 *sachip)
 {
 	void __iomem *irqbase = sachip->base + SA1111_INTC;
-	unsigned int irq;
+	unsigned i, irq;
 
 	/*
 	 * We're guaranteed that this region hasn't been taken.
@@ -464,14 +464,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);
@@ -625,6 +627,7 @@ 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);
@@ -645,7 +648,9 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 	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];
 
 	ret = request_resource(parent, &dev->res);
 	if (ret) {
@@ -699,16 +704,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;
@@ -730,6 +740,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 
 	sachip->phys = mem->start;
 	sachip->irq = irq;
+	sachip->irq_base = pd->irq_base;
 
 	/*
 	 * Map the whole region.  This also maps the

From 36d312130228504a223de44739c807b0353248c1 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 24 Jan 2012 21:25:20 +0000
Subject: [PATCH 037/115] ARM: sa1111: implement support for sparse IRQs

Implement the necessary allocation/freeing functionality to support
sparse IRQs with the SA-1111 device.  On non-sparse IRQ platforms,
this allows us to dynamically allocate from within the available IRQ
number space.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 43 ++++++++++++++++++++++++++++++----------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index d3a8f5e26487..b64a3360c8c2 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,6 +86,7 @@
 #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 sa1110_mb_enable(void);
 extern void sa1110_mb_disable(void);
@@ -435,16 +436,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 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);
@@ -486,6 +499,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;
 }
 
 /*
@@ -740,7 +758,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 
 	sachip->phys = mem->start;
 	sachip->irq = irq;
-	sachip->irq_base = pd->irq_base;
 
 	/*
 	 * Map the whole region.  This also maps the
@@ -771,6 +788,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;
@@ -801,13 +828,6 @@ __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;
@@ -858,6 +878,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);
 	}

From 6bd72f0562142ddae26a052cfc4e578ad6953d06 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 11:01:18 +0000
Subject: [PATCH 038/115] ARM: sa1111: add shutdown hook to sa1111_driver
 structure

Add a shutdown hook to the sa1111_driver structure to allow drivers
to be notified of system reboots and shutdowns.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c               | 9 +++++++++
 arch/arm/include/asm/hardware/sa1111.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index b64a3360c8c2..b0f93628dcd7 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -1348,6 +1348,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);
@@ -1377,6 +1385,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);
 
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 92ed254c175b..29e320f6f85f 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -548,6 +548,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)

From ae99ddbc976572194e8a68cb9ca1e27805ce30c7 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 13:25:47 +0000
Subject: [PATCH 039/115] ARM: sa1111: add platform enable/disable functions

Add platform hooks to be called when individual sa1111 devices are
enabled and disabled.  This will allow us to move some platform
specifics out of the individual drivers.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c               | 22 +++++++++++++++++-----
 arch/arm/include/asm/hardware/sa1111.h |  8 ++++++--
 drivers/input/serio/sa1111ps2.c        |  6 +++++-
 drivers/pcmcia/sa1111_generic.c        | 11 +++++++++--
 drivers/usb/host/ohci-sa1111.c         | 19 ++++++++++++++-----
 5 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index b0f93628dcd7..1366e82e6707 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -106,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
@@ -756,6 +757,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;
 
@@ -1282,16 +1284,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);
 
@@ -1309,6 +1318,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);
 
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 29e320f6f85f..d54d781021c8 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -556,9 +556,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 *);
@@ -581,6 +582,9 @@ 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 */
+	void	*data;
+	int	(*enable)(void *, unsigned);
+	void	(*disable)(void *, unsigned);
 };
 
 #endif  /* _ASM_ARCH_SA1111 */
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 40ec545fbd40..ad7d23b5c6fe 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -124,13 +124,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 +143,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;
 	}
 
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 27f2fe3b7fb4..0735c3e6a8b0 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -163,12 +163,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;
 
@@ -212,6 +218,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
 	}
 
 	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 7d2aa62ea613..f61f4f90529e 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -27,9 +27,10 @@ extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
-static void sa1111_start_hc(struct sa1111_dev *dev)
+static int sa1111_start_hc(struct sa1111_dev *dev)
 {
 	unsigned int usb_rst = 0;
+	int ret;
 
 	printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
 	       __FILE__);
@@ -57,9 +58,13 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
 	 * 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 + SA1111_USB_RESET);
+	}
+
+	return ret;
 }
 
 static void sa1111_stop_hc(struct sa1111_dev *dev)
@@ -140,7 +145,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
 	}
 	hcd->regs = dev->mapbase;
 
-	sa1111_start_hc(dev);
+	ret = sa1111_start_hc(dev);
+	if (ret)
+		goto err2;
+
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
 	retval = usb_add_hcd(hcd, dev->irq[1], 0);
@@ -148,6 +156,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
 		return retval;
 
 	sa1111_stop_hc(dev);
+ err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
 	usb_put_hcd(hcd);

From 3259701cc2969ae16a0018d7e3a89f327fa23a6e Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 13:28:35 +0000
Subject: [PATCH 040/115] ARM: sa11x0: badge4: move board specific ohci
 initialization to badge4.c

Move the handling of the 5v supply into badge4.c, removing this board
specific detail from the sa1111 ohci driver.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/badge4.c  | 15 +++++++++++++++
 drivers/usb/host/ohci-sa1111.c | 14 --------------
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b07a2c024cb7..d84924993bad 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -51,8 +51,23 @@ static struct resource sa1111_resources[] = {
 	},
 };
 
+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,
+	.enable		= badge4_sa1111_enable,
+	.disable	= badge4_sa1111_disable,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index f61f4f90529e..48300080433c 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -16,7 +16,6 @@
 #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
@@ -35,12 +34,6 @@ static int sa1111_start_hc(struct sa1111_dev *dev)
 	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() ||
@@ -84,13 +77,6 @@ static void sa1111_stop_hc(struct sa1111_dev *dev)
 	 * 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
 }
 
 

From e5c0fc4185c551c270868dcb6573604db2bc3171 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Wed, 25 Jan 2012 10:42:52 +0000
Subject: [PATCH 041/115] ARM: sa1111: change devid to be a bitmask

Change the sa1111 device id to be a bitmask.  This allows us to
specify the actual device, while allowing a single driver to bind
to both PS2 devices.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c               | 12 ++++++------
 arch/arm/include/asm/hardware/sa1111.h | 20 +++++++++++---------
 2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 1366e82e6707..4bdf1bb283dc 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -158,7 +158,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
@@ -167,7 +167,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
@@ -835,12 +835,12 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 	has_devs = ~0;
 	if (machine_is_assabet() || machine_is_jornada720() ||
 	    machine_is_badge4())
-		has_devs &= ~(1 << 4);
+		has_devs &= ~SA1111_DEVID_PS2_MSE;
 	else
-		has_devs &= ~(1 << 1);
+		has_devs &= ~SA1111_DEVID_SAC;
 
 	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;
@@ -1335,7 +1335,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)
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index d54d781021c8..37ad29d482f4 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -516,15 +516,17 @@
 
 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;

From 15877e9c8a12ced38ac31d8bf4f93f3634fbea3f Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 12:04:05 +0000
Subject: [PATCH 042/115] NET: sa11x0-ir: fix documentation bug

Spell the module parameter correctly in comments.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index da2705061a60..751f2a9f283b 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -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>

From 22f0bf96de1506081a8b18ad3e0d04d5add70a4a Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 13:55:23 +0000
Subject: [PATCH 043/115] NET: sa11x0-ir: handle DMA mapping errors properly

Handle DMA mapping errors in the rx skb allocation and tx paths.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 751f2a9f283b..84fecce078f6 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -82,7 +82,6 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 		return 0;
 
 	si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
-
 	if (!si->rxskb) {
 		printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
 		return -ENOMEM;
@@ -97,6 +96,11 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 	si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
 					HPSIR_MAX_RXLEN,
 					DMA_FROM_DEVICE);
+	if (dma_mapping_error(si->dev, si->rxbuf_dma)) {
+		dev_kfree_skb_any(si->rxskb);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -518,7 +522,8 @@ 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,
@@ -701,6 +706,13 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 		si->txskb = skb;
 		si->txbuf_dma = dma_map_single(si->dev, skb->data,
 					 skb->len, DMA_TO_DEVICE);
+		if (dma_mapping_error(si->dev, si->txbuf_dma)) {
+			si->txskb = NULL;
+			netif_wake_queue(dev);
+			dev->stats.tx_dropped++;
+			dev_kfree_skb(skb);
+			return NETDEV_TX_OK;
+		}
 
 		sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
 

From d32386086b4a250bd71125f8d760cfffada0e422 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 12:07:24 +0000
Subject: [PATCH 044/115] NET: sa11x0-ir: set netdev's parent struct device

Add the missing SET_NETDEV_DEV() call to set the parent device
correctly for this network interface.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 84fecce078f6..149a3b4aaecc 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -919,6 +919,8 @@ 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;

From e556fdbde38f68d87f689473b112cc65ddacd6a4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 12:02:17 +0000
Subject: [PATCH 045/115] NET: sa11x0-ir: obtain interrupt number from platform
 resources

Convert the sa11x0-ir driver to obtain its interrupt number from the
platform device resources, rather than via the asm/irq.h include.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 149a3b4aaecc..2f5bf0bc8458 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -35,7 +35,6 @@
 #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>
@@ -900,11 +899,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;
@@ -936,7 +939,7 @@ static int sa1100_irda_probe(struct platform_device *pdev)
 		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);
 

From 885767ca4ce0800c5d02eb66cc10a0494b7bf312 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 12:53:22 +0000
Subject: [PATCH 046/115] NET: sa11x0-ir: containerize DMA data

Both the transmit and receive DMA store identical data: the skb, dma
address, and the dma registers.  Move this data into its own data
structure.  The following replacements were used:

	rxskb -> dma_rx.skb
	rxbuf_dma -> dma_rx.dma
	rxdma -> dma_rx.regs

	txskb -> dma_tx.skb
	txbuf_dma -> dma_tx.dma
	txdma -> dma_tx.regs

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 94 ++++++++++++++++++------------------
 1 file changed, 48 insertions(+), 46 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 2f5bf0bc8458..adb7fea78c2d 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -43,6 +43,12 @@ static int power_level = 3;
 static int tx_lpm;
 static int max_rate = 4000000;
 
+struct sa1100_buf {
+	struct sk_buff		*skb;
+	dma_addr_t		dma;
+	dma_regs_t		*regs;
+};
+
 struct sa1100_irda {
 	unsigned char		hscr0;
 	unsigned char		utcr4;
@@ -52,12 +58,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;
@@ -77,11 +79,11 @@ struct sa1100_irda {
  */
 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;
 	}
@@ -90,13 +92,13 @@ 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);
 
-	si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
+	si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
 					HPSIR_MAX_RXLEN,
 					DMA_FROM_DEVICE);
-	if (dma_mapping_error(si->dev, si->rxbuf_dma)) {
-		dev_kfree_skb_any(si->rxskb);
+	if (dma_mapping_error(si->dev, si->dma_rx.dma)) {
+		dev_kfree_skb_any(si->dma_rx.skb);
 		return -ENOMEM;
 	}
 
@@ -109,7 +111,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;
 	}
@@ -122,8 +124,8 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 	/*
 	 * Enable the DMA, receiver and receive interrupt.
 	 */
-	sa1100_clear_dma(si->rxdma);
-	sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
+	sa1100_clear_dma(si->dma_rx.regs);
+	sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN);
 	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
 }
 
@@ -144,7 +146,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 		 * Stop the receive DMA.
 		 */
 		if (IS_FIR(si))
-			sa1100_stop_dma(si->rxdma);
+			sa1100_stop_dma(si->dma_rx.regs);
 
 		local_irq_save(flags);
 
@@ -280,8 +282,8 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si)
 	/*
 	 * Stop all DMA activity.
 	 */
-	sa1100_stop_dma(si->rxdma);
-	sa1100_stop_dma(si->txdma);
+	sa1100_stop_dma(si->dma_rx.regs);
+	sa1100_stop_dma(si->dma_tx.regs);
 
 	/* Disable the port. */
 	Ser2UTCR3 = 0;
@@ -460,7 +462,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
 
 static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
 {
-	struct sk_buff *skb = si->rxskb;
+	struct sk_buff *skb = si->dma_rx.skb;
 	dma_addr_t dma_addr;
 	unsigned int len, stat, data;
 
@@ -472,11 +474,11 @@ 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;
+	dma_addr = sa1100_get_dma_pos(si->dma_rx.regs);
+	len = dma_addr - si->dma_rx.dma;
 	if (len > HPSIR_MAX_RXLEN)
 		len = HPSIR_MAX_RXLEN;
-	dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
+	dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE);
 
 	do {
 		/*
@@ -504,7 +506,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;
@@ -524,7 +526,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
 		 * Remap the buffer - it was previously mapped, and we
 		 * hope that this succeeds.
 		 */
-		si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
+		si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
 						HPSIR_MAX_RXLEN,
 						DMA_FROM_DEVICE);
 	}
@@ -543,7 +545,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
 	/*
 	 * Stop RX DMA
 	 */
-	sa1100_stop_dma(si->rxdma);
+	sa1100_stop_dma(si->dma_rx.regs);
 
 	/*
 	 * Framing error - we throw away the packet completely.
@@ -600,9 +602,9 @@ static void sa1100_irda_txdma_irq(void *id)
 {
 	struct net_device *dev = id;
 	struct sa1100_irda *si = netdev_priv(dev);
-	struct sk_buff *skb = si->txskb;
+	struct sk_buff *skb = si->dma_tx.skb;
 
-	si->txskb = NULL;
+	si->dma_tx.skb = NULL;
 
 	/*
 	 * Wait for the transmission to complete.  Unfortunately,
@@ -620,7 +622,7 @@ static void sa1100_irda_txdma_irq(void *id)
 
 	/*
 	 * Do we need to change speed?  Note that we're lazy
-	 * here - we don't free the old rxskb.  We don't need
+	 * here - we don't free the old dma_rx.skb.  We don't need
 	 * to allocate a buffer either.
 	 */
 	if (si->newspeed) {
@@ -638,7 +640,7 @@ static void sa1100_irda_txdma_irq(void *id)
 	 * Account and free the packet.
 	 */
 	if (skb) {
-		dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
+		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE);
 		dev->stats.tx_packets ++;
 		dev->stats.tx_bytes += skb->len;
 		dev_kfree_skb_irq(skb);
@@ -698,22 +700,22 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 		/*
 		 * We must not be transmitting...
 		 */
-		BUG_ON(si->txskb);
+		BUG_ON(si->dma_tx.skb);
 
 		netif_stop_queue(dev);
 
-		si->txskb = skb;
-		si->txbuf_dma = dma_map_single(si->dev, skb->data,
+		si->dma_tx.skb = skb;
+		si->dma_tx.dma = dma_map_single(si->dev, skb->data,
 					 skb->len, DMA_TO_DEVICE);
-		if (dma_mapping_error(si->dev, si->txbuf_dma)) {
-			si->txskb = NULL;
+		if (dma_mapping_error(si->dev, si->dma_tx.dma)) {
+			si->dma_tx.skb = NULL;
 			netif_wake_queue(dev);
 			dev->stats.tx_dropped++;
 			dev_kfree_skb(skb);
 			return NETDEV_TX_OK;
 		}
 
-		sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
+		sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len);
 
 		/*
 		 * If we have a mean turn-around time, impose the specified
@@ -785,12 +787,12 @@ static int sa1100_irda_start(struct net_device *dev)
 		goto err_irq;
 
 	err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
-				 NULL, NULL, &si->rxdma);
+				 NULL, NULL, &si->dma_rx.regs);
 	if (err)
 		goto err_rx_dma;
 
 	err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
-				 sa1100_irda_txdma_irq, dev, &si->txdma);
+				 sa1100_irda_txdma_irq, dev, &si->dma_tx.regs);
 	if (err)
 		goto err_tx_dma;
 
@@ -827,9 +829,9 @@ err_irlap:
 	si->open = 0;
 	sa1100_irda_shutdown(si);
 err_startup:
-	sa1100_free_dma(si->txdma);
+	sa1100_free_dma(si->dma_tx.regs);
 err_tx_dma:
-	sa1100_free_dma(si->rxdma);
+	sa1100_free_dma(si->dma_rx.regs);
 err_rx_dma:
 	free_irq(dev->irq, dev);
 err_irq:
@@ -847,11 +849,11 @@ static int sa1100_irda_stop(struct net_device *dev)
 	 * If we have been doing DMA receive, make sure we
 	 * tidy that up cleanly.
 	 */
-	if (si->rxskb) {
-		dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
+	if (si->dma_rx.skb) {
+		dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN,
 				 DMA_FROM_DEVICE);
-		dev_kfree_skb(si->rxskb);
-		si->rxskb = NULL;
+		dev_kfree_skb(si->dma_rx.skb);
+		si->dma_rx.skb = NULL;
 	}
 
 	/* Stop IrLAP */
@@ -866,8 +868,8 @@ static int sa1100_irda_stop(struct net_device *dev)
 	/*
 	 * Free resources
 	 */
-	sa1100_free_dma(si->txdma);
-	sa1100_free_dma(si->rxdma);
+	sa1100_free_dma(si->dma_tx.regs);
+	sa1100_free_dma(si->dma_rx.regs);
 	free_irq(dev->irq, dev);
 
 	sa1100_set_power(si, 0);

From ba84525bd9015e7dd20f7c97a2a96b0a238b0223 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 15:38:15 +0000
Subject: [PATCH 047/115] NET: sa11x0-ir: fix leak of tx skb

Ensure that we unmap and free a pending transmit skb when the interface
is stopped.  We rearrange the code a little bit to give all places a
similar layout when freeing the skb in both the completion and interface
stop paths - this gives some consistency to the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index adb7fea78c2d..9dc564830c9d 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -602,9 +602,7 @@ static void sa1100_irda_txdma_irq(void *id)
 {
 	struct net_device *dev = id;
 	struct sa1100_irda *si = netdev_priv(dev);
-	struct sk_buff *skb = si->dma_tx.skb;
-
-	si->dma_tx.skb = NULL;
+	struct sk_buff *skb;
 
 	/*
 	 * Wait for the transmission to complete.  Unfortunately,
@@ -636,14 +634,15 @@ static void sa1100_irda_txdma_irq(void *id)
 	 */
 	sa1100_irda_rx_dma_start(si);
 
-	/*
-	 * Account and free the packet.
-	 */
+	/* Account and free the packet. */
+	skb = si->dma_tx.skb;
 	if (skb) {
-		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE);
+		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len,
+				 DMA_TO_DEVICE);
 		dev->stats.tx_packets ++;
 		dev->stats.tx_bytes += skb->len;
 		dev_kfree_skb_irq(skb);
+		si->dma_tx.skb = NULL;
 	}
 
 	/*
@@ -841,21 +840,31 @@ err_irq:
 static int sa1100_irda_stop(struct net_device *dev)
 {
 	struct sa1100_irda *si = netdev_priv(dev);
+	struct sk_buff *skb;
 
 	disable_irq(dev->irq);
 	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->dma_rx.skb) {
+	skb = si->dma_rx.skb;
+	if (skb) {
 		dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN,
 				 DMA_FROM_DEVICE);
-		dev_kfree_skb(si->dma_rx.skb);
+		dev_kfree_skb(skb);
 		si->dma_rx.skb = NULL;
 	}
 
+	skb = si->dma_tx.skb;
+	if (skb) {
+		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len,
+				 DMA_TO_DEVICE);
+		dev_kfree_skb(skb);
+		si->dma_tx.skb = NULL;
+	}
+
 	/* Stop IrLAP */
 	if (si->irlap) {
 		irlap_close(si->irlap);

From cbe1d24fb70751ef14801338aa945e807ba63a90 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 16:40:07 +0000
Subject: [PATCH 048/115] NET: sa11x0-ir: move
 sa1100_irda_{startup,shutdown,suspend,resume}

Places these functions in better locations in the file, near where
they are used.  This saves some tiresome paging up/down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 262 +++++++++++++++++------------------
 1 file changed, 131 insertions(+), 131 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 9dc564830c9d..32ac4a44ce76 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -230,137 +230,6 @@ sa1100_set_power(struct sa1100_irda *si, unsigned int state)
 	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.
-	 */
-	sa1100_stop_dma(si->dma_rx.regs);
-	sa1100_stop_dma(si->dma_tx.regs);
-
-	/* Disable the port. */
-	Ser2UTCR3 = 0;
-	Ser2HSCR0 = 0;
-
-	if (si->pdata->shutdown)
-		si->pdata->shutdown(si->dev);
-}
-
-#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
-
 /*
  * HP-SIR format interrupt service routines.
  */
@@ -774,6 +643,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.
+	 */
+	sa1100_stop_dma(si->dma_rx.regs);
+	sa1100_stop_dma(si->dma_tx.regs);
+
+	/* 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);
@@ -1024,6 +956,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,

From 0e888ee31566c3f5071474ddd68457a7ad2ae5ac Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 16:30:44 +0000
Subject: [PATCH 049/115] NET: sa11x0-ir: factor out speed checks

Whenever we complete a transmit, we always check for a speed change.
This check was open coded in several places.  Provide a helper
function to do this instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 32ac4a44ce76..bfae34fa7a9e 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -70,6 +70,8 @@ struct sa1100_irda {
 	iobuff_t		rx_buff;
 };
 
+static int sa1100_irda_set_speed(struct sa1100_irda *, int);
+
 #define IS_FIR(si)		((si)->speed >= 4000000)
 
 #define HPSIR_MAX_RXLEN		2047
@@ -129,6 +131,14 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
 }
 
+static void sa1100_irda_check_speed(struct sa1100_irda *si)
+{
+	if (si->newspeed) {
+		sa1100_irda_set_speed(si, si->newspeed);
+		si->newspeed = 0;
+	}
+}
+
 /*
  * Set the IrDA communications speed.
  */
@@ -318,10 +328,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
 			Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
 			Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
 
-			if (si->newspeed) {
-				sa1100_irda_set_speed(si, si->newspeed);
-				si->newspeed = 0;
-			}
+			sa1100_irda_check_speed(si);
 
 			/* I'm hungry! */
 			netif_wake_queue(dev);
@@ -492,10 +499,7 @@ static void sa1100_irda_txdma_irq(void *id)
 	 * here - we don't free the old dma_rx.skb.  We don't need
 	 * to allocate a buffer either.
 	 */
-	if (si->newspeed) {
-		sa1100_irda_set_speed(si, si->newspeed);
-		si->newspeed = 0;
-	}
+	sa1100_irda_check_speed(si);
 
 	/*
 	 * Start reception.  This disables the transmitter for
@@ -538,10 +542,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 	 * 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;
 	}

From 3d26db137ac3169623a132ea310d26af6a48bf88 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 16:16:39 +0000
Subject: [PATCH 050/115] NET: sa11x0-ir: split SIR and FIR tx functions

Split the SIR and FIR transmit functions, as they behave differently.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 118 ++++++++++++++++++++---------------
 1 file changed, 66 insertions(+), 52 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index bfae34fa7a9e..8b8cf4152604 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -68,6 +68,8 @@ struct sa1100_irda {
 
 	iobuff_t		tx_buff;
 	iobuff_t		rx_buff;
+
+	int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
 };
 
 static int sa1100_irda_set_speed(struct sa1100_irda *, int);
@@ -139,6 +141,63 @@ static void sa1100_irda_check_speed(struct sa1100_irda *si)
 	}
 }
 
+/*
+ * HP-SIR format support.
+ */
+static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
+	struct sa1100_irda *si)
+{
+	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 characters received.
+	 */
+	Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
+
+	dev_kfree_skb(skb);
+
+	return NETDEV_TX_OK;
+}
+
+/*
+ * FIR format support.
+ */
+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;
+	si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len,
+					DMA_TO_DEVICE);
+	if (dma_mapping_error(si->dev, si->dma_tx.dma)) {
+		si->dma_tx.skb = NULL;
+		netif_wake_queue(dev);
+		dev->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	sa1100_start_dma(si->dma_tx.regs, si->dma_tx.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);
+
+	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
+
+	return NETDEV_TX_OK;
+}
+
+
 /*
  * Set the IrDA communications speed.
  */
@@ -176,6 +235,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 			si->pdata->set_speed(si->dev, speed);
 
 		si->speed = speed;
+		si->tx_start = sa1100_irda_sir_tx_start;
 
 		local_irq_restore(flags);
 		ret = 0;
@@ -191,6 +251,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 		Ser2UTCR3 = 0;
 
 		si->speed = speed;
+		si->tx_start = sa1100_irda_fir_tx_start;
 
 		if (si->pdata->set_speed)
 			si->pdata->set_speed(si->dev, speed);
@@ -538,66 +599,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) {
 		sa1100_irda_check_speed(si);
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
 
-	if (!IS_FIR(si)) {
-		netif_stop_queue(dev);
+	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);
+	/* We must not already have a skb to transmit... */
+	BUG_ON(si->dma_tx.skb);
 
-		/*
-		 * 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->dma_tx.skb);
-
-		netif_stop_queue(dev);
-
-		si->dma_tx.skb = skb;
-		si->dma_tx.dma = dma_map_single(si->dev, skb->data,
-					 skb->len, DMA_TO_DEVICE);
-		if (dma_mapping_error(si->dev, si->dma_tx.dma)) {
-			si->dma_tx.skb = NULL;
-			netif_wake_queue(dev);
-			dev->stats.tx_dropped++;
-			dev_kfree_skb(skb);
-			return NETDEV_TX_OK;
-		}
-
-		sa1100_start_dma(si->dma_tx.regs, si->dma_tx.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);
-
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
-	}
-
-	return NETDEV_TX_OK;
+	return si->tx_start(skb, dev, si);
 }
 
 static int

From 374f77390ca99b401ee121616524ed32c54d5ad6 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 16:26:15 +0000
Subject: [PATCH 051/115] NET: sa11x0-ir: indirect handling of SIR and FIR
 interrupts

Use the same method for doing this as we do for the tx_start functions.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 50 +++++++++++++++++-------------------
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 8b8cf4152604..32dee3322679 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -70,6 +70,7 @@ struct sa1100_irda {
 	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);
@@ -197,6 +198,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	return NETDEV_TX_OK;
 }
 
+static irqreturn_t sa1100_irda_sir_irq(struct net_device *, struct sa1100_irda *);
+static irqreturn_t sa1100_irda_fir_irq(struct net_device *, struct sa1100_irda *);
 
 /*
  * Set the IrDA communications speed.
@@ -236,6 +239,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 
 		si->speed = speed;
 		si->tx_start = sa1100_irda_sir_tx_start;
+		si->irq = sa1100_irda_sir_irq;
 
 		local_irq_restore(flags);
 		ret = 0;
@@ -252,6 +256,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 
 		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);
@@ -304,9 +309,8 @@ sa1100_set_power(struct sa1100_irda *si, unsigned int state)
 /*
  * 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;
@@ -395,6 +399,8 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
 			netif_wake_queue(dev);
 		}
 	}
+
+	return IRQ_HANDLED;
 }
 
 static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
@@ -475,10 +481,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
  *
  * No matter what, 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
 	 */
@@ -520,16 +524,16 @@ 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)
 {
 	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;
+	struct sa1100_irda *si = netdev_priv(dev);
+
+	return si->irq(dev, si);
 }
 
 /*
@@ -728,10 +732,6 @@ 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->dma_rx.regs);
 	if (err)
@@ -742,11 +742,6 @@ static int sa1100_irda_start(struct net_device *dev)
 	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.
 	 */
@@ -762,15 +757,21 @@ 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);
@@ -779,8 +780,6 @@ err_startup:
 err_tx_dma:
 	sa1100_free_dma(si->dma_rx.regs);
 err_rx_dma:
-	free_irq(dev->irq, dev);
-err_irq:
 	return err;
 }
 
@@ -789,7 +788,9 @@ 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);
 
 	/*
@@ -818,9 +819,6 @@ static int sa1100_irda_stop(struct net_device *dev)
 		si->irlap = NULL;
 	}
 
-	netif_stop_queue(dev);
-	si->open = 0;
-
 	/*
 	 * Free resources
 	 */

From a6b2ea66d630ad0687a1ac25d5a6afb282bd364a Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 17:10:01 +0000
Subject: [PATCH 052/115] NET: sa11x0-ir: move SIR and FIR interrupt support

Move the interrupt handlers to the SIR and FIR sections of the file.
This improves the localization of the protocol handlers.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 440 +++++++++++++++++------------------
 1 file changed, 216 insertions(+), 224 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 32dee3322679..61b42d1265b4 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -164,6 +164,100 @@ static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	return NETDEV_TX_OK;
 }
 
+static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
+{
+	int status;
+
+	status = Ser2UTSR0;
+
+	/*
+	 * Deal with any receive errors first.  The bytes in error may be
+	 * the only bytes in the receive FIFO, so we do this first.
+	 */
+	while (status & UTSR0_EIF) {
+		int stat, data;
+
+		stat = Ser2UTSR1;
+		data = Ser2UTDR;
+
+		if (stat & (UTSR1_FRE | UTSR1_ROR)) {
+			dev->stats.rx_errors++;
+			if (stat & UTSR1_FRE)
+				dev->stats.rx_frame_errors++;
+			if (stat & UTSR1_ROR)
+				dev->stats.rx_fifo_errors++;
+		} else
+			async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
+
+		status = Ser2UTSR0;
+	}
+
+	/*
+	 * We must clear certain bits.
+	 */
+	Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+	if (status & UTSR0_RFS) {
+		/*
+		 * There are at least 4 bytes in the FIFO.  Read 3 bytes
+		 * and leave the rest to the block below.
+		 */
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+	}
+
+	if (status & (UTSR0_RFS | UTSR0_RID)) {
+		/*
+		 * Fifo contains more than 1 character.
+		 */
+		do {
+			async_unwrap_char(dev, &dev->stats, &si->rx_buff,
+					  Ser2UTDR);
+		} while (Ser2UTSR1 & UTSR1_RNE);
+
+	}
+
+	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);
+
+		if (si->tx_buff.len == 0) {
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += si->tx_buff.data -
+					      si->tx_buff.head;
+
+			/*
+			 * We need to ensure that the transmitter has
+			 * finished.
+			 */
+			do
+				rmb();
+			while (Ser2UTSR1 & UTSR1_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;
+
+			sa1100_irda_check_speed(si);
+
+			/* I'm hungry! */
+			netif_wake_queue(dev);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 /*
  * FIR format support.
  */
@@ -198,8 +292,128 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	return NETDEV_TX_OK;
 }
 
-static irqreturn_t sa1100_irda_sir_irq(struct net_device *, struct sa1100_irda *);
-static irqreturn_t sa1100_irda_fir_irq(struct net_device *, struct sa1100_irda *);
+static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
+{
+	struct sk_buff *skb = si->dma_rx.skb;
+	dma_addr_t dma_addr;
+	unsigned int len, stat, data;
+
+	if (!skb) {
+		printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
+		return;
+	}
+
+	/*
+	 * Get the current data position.
+	 */
+	dma_addr = sa1100_get_dma_pos(si->dma_rx.regs);
+	len = dma_addr - si->dma_rx.dma;
+	if (len > HPSIR_MAX_RXLEN)
+		len = HPSIR_MAX_RXLEN;
+	dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE);
+
+	do {
+		/*
+		 * Read Status, and then Data.
+		 */
+		stat = Ser2HSSR1;
+		rmb();
+		data = Ser2HSDR;
+
+		if (stat & (HSSR1_CRE | HSSR1_ROR)) {
+			dev->stats.rx_errors++;
+			if (stat & HSSR1_CRE)
+				dev->stats.rx_crc_errors++;
+			if (stat & HSSR1_ROR)
+				dev->stats.rx_frame_errors++;
+		} else
+			skb->data[len++] = data;
+
+		/*
+		 * If we hit the end of frame, there's
+		 * no point in continuing.
+		 */
+		if (stat & HSSR1_EOF)
+			break;
+	} while (Ser2HSSR0 & HSSR0_EIF);
+
+	if (stat & HSSR1_EOF) {
+		si->dma_rx.skb = NULL;
+
+		skb_put(skb, len);
+		skb->dev = dev;
+		skb_reset_mac_header(skb);
+		skb->protocol = htons(ETH_P_IRDA);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += len;
+
+		/*
+		 * Before we pass the buffer up, allocate a new one.
+		 */
+		sa1100_irda_rx_alloc(si);
+
+		netif_rx(skb);
+	} else {
+		/*
+		 * Remap the buffer - it was previously mapped, and we
+		 * hope that this succeeds.
+		 */
+		si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
+						HPSIR_MAX_RXLEN,
+						DMA_FROM_DEVICE);
+	}
+}
+
+/*
+ * 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 irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
+{
+	/*
+	 * Stop RX DMA
+	 */
+	sa1100_stop_dma(si->dma_rx.regs);
+
+	/*
+	 * Framing error - we throw away the packet completely.
+	 * Clearing RXE flushes the error conditions and data
+	 * from the fifo.
+	 */
+	if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
+		dev->stats.rx_errors++;
+
+		if (Ser2HSSR0 & HSSR0_FRE)
+			dev->stats.rx_frame_errors++;
+
+		/*
+		 * Clear out the DMA...
+		 */
+		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+
+		/*
+		 * Clear selected status bits now, so we
+		 * don't miss them next time around.
+		 */
+		Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;
+	}
+
+	/*
+	 * Deal with any receive errors.  The any of the lowest
+	 * 8 bytes in the FIFO may contain an error.  We must read
+	 * them one by one.  The "error" could even be the end of
+	 * packet!
+	 */
+	if (Ser2HSSR0 & HSSR0_EIF)
+		sa1100_irda_fir_error(si, dev);
+
+	/*
+	 * No matter what happens, we must restart reception.
+	 */
+	sa1100_irda_rx_dma_start(si);
+
+	return IRQ_HANDLED;
+}
 
 /*
  * Set the IrDA communications speed.
@@ -306,228 +520,6 @@ sa1100_set_power(struct sa1100_irda *si, unsigned int state)
 	return ret;
 }
 
-/*
- * HP-SIR format interrupt service routines.
- */
-static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
-{
-	int status;
-
-	status = Ser2UTSR0;
-
-	/*
-	 * Deal with any receive errors first.  The bytes in error may be
-	 * the only bytes in the receive FIFO, so we do this first.
-	 */
-	while (status & UTSR0_EIF) {
-		int stat, data;
-
-		stat = Ser2UTSR1;
-		data = Ser2UTDR;
-
-		if (stat & (UTSR1_FRE | UTSR1_ROR)) {
-			dev->stats.rx_errors++;
-			if (stat & UTSR1_FRE)
-				dev->stats.rx_frame_errors++;
-			if (stat & UTSR1_ROR)
-				dev->stats.rx_fifo_errors++;
-		} else
-			async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
-
-		status = Ser2UTSR0;
-	}
-
-	/*
-	 * We must clear certain bits.
-	 */
-	Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-
-	if (status & UTSR0_RFS) {
-		/*
-		 * There are at least 4 bytes in the FIFO.  Read 3 bytes
-		 * and leave the rest to the block below.
-		 */
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-	}
-
-	if (status & (UTSR0_RFS | UTSR0_RID)) {
-		/*
-		 * Fifo contains more than 1 character.
-		 */
-		do {
-			async_unwrap_char(dev, &dev->stats, &si->rx_buff,
-					  Ser2UTDR);
-		} while (Ser2UTSR1 & UTSR1_RNE);
-
-	}
-
-	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);
-
-		if (si->tx_buff.len == 0) {
-			dev->stats.tx_packets++;
-			dev->stats.tx_bytes += si->tx_buff.data -
-					      si->tx_buff.head;
-
-			/*
-			 * We need to ensure that the transmitter has
-			 * finished.
-			 */
-			do
-				rmb();
-			while (Ser2UTSR1 & UTSR1_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;
-
-			sa1100_irda_check_speed(si);
-
-			/* I'm hungry! */
-			netif_wake_queue(dev);
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
-{
-	struct sk_buff *skb = si->dma_rx.skb;
-	dma_addr_t dma_addr;
-	unsigned int len, stat, data;
-
-	if (!skb) {
-		printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
-		return;
-	}
-
-	/*
-	 * Get the current data position.
-	 */
-	dma_addr = sa1100_get_dma_pos(si->dma_rx.regs);
-	len = dma_addr - si->dma_rx.dma;
-	if (len > HPSIR_MAX_RXLEN)
-		len = HPSIR_MAX_RXLEN;
-	dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE);
-
-	do {
-		/*
-		 * Read Status, and then Data.
-		 */
-		stat = Ser2HSSR1;
-		rmb();
-		data = Ser2HSDR;
-
-		if (stat & (HSSR1_CRE | HSSR1_ROR)) {
-			dev->stats.rx_errors++;
-			if (stat & HSSR1_CRE)
-				dev->stats.rx_crc_errors++;
-			if (stat & HSSR1_ROR)
-				dev->stats.rx_frame_errors++;
-		} else
-			skb->data[len++] = data;
-
-		/*
-		 * If we hit the end of frame, there's
-		 * no point in continuing.
-		 */
-		if (stat & HSSR1_EOF)
-			break;
-	} while (Ser2HSSR0 & HSSR0_EIF);
-
-	if (stat & HSSR1_EOF) {
-		si->dma_rx.skb = NULL;
-
-		skb_put(skb, len);
-		skb->dev = dev;
-		skb_reset_mac_header(skb);
-		skb->protocol = htons(ETH_P_IRDA);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += len;
-
-		/*
-		 * Before we pass the buffer up, allocate a new one.
-		 */
-		sa1100_irda_rx_alloc(si);
-
-		netif_rx(skb);
-	} else {
-		/*
-		 * Remap the buffer - it was previously mapped, and we
-		 * hope that this succeeds.
-		 */
-		si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
-						HPSIR_MAX_RXLEN,
-						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.
- */
-static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
-{
-	/*
-	 * Stop RX DMA
-	 */
-	sa1100_stop_dma(si->dma_rx.regs);
-
-	/*
-	 * Framing error - we throw away the packet completely.
-	 * Clearing RXE flushes the error conditions and data
-	 * from the fifo.
-	 */
-	if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
-		dev->stats.rx_errors++;
-
-		if (Ser2HSSR0 & HSSR0_FRE)
-			dev->stats.rx_frame_errors++;
-
-		/*
-		 * Clear out the DMA...
-		 */
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
-
-		/*
-		 * Clear selected status bits now, so we
-		 * don't miss them next time around.
-		 */
-		Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;
-	}
-
-	/*
-	 * Deal with any receive errors.  The any of the lowest
-	 * 8 bytes in the FIFO may contain an error.  We must read
-	 * them one by one.  The "error" could even be the end of
-	 * packet!
-	 */
-	if (Ser2HSSR0 & HSSR0_EIF)
-		sa1100_irda_fir_error(si, 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)
 {
 	struct net_device *dev = dev_id;

From 26f2bee1a3063ddd89f76a75b99adb32636f3513 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 17:48:02 +0000
Subject: [PATCH 053/115] NET: sa11x0-ir: move sa1100_irda_txdma_irq

Move the FIR DMA transmit completion function along-side the other FIR
protocol functions.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 108 +++++++++++++++++------------------
 1 file changed, 53 insertions(+), 55 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 61b42d1265b4..0b5a2e2a7be4 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -261,6 +261,57 @@ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_ird
 /*
  * 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;
+
+	/*
+	 * 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);
+
+	/*
+	 * Clear the transmit underrun bit.
+	 */
+	Ser2HSSR0 = HSSR0_TUR;
+
+	/*
+	 * 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);
+
+	/*
+	 * 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_single(si->dev, si->dma_tx.dma, skb->len,
+				 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)
 {
@@ -528,60 +579,6 @@ static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
 	return si->irq(dev, si);
 }
 
-/*
- * TX DMA completion handler.
- */
-static void sa1100_irda_txdma_irq(void *id)
-{
-	struct net_device *dev = id;
-	struct sa1100_irda *si = netdev_priv(dev);
-	struct sk_buff *skb;
-
-	/*
-	 * 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);
-
-	/*
-	 * Clear the transmit underrun bit.
-	 */
-	Ser2HSSR0 = HSSR0_TUR;
-
-	/*
-	 * 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);
-
-	/*
-	 * 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_single(si->dev, si->dma_tx.dma, skb->len,
-				 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_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sa1100_irda *si = netdev_priv(dev);
@@ -730,7 +727,8 @@ static int sa1100_irda_start(struct net_device *dev)
 		goto err_rx_dma;
 
 	err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
-				 sa1100_irda_txdma_irq, dev, &si->dma_tx.regs);
+				 sa1100_irda_firtxdma_irq, dev,
+				 &si->dma_tx.regs);
 	if (err)
 		goto err_tx_dma;
 

From 6a7f4911a470fede7d40746487fb1e4a95657efd Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 8 Jan 2012 20:49:28 +0000
Subject: [PATCH 054/115] NET: sa11x0-ir: get rid of si->hscr0

si->hscr0 is initialized to zero, and never changed.  Get rid of this
redundant variable.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 0b5a2e2a7be4..d428dd0a8bce 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -50,7 +50,6 @@ struct sa1100_buf {
 };
 
 struct sa1100_irda {
-	unsigned char		hscr0;
 	unsigned char		utcr4;
 	unsigned char		power;
 	unsigned char		open;
@@ -124,14 +123,14 @@ 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->dma_rx.regs);
 	sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN);
-	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
+	Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
 }
 
 static void sa1100_irda_check_speed(struct sa1100_irda *si)
@@ -338,7 +337,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	if (mtt)
 		udelay(mtt);
 
-	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
+	Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
 
 	return NETDEV_TX_OK;
 }
@@ -440,7 +439,7 @@ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_ird
 		/*
 		 * Clear out the DMA...
 		 */
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+		Ser2HSCR0 = HSCR0_HSSP;
 
 		/*
 		 * Clear selected status bits now, so we
@@ -513,10 +512,8 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 	case 4000000:
 		local_irq_save(flags);
 
-		si->hscr0 = 0;
-
 		Ser2HSSR0 = 0xff;
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+		Ser2HSCR0 = HSCR0_HSSP;
 		Ser2UTCR3 = 0;
 
 		si->speed = speed;

From 32273f50608e9b98116622e32187cbd139c09716 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 12:45:00 +0000
Subject: [PATCH 055/115] NET: sa11x0-ir: convert to use scatterlist DMA API

Convert the sa11x0 IrDA driver to use the scatterlist DMA API.  This
is a preparatory patch for converting the driver to use the DMA engine
API, which requires a struct scatterlist for every transfer.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 42 ++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index d428dd0a8bce..86d296ed69a7 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -45,7 +45,7 @@ static int max_rate = 4000000;
 
 struct sa1100_buf {
 	struct sk_buff		*skb;
-	dma_addr_t		dma;
+	struct scatterlist	sg;
 	dma_regs_t		*regs;
 };
 
@@ -98,10 +98,8 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 	 */
 	skb_reserve(si->dma_rx.skb, 1);
 
-	si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
-					HPSIR_MAX_RXLEN,
-					DMA_FROM_DEVICE);
-	if (dma_mapping_error(si->dev, si->dma_rx.dma)) {
+	sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
+	if (dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
 		dev_kfree_skb_any(si->dma_rx.skb);
 		return -ENOMEM;
 	}
@@ -129,7 +127,8 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 	 * Enable the DMA, receiver and receive interrupt.
 	 */
 	sa1100_clear_dma(si->dma_rx.regs);
-	sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN);
+	sa1100_start_dma(si->dma_rx.regs, sg_dma_address(&si->dma_rx.sg),
+			 sg_dma_len(&si->dma_rx.sg));
 	Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
 }
 
@@ -296,8 +295,8 @@ static void sa1100_irda_firtxdma_irq(void *id)
 	/* Account and free the packet. */
 	skb = si->dma_tx.skb;
 	if (skb) {
-		dma_unmap_single(si->dev, si->dma_tx.dma, skb->len,
-				 DMA_TO_DEVICE);
+		dma_unmap_sg(si->dev, &si->dma_tx.sg, 1,
+			     DMA_TO_DEVICE);
 		dev->stats.tx_packets ++;
 		dev->stats.tx_bytes += skb->len;
 		dev_kfree_skb_irq(skb);
@@ -317,9 +316,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	int mtt = irda_get_mtt(skb);
 
 	si->dma_tx.skb = skb;
-	si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len,
-					DMA_TO_DEVICE);
-	if (dma_mapping_error(si->dev, si->dma_tx.dma)) {
+	sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
+	if (dma_map_sg(si->dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
 		si->dma_tx.skb = NULL;
 		netif_wake_queue(dev);
 		dev->stats.tx_dropped++;
@@ -327,7 +325,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 		return NETDEV_TX_OK;
 	}
 
-	sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len);
+	sa1100_start_dma(si->dma_tx.regs, sg_dma_address(&si->dma_tx.sg),
+			 sg_dma_len(&si->dma_tx.sg));
 
 	/*
 	 * If we have a mean turn-around time, impose the specified
@@ -357,10 +356,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->dma_rx.regs);
-	len = dma_addr - si->dma_rx.dma;
+	len = dma_addr - sg_dma_address(&si->dma_rx.sg);
 	if (len > HPSIR_MAX_RXLEN)
 		len = HPSIR_MAX_RXLEN;
-	dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE);
+	dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 
 	do {
 		/*
@@ -408,9 +407,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
 		 * Remap the buffer - it was previously mapped, and we
 		 * hope that this succeeds.
 		 */
-		si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
-						HPSIR_MAX_RXLEN,
-						DMA_FROM_DEVICE);
+		dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 	}
 }
 
@@ -786,16 +783,16 @@ static int sa1100_irda_stop(struct net_device *dev)
 	 */
 	skb = si->dma_rx.skb;
 	if (skb) {
-		dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN,
-				 DMA_FROM_DEVICE);
+		dma_unmap_sg(si->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_single(si->dev, si->dma_tx.dma, skb->len,
-				 DMA_TO_DEVICE);
+		dma_unmap_sg(si->dev, &si->dma_tx.sg, 1,
+			     DMA_TO_DEVICE);
 		dev_kfree_skb(skb);
 		si->dma_tx.skb = NULL;
 	}
@@ -871,6 +868,9 @@ static int sa1100_irda_probe(struct platform_device *pdev)
 	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
 	 */

From 04b7fc4dec4fcb61dbe022bbaffda8ea37c39430 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 13:51:10 +0000
Subject: [PATCH 056/115] NET: sa11x0-ir: fix size of SIR transmit buffer

The SIR transmit buffer was being allocated as 4000 bytes.  IrDA now
has constants for the buffer sizes, and defines the maximum wrapped
SIR packet to be 4269 bytes as indicated by IRDA_SIR_MAX_FRAME.  Use
this definition to allocate the transmit buffer instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 86d296ed69a7..be67bdc0ca02 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -877,7 +877,7 @@ static int sa1100_irda_probe(struct platform_device *pdev)
 	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;
 

From 3c500a35544d6270b127bce7d4c5a15ef454b9e2 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 12 Jan 2012 13:56:28 +0000
Subject: [PATCH 057/115] NET: sa11x0-ir: split si->dev for IrDA transmit and
 receive buffers

The sa11x0-ir device is not the device which is doing the DMA, the
DMA is being performed by a separate DMA engine.  Split the struct
device associated with each DMA channel from the main struct device,
but for the time being initialize it from the main struct device.

This is another preparatory step to converting this driver to use the
DMA engine API.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index be67bdc0ca02..9c748f38b9d5 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -44,6 +44,7 @@ static int tx_lpm;
 static int max_rate = 4000000;
 
 struct sa1100_buf {
+	struct device		*dev;
 	struct sk_buff		*skb;
 	struct scatterlist	sg;
 	dma_regs_t		*regs;
@@ -99,7 +100,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 	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->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
+	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;
 	}
@@ -295,7 +296,7 @@ static void sa1100_irda_firtxdma_irq(void *id)
 	/* Account and free the packet. */
 	skb = si->dma_tx.skb;
 	if (skb) {
-		dma_unmap_sg(si->dev, &si->dma_tx.sg, 1,
+		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;
@@ -317,7 +318,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 
 	si->dma_tx.skb = skb;
 	sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
-	if (dma_map_sg(si->dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+	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++;
@@ -359,7 +360,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
 	len = dma_addr - sg_dma_address(&si->dma_rx.sg);
 	if (len > HPSIR_MAX_RXLEN)
 		len = HPSIR_MAX_RXLEN;
-	dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
+	dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 
 	do {
 		/*
@@ -407,7 +408,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
 		 * Remap the buffer - it was previously mapped, and we
 		 * hope that this succeeds.
 		 */
-		dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
+		dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 	}
 }
 
@@ -726,6 +727,9 @@ static int sa1100_irda_start(struct net_device *dev)
 	if (err)
 		goto err_tx_dma;
 
+	si->dma_rx.dev = si->dev;
+	si->dma_tx.dev = si->dev;
+
 	/*
 	 * Setup the serial port for the specified speed.
 	 */
@@ -783,7 +787,7 @@ static int sa1100_irda_stop(struct net_device *dev)
 	 */
 	skb = si->dma_rx.skb;
 	if (skb) {
-		dma_unmap_sg(si->dev, &si->dma_rx.sg, 1,
+		dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
 			     DMA_FROM_DEVICE);
 		dev_kfree_skb(skb);
 		si->dma_rx.skb = NULL;
@@ -791,7 +795,7 @@ static int sa1100_irda_stop(struct net_device *dev)
 
 	skb = si->dma_tx.skb;
 	if (skb) {
-		dma_unmap_sg(si->dev, &si->dma_tx.sg, 1,
+		dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
 			     DMA_TO_DEVICE);
 		dev_kfree_skb(skb);
 		si->dma_tx.skb = NULL;

From abe06082d07fcb0673cb93338c1d6f037fdc375b Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 22:13:52 +0000
Subject: [PATCH 058/115] MFD: mcp/ucb1x00: separate ucb1x00 driver data from
 the MCP data

Patch taken from 5dd7bf59e0 (ARM: sa11x0: Implement autoloading of codec
and codec pdata for mcp bus.) by Jochen Friedrich <jochen@scram.de>.

This adds just the codec data part of the patch.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/collie.c           | 7 ++++++-
 arch/arm/mach-sa1100/include/mach/mcp.h | 2 +-
 arch/arm/mach-sa1100/simpad.c           | 7 ++++++-
 drivers/mfd/mcp-core.c                  | 3 ++-
 drivers/mfd/mcp-sa11x0.c                | 3 +--
 drivers/mfd/ucb1x00-core.c              | 7 ++++---
 include/linux/mfd/mcp.h                 | 3 +--
 include/linux/mfd/ucb1x00.h             | 3 +++
 8 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index efa2bc132cbf..0e7359785159 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -22,6 +22,7 @@
 #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>
@@ -85,10 +86,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,
 };
 
 /*
diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h
index ed1a331508a7..4b2860ae3828 100644
--- a/arch/arm/mach-sa1100/include/mach/mcp.h
+++ b/arch/arm/mach-sa1100/include/mach/mcp.h
@@ -16,7 +16,7 @@ struct mcp_plat_data {
 	u32 mccr0;
 	u32 mccr1;
 	unsigned int sclk_rate;
-	int gpio_base;
+	void *codec_pdata;
 };
 
 #endif
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 3aa36ec21039..81506562ee26 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -10,6 +10,7 @@
 #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>
@@ -187,10 +188,14 @@ static struct resource simpad_flash_resources [] = {
 	}
 };
 
+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,
 };
 
 
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 280a4f8a7876..c409d6327140 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -217,8 +217,9 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_add(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_add(&mcp->attached_device);
 }
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 420710b19f2d..960ebc790389 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -194,7 +194,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
 	mcp->owner		= THIS_MODULE;
 	mcp->ops		= &mcp_sa11x0;
 	mcp->sclk_rate		= data->sclk_rate;
-	mcp->gpio_base		= data->gpio_base;
 
 	m = priv(mcp);
 	m->mccr0 = data->mccr0 | 0x7f7f;
@@ -229,7 +228,7 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
 	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
 			  mcp->sclk_rate;
 
-	ret = mcp_host_add(mcp);
+	ret = mcp_host_add(mcp, data->codec_pdata);
 	if (ret == 0)
 		return 0;
 
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index f2fb4205467c..6825169b06fc 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -534,6 +534,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 {
 	struct ucb1x00 *ucb;
 	struct ucb1x00_driver *drv;
+	struct ucb1x00_plat_data *pdata;
 	unsigned int id;
 	int ret = -ENODEV;
 	int temp;
@@ -551,7 +552,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 	if (!ucb)
 		goto err_disable;
 
-
+	pdata = mcp->attached_device.platform_data;
 	ucb->dev.class = &ucb1x00_class;
 	ucb->dev.parent = &mcp->attached_device;
 	dev_set_name(&ucb->dev, "ucb1x00");
@@ -570,9 +571,9 @@ static int ucb1x00_probe(struct mcp *mcp)
 	}
 
 	ucb->gpio.base = -1;
-	if (mcp->gpio_base != 0) {
+	if (pdata && pdata->gpio_base) {
 		ucb->gpio.label = dev_name(&ucb->dev);
-		ucb->gpio.base = mcp->gpio_base;
+		ucb->gpio.base = pdata->gpio_base;
 		ucb->gpio.ngpio = 10;
 		ucb->gpio.set = ucb1x00_gpio_set;
 		ucb->gpio.get = ucb1x00_gpio_get;
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index dfe7e517ad9b..bfcdf6d3f1bf 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -20,7 +20,6 @@ struct mcp {
 	unsigned int	sclk_rate;
 	unsigned int	rw_timeout;
 	struct device	attached_device;
-	int		gpio_base;
 };
 
 struct mcp_ops {
@@ -41,7 +40,7 @@ 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_add(struct mcp *);
+int mcp_host_add(struct mcp *, void *);
 void mcp_host_del(struct mcp *);
 void mcp_host_free(struct mcp *);
 
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 4321f044d1e4..731b23a656c0 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -104,6 +104,9 @@
 #define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
 #define UCB_MODE_AUD_OFF_CAN	(1 << 13)
 
+struct ucb1x00_plat_data {
+	int			gpio_base;
+};
 
 struct ucb1x00_irq {
 	void *devid;

From 945f6310d3cf0523560b33b9ddb3271666141bd5 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 09:30:27 +0000
Subject: [PATCH 059/115] MFD: ucb1x00-ts: provide input layer with device
 parent

Provide the input layer struct device with its parent device, so
that the input layer's device appears in the correct place in the
device tree.  This also allows the input device to be visibily
associated with its hardware.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-ts.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index ec6ffb6e287d..742d0c7bbbc2 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -363,6 +363,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
 	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);

From c364ff473a8d31c93da5e21ac5d2789a935c8faf Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 16:41:26 +0000
Subject: [PATCH 060/115] MFD: ucb1x00-core: get rid of mach/hardware.h include

Nothing in this driver requires anything from the machine/platform
headers, so remove this needless header file.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 6825169b06fc..cc1c0dce7bd9 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -29,8 +29,6 @@
 #include <linux/gpio.h>
 #include <linux/semaphore.h>
 
-#include <mach/hardware.h>
-
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);

From 2f7510c6070932371e0b842a5470ce7190dcf162 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 22 Jan 2012 19:02:25 +0000
Subject: [PATCH 061/115] MFD: ucb1x00-core: add handling for ucb1x00 reset

Provide a way to handle the software controlled ucb1x00 reset signal
from the ucb1x00-core driver without having to code platform specifics
into these drivers.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c  | 17 +++++++++++++----
 include/linux/mfd/ucb1x00.h |  7 +++++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index cc1c0dce7bd9..42eee633b864 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -530,13 +530,17 @@ 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;
-	struct ucb1x00_plat_data *pdata;
+	struct ucb1x00 *ucb;
 	unsigned int id;
 	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);
 
@@ -550,7 +554,6 @@ static int ucb1x00_probe(struct mcp *mcp)
 	if (!ucb)
 		goto err_disable;
 
-	pdata = mcp->attached_device.platform_data;
 	ucb->dev.class = &ucb1x00_class;
 	ucb->dev.parent = &mcp->attached_device;
 	dev_set_name(&ucb->dev, "ucb1x00");
@@ -606,7 +609,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 	}
 	mutex_unlock(&ucb1x00_mutex);
 
-	goto out;
+	return ret;
 
  err_irq:
 	free_irq(ucb->irq, ucb);
@@ -618,11 +621,14 @@ static int ucb1x00_probe(struct mcp *mcp)
  err_disable:
 	mcp_disable(mcp);
  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,6 +649,9 @@ static void ucb1x00_remove(struct mcp *mcp)
 
 	free_irq(ucb->irq, ucb);
 	device_unregister(&ucb->dev);
+
+	if (pdata && pdata->reset)
+		pdata->reset(UCB_RST_REMOVE);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 731b23a656c0..fd088cc6a4ca 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -104,7 +104,14 @@
 #define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
 #define UCB_MODE_AUD_OFF_CAN	(1 << 13)
 
+enum ucb1x00_reset {
+	UCB_RST_PROBE,
+	UCB_RST_REMOVE,
+	UCB_RST_PROBE_FAIL,
+};
+
 struct ucb1x00_plat_data {
+	void			(*reset)(enum ucb1x00_reset);
 	int			gpio_base;
 };
 

From ddb1e04a35846b6c5b6039e92555dafaf6ee03d2 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 16:33:38 +0000
Subject: [PATCH 062/115] MFD: ucb1x00-core: add .owner initializer and module
 alias

Add a .owner initializer to the UCB1x00 mcp driver structure, and
set an appropriate module alias to identify this driver.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 42eee633b864..c2757c11ce7b 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -714,6 +714,7 @@ static int ucb1x00_resume(struct mcp *mcp)
 static struct mcp_driver ucb1x00_driver = {
 	.drv		= {
 		.name	= "ucb1x00",
+		.owner	= THIS_MODULE,
 	},
 	.probe		= ucb1x00_probe,
 	.remove		= ucb1x00_remove,
@@ -757,6 +758,7 @@ 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");

From cae154767a96563d33924872aacfdc63d584f707 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 09:33:38 +0000
Subject: [PATCH 063/115] MFD: ucb1x00-core: use mutexes instead of semaphores

Convert the ucb1x00 driver to use mutexes rather than the depreciated
semaphores for exclusive access to the ADC.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c  | 15 +++++++--------
 include/linux/mfd/ucb1x00.h |  4 ++--
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index c2757c11ce7b..7386f822d4cd 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -27,7 +27,6 @@
 #include <linux/mutex.h>
 #include <linux/mfd/ucb1x00.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
@@ -99,7 +98,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)
 {
@@ -183,7 +182,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.
@@ -193,7 +192,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;
 
@@ -215,7 +214,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)
 {
@@ -243,7 +242,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)
 {
@@ -251,7 +250,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);
 }
 
 /*
@@ -560,7 +559,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	spin_lock_init(&ucb->lock);
 	spin_lock_init(&ucb->io_lock);
-	sema_init(&ucb->adc_sem, 1);
+	mutex_init(&ucb->adc_mutex);
 
 	ucb->id  = id;
 	ucb->mcp = mcp;
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index fd088cc6a4ca..a4b954381c2f 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -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
@@ -124,7 +124,7 @@ struct ucb1x00 {
 	spinlock_t		lock;
 	struct mcp		*mcp;
 	unsigned int		irq;
-	struct semaphore	adc_sem;
+	struct mutex		adc_mutex;
 	spinlock_t		io_lock;
 	u16			id;
 	u16			io_dir;

From f5ae587f5d258bda9c24bb8387315eb2ebedeee9 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 14:45:17 +0000
Subject: [PATCH 064/115] MFD: ucb1x00-core: clean up device handling in probe

Clean up the device handling so we can use the struct device sanely.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 7386f822d4cd..74d9fcf891d5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -553,6 +553,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 	if (!ucb)
 		goto err_disable;
 
+	device_initialize(&ucb->dev);
 	ucb->dev.class = &ucb1x00_class;
 	ucb->dev.parent = &mcp->attached_device;
 	dev_set_name(&ucb->dev, "ucb1x00");
@@ -563,11 +564,16 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	ucb->id  = id;
 	ucb->mcp = mcp;
+
+	ret = device_add(&ucb->dev);
+	if (ret)
+		goto err_dev_add;
+
 	ucb->irq = ucb1x00_detect_irq(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;
@@ -581,25 +587,20 @@ static int ucb1x00_probe(struct mcp *mcp)
 		ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
 		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",
+		dev_err(&ucb->dev, "ucb1x00: unable to grab irq%d: %d\n",
 			ucb->irq, ret);
-		goto err_gpio;
+		goto err_irq;
 	}
 
 	mcp_set_drvdata(mcp, ucb);
 
-	ret = device_register(&ucb->dev);
-	if (ret)
-		goto err_irq;
-
-
 	INIT_LIST_HEAD(&ucb->devs);
 	mutex_lock(&ucb1x00_mutex);
 	list_add(&ucb->node, &ucb1x00_devices);
@@ -611,12 +612,13 @@ static int ucb1x00_probe(struct mcp *mcp)
 	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_gpio_add:
+ err_no_irq:
+	device_del(&ucb->dev);
+ err_dev_add:
+	put_device(&ucb->dev);
  err_disable:
 	mcp_disable(mcp);
  out:

From 7655b2ac9ed3206fb916357b8b1065f08324507d Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 14:47:00 +0000
Subject: [PATCH 065/115] MFD: ucb1x00-core: add owner and dev initializers to
 gpio structure

Register the gpio device with proper .owner and .dev elements set
appropraitely.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 74d9fcf891d5..30ef726f4ba0 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -579,6 +579,8 @@ static int ucb1x00_probe(struct mcp *mcp)
 	ucb->gpio.base = -1;
 	if (pdata && pdata->gpio_base) {
 		ucb->gpio.label = dev_name(&ucb->dev);
+		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;

From 65b539bb900f64b9a3f9b761bf0f735dc84e6b70 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 15:35:01 +0000
Subject: [PATCH 066/115] MFD: ucb1x00-core: scan drivers in same order they're
 registered

Cosmetic patch to scan the list of drivers in the order that the drivers
are registered, rather than the reverse order.  This avoids surprises
when drivers get probed in the reverse order, and input devices get
registered in a different order due to bind/unbind than from boot.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 30ef726f4ba0..162496de1b38 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -436,8 +436,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);
 		}
@@ -605,7 +605,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	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);
 	}
@@ -663,7 +663,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);
 	}

From ed442b6798eb39eda3bcea92ef9403280b603818 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 18:13:20 +0000
Subject: [PATCH 067/115] MFD: ucb1x00-core: add missing
 ucb1x00_enable()/ucb1x00_disable()

ucb1x00_enable() and ucb1x00_disable() are used for power saving on the
SIB interface, allowing the host supplied clock to be disabled when not
required.  We require drivers which access the ucb1x00 to ensure that
they have enabled the clock prior to accessing the device, and they
should disable it once they're done.

As we don't expect gpiolib users to be aware of this detail, we must
make these calls in the gpiolib interfaces.  Add them.

Also add them to the resume method, which needs to re-establish the
GPIO pin settings.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 162496de1b38..9f8ea52f0ca8 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -116,14 +116,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)
@@ -133,7 +141,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;
@@ -153,6 +163,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);
 
@@ -160,6 +171,7 @@ 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;
@@ -703,8 +715,10 @@ static int ucb1x00_resume(struct mcp *mcp)
 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
 	struct ucb1x00_dev *dev;
 
+	ucb1x00_enable(ucb);
 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+	ucb1x00_disable(ucb);
 	mutex_lock(&ucb1x00_mutex);
 	list_for_each_entry(dev, &ucb->devs, dev_node) {
 		if (dev->drv->resume)

From 2b4d9d2b001be2ff06be2ea5c52e9adaf85b0805 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 18:24:17 +0000
Subject: [PATCH 068/115] MFD: ucb1x00-core: disable mcp clock when bus is not
 required

The ucb1x00-core was leaving the mcp clock enabled indefinitely after
probe.  This needlessly wastes power.  Add the necessary disables to
ensure that the clock remains off when we don't need it.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 9f8ea52f0ca8..ed2a4b2e518f 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -554,16 +554,17 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	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;
@@ -581,7 +582,9 @@ static int ucb1x00_probe(struct mcp *mcp)
 	if (ret)
 		goto err_dev_add;
 
+	ucb1x00_enable(ucb);
 	ucb->irq = ucb1x00_detect_irq(ucb);
+	ucb1x00_disable(ucb);
 	if (ucb->irq == NO_IRQ) {
 		dev_err(&ucb->dev, "IRQ probe failed\n");
 		ret = -ENODEV;
@@ -633,8 +636,6 @@ static int ucb1x00_probe(struct mcp *mcp)
 	device_del(&ucb->dev);
  err_dev_add:
 	put_device(&ucb->dev);
- err_disable:
-	mcp_disable(mcp);
  out:
 	if (pdata && pdata->reset)
 		pdata->reset(UCB_RST_PROBE_FAIL);

From a4b54acf9e691a3051950444d33980741e7d63a8 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 18:26:17 +0000
Subject: [PATCH 069/115] MFD: mcp-sa11x0: complain if mcp clock is left
 enabled

Issue a warning if the mcp clock was left enabled by some driver when
we're suspending or tearing down the core driver for the device.  This
is an aid for debugging missing disable calls.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 960ebc790389..c381436ed3de 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -252,6 +252,10 @@ static int mcp_sa11x0_remove(struct platform_device *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);
 
@@ -271,6 +275,9 @@ static int mcp_sa11x0_suspend(struct device *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");
+
 	writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
 
 	return 0;

From 5a09b7120a965a7d7e8494d0ed509135bbce0118 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 16:36:30 +0000
Subject: [PATCH 070/115] MFD: ucb1x00-core: convert to use dev_pm_ops

Convert the ucb1x00-core driver to use dev_pm_ops rather than the legacy
members in the mcp driver.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c  | 32 ++++++++++++++++++--------------
 include/linux/mfd/ucb1x00.h |  2 +-
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index ed2a4b2e518f..6fab82557543 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -26,6 +26,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mfd/ucb1x00.h>
+#include <linux/pm.h>
 #include <linux/gpio.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
@@ -697,47 +698,50 @@ 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 *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);
 	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 *ucb = dev_get_drvdata(dev);
+	struct ucb1x00_dev *udev;
 
 	ucb1x00_enable(ucb);
 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
 	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)
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index a4b954381c2f..253c12c157a6 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -154,7 +154,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);
 };
 

From cf4abfcc0df2985ff6061f74e63b8353f2a1d0bc Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 16:38:50 +0000
Subject: [PATCH 071/115] MFD: mcp-core: remove legacy driver suspend/resume
 methods

The legacy driver suspend/resume methods are no longer used, so get rid
of them.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-core.c  | 28 ----------------------------
 include/linux/mfd/mcp.h |  2 --
 2 files changed, 30 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index c409d6327140..6acf2e03f2ba 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -47,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,
 };
 
 /**
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index bfcdf6d3f1bf..a9e8bd157673 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -48,8 +48,6 @@ 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 *);

From a3364409c4af8bae42d04def48dc11409787e503 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 14:58:28 +0000
Subject: [PATCH 072/115] MFD: ucb1x00: convert to use genirq

Convert the ucb1x00 driver to use genirq's interrupt services, rather
than its own private implementation.  This allows a wider range of
drivers to use the GPIO interrupts (such as the gpio_keys driver)
without being aware of the UCB1x00's private IRQ system.

This prevents the UCB1x00 core driver from being built as a module,
so adjust the configuration to add that restriction.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/Kconfig         |   5 +-
 drivers/mfd/ucb1x00-core.c  | 257 ++++++++++++++----------------------
 drivers/mfd/ucb1x00-ts.c    |  37 +++++-
 include/linux/mfd/ucb1x00.h |  22 +--
 4 files changed, 137 insertions(+), 184 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index cd13e9f2f5e6..28a301b28579 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -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"
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 6fab82557543..400604d38780 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -23,6 +23,7 @@
 #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>
@@ -178,6 +179,13 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
 	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)
@@ -274,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);
@@ -285,157 +292,84 @@ 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);
-
-		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);
-	}
 }
 
-/**
- *	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_mask(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 void ucb1x00_irq_unmask(struct irq_data *data)
 {
-	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;
-
-	irq = ucb->irq_handler + idx;
-	ret = -ENOENT;
-
-	spin_lock_irq(&ucb->lock);
-	if (irq->devid == devid) {
-		ucb->irq_ris_enbl &= ~(1 << idx);
-		ucb->irq_fal_enbl &= ~(1 << idx);
-
-		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);
-
-		irq->fn = NULL;
-		irq->devid = NULL;
-		ret = 0;
-	}
-	spin_unlock_irq(&ucb->lock);
-	return ret;
-
-bad:
-	printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-	return -EINVAL;
+	raw_spin_lock(&ucb->irq_lock);
+	ucb->irq_mask |= mask;
+	ucb1x00_irq_update(ucb, mask);
+	raw_spin_unlock(&ucb->irq_lock);
 }
 
+static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+	unsigned mask = 1 << (data->irq - ucb->irq_base);
+
+	raw_spin_lock(&ucb->irq_lock);
+	if (type & IRQ_TYPE_EDGE_RISING)
+		ucb->irq_ris_enbl |= mask;
+	else
+		ucb->irq_ris_enbl &= ~mask;
+
+	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);
+
+	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,
+};
+
 static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
 {
 	struct ucb1x00_dev *dev;
@@ -545,9 +479,8 @@ static int ucb1x00_probe(struct mcp *mcp)
 	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
 	struct ucb1x00_driver *drv;
 	struct ucb1x00 *ucb;
-	unsigned int id;
+	unsigned id, i, irq_base;
 	int ret = -ENODEV;
-	int temp;
 
 	/* Tell the platform to deassert the UCB1x00 reset */
 	if (pdata && pdata->reset)
@@ -572,7 +505,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 	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);
 	mutex_init(&ucb->adc_mutex);
 
@@ -593,6 +526,26 @@ static int ucb1x00_probe(struct mcp *mcp)
 	}
 
 	ucb->gpio.base = -1;
+	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.dev = &ucb->dev;
@@ -603,20 +556,13 @@ static int ucb1x00_probe(struct mcp *mcp)
 		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_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) {
-		dev_err(&ucb->dev, "ucb1x00: unable to grab irq%d: %d\n",
-			ucb->irq, ret);
-		goto err_irq;
-	}
-
 	mcp_set_drvdata(mcp, ucb);
 
 	INIT_LIST_HEAD(&ucb->devs);
@@ -629,10 +575,11 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	return ret;
 
- err_irq:
-	if (ucb->gpio.base != -1)
-		temp = gpiochip_remove(&ucb->gpio);
  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:
@@ -664,7 +611,8 @@ 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)
@@ -772,11 +720,6 @@ 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);
 
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 742d0c7bbbc2..1e0e20c0e082 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -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>
@@ -41,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;
@@ -237,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);
 
 			/*
@@ -280,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;
 
@@ -313,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;
 	}
@@ -333,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);
 }
@@ -358,6 +380,7 @@ 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;
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 253c12c157a6..6fb907446c33 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -112,18 +112,15 @@ enum ucb1x00_reset {
 
 struct ucb1x00_plat_data {
 	void			(*reset)(enum ucb1x00_reset);
+	unsigned		irq_base;
 	int			gpio_base;
 };
 
-struct ucb1x00_irq {
-	void *devid;
-	void (*fn)(int, void *);
-};
-
 struct ucb1x00 {
-	spinlock_t		lock;
+	raw_spinlock_t		irq_lock;
 	struct mcp		*mcp;
 	unsigned int		irq;
+	int			irq_base;
 	struct mutex		adc_mutex;
 	spinlock_t		io_lock;
 	u16			id;
@@ -132,7 +129,7 @@ struct ucb1x00 {
 	u16			adc_cr;
 	u16			irq_fal_enbl;
 	u16			irq_ris_enbl;
-	struct ucb1x00_irq	irq_handler[16];
+	u16			irq_mask;
 	struct device		dev;
 	struct list_head	node;
 	struct list_head	devs;
@@ -255,15 +252,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

From 33237616771bfc29a97f17e74efe3799bb790343 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 22 Jan 2012 20:05:24 +0000
Subject: [PATCH 073/115] MFD: ucb1x00-core: add wakeup support

Add genirq wakeup support for the ucb1x00 device.  This allows an
attached gpio_keys driver to wakeup the system.  Touchscreen is also
possible.

When there are no wakeup sources, ask the platform to assert the reset
signal to avoid any unexpected behaviour; this also puts the reset
signal at the right level when power is removed from the device.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c  | 59 +++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ucb1x00.h |  4 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 400604d38780..70f02daeb22a 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -362,12 +362,32 @@ static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
 	return 0;
 }
 
+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);
+
+	if (!pdata || !pdata->can_wakeup)
+		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)
@@ -565,6 +585,9 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	mcp_set_drvdata(mcp, ucb);
 
+	if (pdata)
+		device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
+
 	INIT_LIST_HEAD(&ucb->devs);
 	mutex_lock(&ucb1x00_mutex);
 	list_add_tail(&ucb->node, &ucb1x00_devices);
@@ -648,6 +671,7 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
 
 static int ucb1x00_suspend(struct device *dev)
 {
+	struct ucb1x00_plat_data *pdata = dev->platform_data;
 	struct ucb1x00 *ucb = dev_get_drvdata(dev);
 	struct ucb1x00_dev *udev;
 
@@ -657,18 +681,53 @@ static int ucb1x00_suspend(struct device *dev)
 			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 device *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(udev, &ucb->devs, dev_node) {
 		if (udev->drv->resume)
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 6fb907446c33..28af41756360 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -106,6 +106,8 @@
 
 enum ucb1x00_reset {
 	UCB_RST_PROBE,
+	UCB_RST_RESUME,
+	UCB_RST_SUSPEND,
 	UCB_RST_REMOVE,
 	UCB_RST_PROBE_FAIL,
 };
@@ -114,6 +116,7 @@ struct ucb1x00_plat_data {
 	void			(*reset)(enum ucb1x00_reset);
 	unsigned		irq_base;
 	int			gpio_base;
+	unsigned		can_wakeup;
 };
 
 struct ucb1x00 {
@@ -130,6 +133,7 @@ struct ucb1x00 {
 	u16			irq_fal_enbl;
 	u16			irq_ris_enbl;
 	u16			irq_mask;
+	u16			irq_wake;
 	struct device		dev;
 	struct list_head	node;
 	struct list_head	devs;

From 69dde86aa616b09bb3ef39a5ab783f82254d241c Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 20 Jan 2012 22:18:06 +0000
Subject: [PATCH 074/115] ARM: sa11x0: add assabet ucb1x00 platform data

Add ucb1x00 platform data to enable GPIO support on the UCB1300 device.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 3a1914568374..c45402f866cc 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -15,6 +15,7 @@
 #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>
@@ -199,9 +200,14 @@ static struct irda_platform_data assabet_irda_data = {
 	.set_speed	= assabet_irda_set_speed,
 };
 
+static struct ucb1x00_plat_data assabet_ucb1x00_data = {
+	.gpio_base	= -1,
+};
+
 static struct mcp_plat_data assabet_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
+	.codec_pdata	= &assabet_ucb1x00_data,
 };
 
 static void __init assabet_init(void)

From 54292a4649a5dd93562d10f188a8e201afebfe2f Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 21 Jan 2012 15:53:42 +0000
Subject: [PATCH 075/115] MFD: ucb1x00-assabet: add support for UCB1x00 GPIO
 switches

Add support for UCB1x00 GPIO buttons found on the Assabet platform.
We can now trivially support these buttons as we have standardized
gpiolib, genirq and gpio keyboard support in place for this device.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-assabet.c | 45 +++++++++++++++++++++++++++++++----
 1 file changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index b7be613cb503..b63c0756a669 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -11,9 +11,13 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.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/mfd/ucb1x00.h>
 
 #define UCB1X00_ATTR(name,input)\
@@ -35,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);

From 6ed3e2acc7995625625592abe8cd3383c34a471b Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 22 Jan 2012 19:23:33 +0000
Subject: [PATCH 076/115] MFD: mcp-sa11x0/assabet: move assabet reset handling
 out of mcp-sa11x0.c

Move the assabet specific reset handling out of mcp-sa11x0.c, into its
board file.  This leaves the mcp code free from all board specific
details.

Acked-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 8 ++++++++
 drivers/mfd/mcp-sa11x0.c       | 6 ------
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index c45402f866cc..b5955ad35945 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -70,6 +70,13 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
 
 EXPORT_SYMBOL(ASSABET_BCR_frob);
 
+static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
+{
+	if (state == UCB_RST_PROBE)
+		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+}
+
+
 static void assabet_backlight_power(int on)
 {
 #ifndef ASSABET_PAL_VIDEO
@@ -201,6 +208,7 @@ static struct irda_platform_data assabet_irda_data = {
 };
 
 static struct ucb1x00_plat_data assabet_ucb1x00_data = {
+	.reset		= assabet_ucb1x00_reset,
 	.gpio_base	= -1,
 };
 
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index c381436ed3de..1c0ceacaa1f6 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -27,8 +27,6 @@
 #include <asm/system.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
 #define DRIVER_NAME "sa11x0-mcp"
 
 struct mcp_sa11x0 {
@@ -208,10 +206,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
 
 	platform_set_drvdata(dev, mcp);
 
-	if (machine_is_assabet()) {
-		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-	}
-
 	/*
 	 * Initialise device.  Note that we initially
 	 * set the sampling rate to minimum.

From 66564d832f531c6336d6d06b6976e16b249aa532 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:00:38 +0000
Subject: [PATCH 077/115] FB: sa1100: avoid section mismatch warnings

WARNING: drivers/video/built-in.o(.devinit.text+0x58): Section mismatch in reference from the function sa1100fb_probe() to the function .init.text:sa1100fb_init_fbinfo()
The function __devinit sa1100fb_probe() references
a function __init sa1100fb_init_fbinfo().
If sa1100fb_init_fbinfo is only used by sa1100fb_probe then
annotate sa1100fb_init_fbinfo with a matching annotation.

WARNING: drivers/video/built-in.o(.devinit.text+0x258): Section mismatch in reference from the function sa1100fb_init_fbinfo() to the (unknown reference) .init.data:(unknown)
The function __devinit sa1100fb_init_fbinfo() references
a (unknown reference) __initdata (unknown).
If (unknown) is only used by sa1100fb_init_fbinfo then
annotate (unknown) with a matching annotation.

WARNING: drivers/video/built-in.o(.devinit.text+0x26c): Section mismatch in reference from the function sa1100fb_init_fbinfo() to the (unknown reference) .init.data:(unknown)
The function __devinit sa1100fb_init_fbinfo() references
a (unknown reference) __initdata (unknown).
If (unknown) is only used by sa1100fb_init_fbinfo then
annotate (unknown) with a matching annotation.

WARNING: drivers/video/built-in.o(.devinit.text+0x270): Section mismatch in reference from the function sa1100fb_init_fbinfo() to the (unknown reference) .init.data:(unknown)
The function __devinit sa1100fb_init_fbinfo() references
a (unknown reference) __initdata (unknown).
If (unknown) is only used by sa1100fb_init_fbinfo then
annotate (unknown) with a matching annotation.

WARNING: drivers/video/built-in.o(.devinit.text+0x278): Section mismatch in reference from the function sa1100fb_init_fbinfo() to the (unknown reference) .init.data:(unknown)
The function __devinit sa1100fb_init_fbinfo() references
a (unknown reference) __initdata (unknown).
If (unknown) is only used by sa1100fb_init_fbinfo then
annotate (unknown) with a matching annotation.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 98d55d0e2da5..2cc268c0e89a 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -227,7 +227,7 @@ static struct sa1100fb_rgb def_rgb_16 = {
  * takes an RGB666 signal, but we provide it with an RGB565 signal
  * instead (def_rgb_16).
  */
-static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
+static struct sa1100fb_mach_info lq039q2ds54_info __devinitdata = {
 	.pixclock	= 171521,	.bpp		= 16,
 	.xres		= 320,		.yres		= 240,
 
@@ -241,7 +241,7 @@ static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
 	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 #else
-static struct sa1100fb_mach_info pal_info __initdata = {
+static struct sa1100fb_mach_info pal_info __devinitdata = {
 	.pixclock	= 67797,	.bpp		= 16,
 	.xres		= 640,		.yres		= 512,
 
@@ -256,7 +256,7 @@ static struct sa1100fb_mach_info pal_info __initdata = {
 #endif
 
 #ifdef CONFIG_SA1100_H3600
-static struct sa1100fb_mach_info h3600_info __initdata = {
+static struct sa1100fb_mach_info h3600_info __devinitdata = {
 	.pixclock	= 174757, 	.bpp		= 16,
 	.xres		= 320,		.yres		= 240,
 
@@ -279,7 +279,7 @@ static struct sa1100fb_rgb h3600_rgb_16 = {
 #endif
 
 #ifdef CONFIG_SA1100_H3100
-static struct sa1100fb_mach_info h3100_info __initdata = {
+static struct sa1100fb_mach_info h3100_info __devinitdata = {
 	.pixclock	= 406977, 	.bpp		= 4,
 	.xres		= 320,		.yres		= 240,
 
@@ -297,7 +297,7 @@ static struct sa1100fb_mach_info h3100_info __initdata = {
 #endif
 
 #ifdef CONFIG_SA1100_COLLIE
-static struct sa1100fb_mach_info collie_info __initdata = {
+static struct sa1100fb_mach_info collie_info __devinitdata = {
 	.pixclock	= 171521,	.bpp		= 16,
 	.xres		= 320,		.yres		= 240,
 
@@ -313,7 +313,7 @@ static struct sa1100fb_mach_info collie_info __initdata = {
 #endif
 
 #ifdef LART_GREY_LCD
-static struct sa1100fb_mach_info lart_grey_info __initdata = {
+static struct sa1100fb_mach_info lart_grey_info __devinitdata = {
 	.pixclock	= 150000,	.bpp		= 4,
 	.xres		= 320,		.yres		= 240,
 
@@ -329,7 +329,7 @@ static struct sa1100fb_mach_info lart_grey_info __initdata = {
 };
 #endif
 #ifdef LART_COLOR_LCD
-static struct sa1100fb_mach_info lart_color_info __initdata = {
+static struct sa1100fb_mach_info lart_color_info __devinitdata = {
 	.pixclock	= 150000,	.bpp		= 16,
 	.xres		= 320,		.yres		= 240,
 
@@ -342,7 +342,7 @@ static struct sa1100fb_mach_info lart_color_info __initdata = {
 };
 #endif
 #ifdef LART_VIDEO_OUT
-static struct sa1100fb_mach_info lart_video_info __initdata = {
+static struct sa1100fb_mach_info lart_video_info __devinitdata = {
 	.pixclock	= 39721,	.bpp		= 16,
 	.xres		= 640,		.yres		= 480,
 
@@ -358,7 +358,7 @@ static struct sa1100fb_mach_info lart_video_info __initdata = {
 #endif
 
 #ifdef LART_KIT01_LCD
-static struct sa1100fb_mach_info lart_kit01_info __initdata = {
+static struct sa1100fb_mach_info lart_kit01_info __devinitdata = {
 	.pixclock	= 63291,	.bpp		= 16,
 	.xres		= 640,		.yres		= 480,
 
@@ -372,7 +372,7 @@ static struct sa1100fb_mach_info lart_kit01_info __initdata = {
 #endif
 
 #ifdef CONFIG_SA1100_SHANNON
-static struct sa1100fb_mach_info shannon_info __initdata = {
+static struct sa1100fb_mach_info shannon_info __devinitdata = {
 	.pixclock	= 152500,	.bpp		= 8,
 	.xres		= 640,		.yres		= 480,
 
@@ -389,7 +389,7 @@ static struct sa1100fb_mach_info shannon_info __initdata = {
 
 
 
-static struct sa1100fb_mach_info * __init
+static struct sa1100fb_mach_info * __devinit
 sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
 {
 	struct sa1100fb_mach_info *inf = NULL;
@@ -1318,7 +1318,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 +1344,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,7 +1352,7 @@ 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_info *fbi;

From 4f7e34f8eff0b3dbbd75cc778b0a363bdb29ac18 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:11:03 +0000
Subject: [PATCH 078/115] FB: sa1100: add .owner initializer to driver
 structure

Annotate the driver structure with the .owner field, to allow the
module to be associated with the driver.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 2cc268c0e89a..bac9d4f39da5 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1505,6 +1505,7 @@ static struct platform_driver sa1100fb_driver = {
 	.resume		= sa1100fb_resume,
 	.driver		= {
 		.name	= "sa11x0-fb",
+		.owner	= THIS_MODULE,
 	},
 };
 

From 58f5cbf275f8fb9529cba20df2564d370a6107da Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:13:30 +0000
Subject: [PATCH 079/115] FB: sa1100: constify rgb structures

The rgb structures should only be read and never written.  Constify
them.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 8 ++++----
 drivers/video/sa1100fb.h | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index bac9d4f39da5..a797220fdf5c 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -199,21 +199,21 @@
 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, },
@@ -270,7 +270,7 @@ static struct sa1100fb_mach_info h3600_info __devinitdata = {
 	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 
-static struct sa1100fb_rgb h3600_rgb_16 = {
+static const struct sa1100fb_rgb h3600_rgb_16 = {
 	.red	= { .offset = 12, .length = 4, },
 	.green	= { .offset = 7,  .length = 4, },
 	.blue	= { .offset = 1,  .length = 4, },
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 1c3b459865d8..7a3d66a5516f 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -65,7 +65,7 @@ struct sa1100fb_lcd_reg {
 struct sa1100fb_info {
 	struct fb_info		fb;
 	struct device		*dev;
-	struct sa1100fb_rgb	*rgb[NR_RGB];
+	const struct sa1100fb_rgb *rgb[NR_RGB];
 
 	u_int			max_bpp;
 	u_int			max_xres;

From 798892966871077b8c867abf3d491227037dc2eb Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:22:56 +0000
Subject: [PATCH 080/115] FB: sa1100: convert printks to dev_xxx()

Use the dev_xxx() macros for driver kernel message output, rather than
open coded printk() with KERN_ levels etc.  Remove DPRINTK().

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 72 +++++++++++++++++++---------------------
 drivers/video/sa1100fb.h |  9 -----
 2 files changed, 34 insertions(+), 47 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index a797220fdf5c..ecd7cd4ce412 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -183,10 +183,6 @@
 #include <mach/assabet.h>
 #include <mach/shannon.h>
 
-/*
- * debugging?
- */
-#define DEBUG 0
 /*
  * Complain if VAR is out of range.
  */
@@ -614,7 +610,7 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 	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 +634,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
@@ -683,7 +679,7 @@ 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;
@@ -704,7 +700,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;
@@ -775,7 +771,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,39 +859,39 @@ 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
 
@@ -928,10 +924,10 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
 		(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;
@@ -967,7 +963,7 @@ 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);
@@ -975,7 +971,7 @@ static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int 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);
@@ -1015,7 +1011,7 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
 
 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
@@ -1037,19 +1033,19 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 		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);
+	dev_dbg(fbi->dev, "DBAR1 = 0x%08lx\n", DBAR1);
+	dev_dbg(fbi->dev, "DBAR2 = 0x%08lx\n", DBAR2);
+	dev_dbg(fbi->dev, "LCCR0 = 0x%08lx\n", LCCR0);
+	dev_dbg(fbi->dev, "LCCR1 = 0x%08lx\n", LCCR1);
+	dev_dbg(fbi->dev, "LCCR2 = 0x%08lx\n", LCCR2);
+	dev_dbg(fbi->dev, "LCCR3 = 0x%08lx\n", LCCR3);
 }
 
 static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	DPRINTK("Disabling LCD controller\n");
+	dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
 	if (machine_is_shannon()) {
 		GPCR |= SHANNON_GPIO_DISP_EN;
@@ -1268,7 +1264,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 */
@@ -1459,7 +1455,7 @@ 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;
 	}
 
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 7a3d66a5516f..b1d5b089ee4a 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -129,15 +129,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
  */

From 531060fc1989a438fbc2c3198f5057c40121ff50 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:49:44 +0000
Subject: [PATCH 081/115] FB: sa1100: combine RGB bitfield overrides into
 sa1100fb_mach_info

Allow the sa1100fb_mach_info structure to carry the RGB bitfield
overrides, rather than requiring them to be separately initialized
in sa1100fb_get_machine_info().

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 21 ++++++++++++++-------
 drivers/video/sa1100fb.h | 22 ++++++++++------------
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index ecd7cd4ce412..a905e20404fd 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -252,6 +252,13 @@ static struct sa1100fb_mach_info pal_info __devinitdata = {
 #endif
 
 #ifdef CONFIG_SA1100_H3600
+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_info __devinitdata = {
 	.pixclock	= 174757, 	.bpp		= 16,
 	.xres		= 320,		.yres		= 240,
@@ -264,13 +271,8 @@ static struct sa1100fb_mach_info h3600_info __devinitdata = {
 
 	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
 	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
 
-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, },
+	.rgb[RGB_16] = &h3600_rgb_16,
 };
 #endif
 
@@ -413,7 +415,6 @@ sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
 #ifdef CONFIG_SA1100_H3600
 	if (machine_is_h3600()) {
 		inf = &h3600_info;
-		fbi->rgb[RGB_16] = &h3600_rgb_16;
 	}
 #endif
 #ifdef CONFIG_SA1100_COLLIE
@@ -1352,6 +1353,7 @@ static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 {
 	struct sa1100fb_mach_info *inf;
 	struct sa1100fb_info *fbi;
+	unsigned i;
 
 	fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
 		      GFP_KERNEL);
@@ -1424,6 +1426,11 @@ static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
 					  fbi->max_bpp / 8;
 
+	/* 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);
 	mutex_init(&fbi->ctrlr_lock);
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index b1d5b089ee4a..77239b766e56 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -10,10 +10,12 @@
  * for more details.
  */
 
-/*
- * These are the bitfields for each
- * display depth that we support.
- */
+#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;
@@ -21,9 +23,7 @@ struct sa1100fb_rgb {
 	struct fb_bitfield	transp;
 };
 
-/*
- * This structure describes the machine which we are running on.
- */
+/* This structure describes the machine which we are running on. */
 struct sa1100fb_mach_info {
 	u_long		pixclock;
 
@@ -47,6 +47,9 @@ struct sa1100fb_mach_info {
 
 	u_int		lccr0;
 	u_int		lccr3;
+
+	/* Overrides for the default RGB maps */
+	const struct sa1100fb_rgb *rgb[NR_RGB];
 };
 
 /* Shadows for LCD controller registers */
@@ -57,11 +60,6 @@ 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;

From 9e6720fb0cfd6edda12b408a66f4ac88e8a82e32 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 10:56:06 +0000
Subject: [PATCH 082/115] FB: sa1100: move machine inf structures to
 <video/sa1100fb.h>

Move the LCD data structures to an include file which can be shared
with the board code in arch/arm/mach-sa1100.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c |  6 +++-
 drivers/video/sa1100fb.h | 42 ----------------------------
 include/video/sa1100fb.h | 59 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 43 deletions(-)
 create mode 100644 include/video/sa1100fb.h

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index a905e20404fd..8f5557a12ff8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -178,6 +178,8 @@
 #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>
@@ -1388,7 +1390,9 @@ static struct sa1100fb_info * __devinit 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);
+	inf = dev->platform_data;
+	if (!inf)
+		inf = sa1100fb_get_machine_info(fbi);
 
 	/*
 	 * People just don't seem to get this.  We don't support
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 77239b766e56..9ff9ba9a281a 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -10,48 +10,6 @@
  * for more details.
  */
 
-#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];
-};
-
 /* Shadows for LCD controller registers */
 struct sa1100fb_lcd_reg {
 	unsigned long lccr0;
diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h
new file mode 100644
index 000000000000..e73c813c87f0
--- /dev/null
+++ b/include/video/sa1100fb.h
@@ -0,0 +1,59 @@
+/*
+ * 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];
+};
+
+#endif

From e1b7a72aeb8292502c97b43eceb01aea47ded40f Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 11:50:04 +0000
Subject: [PATCH 083/115] FB: sa1100: move platform data to platform files

Move platform data out of the sa1100fb driver into the various
platform files themselves.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c |  40 ++++++
 arch/arm/mach-sa1100/collie.c  |  17 +++
 arch/arm/mach-sa1100/generic.c |   8 +-
 arch/arm/mach-sa1100/generic.h |   3 +
 arch/arm/mach-sa1100/h3100.c   |  22 ++-
 arch/arm/mach-sa1100/h3600.c   |  31 ++++-
 arch/arm/mach-sa1100/lart.c    |  79 +++++++++++
 arch/arm/mach-sa1100/shannon.c |  17 +++
 drivers/video/sa1100fb.c       | 239 +--------------------------------
 9 files changed, 218 insertions(+), 238 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 0c4b76ab4d8e..37fb0cd1a296 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -20,6 +20,8 @@
 #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>
@@ -204,6 +206,39 @@ static struct mcp_plat_data assabet_mcp_data = {
 	.sclk_rate	= 11981000,
 };
 
+#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 = {
+	.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 = {
+	.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
+
 static void __init assabet_init(void)
 {
 	/*
@@ -249,6 +284,11 @@ static void __init assabet_init(void)
 #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);
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index fd5652118ed1..70f6cdc9e63d 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -28,6 +28,8 @@
 #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>
@@ -310,6 +312,20 @@ static struct resource collie_flash_resources[] = {
 	}
 };
 
+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)
 {
 	int ret = 0;
@@ -348,6 +364,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);
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index bb10ee2cb89f..f57808fb1827 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -19,6 +19,8 @@
 #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>
@@ -294,6 +296,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,
@@ -356,7 +363,6 @@ static struct platform_device *sa11x0_devices[] __initdata = {
 	&sa11x0uart3_device,
 	&sa11x0ssp_device,
 	&sa11x0pcmcia_device,
-	&sa11x0fb_device,
 	&sa11x0rtc_device,
 };
 
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index 33268cf6be36..3b903f42464d 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -40,3 +40,6 @@ void sa11x0_register_irda(struct irda_platform_data *irda);
 
 struct mcp_plat_data;
 void sa11x0_register_mcp(struct mcp_plat_data *data);
+
+struct sa1100fb_mach_info;
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
index 1e6b3c105ba6..1f8a271dc668 100644
--- a/arch/arm/mach-sa1100/h3100.c
+++ b/arch/arm/mach-sa1100/h3100.c
@@ -14,6 +14,8 @@
 #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>
@@ -36,13 +38,26 @@ 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),
+};
 
 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,6 +95,9 @@ static void __init h3100_mach_init(void)
 {
 	h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
 	h3xxx_mach_init();
+
+	sa1100fb_lcd_power = h3100_lcd_power;
+	sa11x0_register_lcd(&h3100_lcd_info);
 	sa11x0_register_irda(&h3100_irda_data);
 }
 
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 6b58e7460ecf..3dd39bfe348d 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -14,6 +14,8 @@
 #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>
@@ -56,11 +58,33 @@ 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,
+};
+
+
 static void __init h3600_map_io(void)
 {
 	h3xxx_map_io();
-
-	sa1100fb_lcd_power = h3600_lcd_power;
 }
 
 /*
@@ -121,6 +145,9 @@ static void __init h3600_mach_init(void)
 {
 	h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
 	h3xxx_mach_init();
+
+	sa1100fb_lcd_power = h3600_lcd_power;
+	sa11x0_register_lcd(&h3600_lcd_info);
 	sa11x0_register_irda(&h3600_irda_data);
 }
 
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index af4e2761f3db..463a322a425b 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -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>
@@ -26,8 +28,85 @@ 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_register_mcp(&lart_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 318b2b766a0b..c695b730bd69 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -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>
@@ -57,8 +59,23 @@ static struct mcp_plat_data shannon_mcp_data = {
 	.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_register_lcd(&shannon_lcd_info);
 	sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
 	sa11x0_register_mcp(&shannon_mcp_data);
 }
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 8f5557a12ff8..d645c6d5fd9f 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -218,235 +218,7 @@ static const struct sa1100fb_rgb def_rgb_16 = {
 	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 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_info __devinitdata = {
-	.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,
-};
-#endif
-
-#ifdef CONFIG_SA1100_H3100
-static struct sa1100fb_mach_info h3100_info __devinitdata = {
-	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 __devinitdata = {
-	.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 * __devinit
-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;
-	}
-#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);
@@ -1353,7 +1125,7 @@ static struct fb_monspecs monspecs __devinitdata = {
 
 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;
 
@@ -1390,10 +1162,6 @@ static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 	fbi->rgb[RGB_8]		= &rgb_8;
 	fbi->rgb[RGB_16]	= &def_rgb_16;
 
-	inf = dev->platform_data;
-	if (!inf)
-		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
@@ -1447,6 +1215,11 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 	struct sa1100fb_info *fbi;
 	int ret, irq;
 
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "no platform LCD data\n");
+		return -EINVAL;
+	}
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return -EINVAL;

From 086ada54abaa4316e8603f02410fe8ebc9ba2de1 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 12:03:22 +0000
Subject: [PATCH 084/115] FB: sa1100: remove global sa1100fb_.*_power function
 pointers

Now that we have platform data contained within the individual board
code, we can get rid of the global function pointers, placing them
inside the platform data instead.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c | 90 ++++++++++++++++++++++------------
 arch/arm/mach-sa1100/generic.c |  6 ---
 arch/arm/mach-sa1100/generic.h |  3 --
 arch/arm/mach-sa1100/h3100.c   |  3 +-
 arch/arm/mach-sa1100/h3600.c   |  3 +-
 drivers/video/sa1100fb.c       | 32 ++++--------
 drivers/video/sa1100fb.h       |  2 +
 include/video/sa1100fb.h       |  4 ++
 8 files changed, 79 insertions(+), 64 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 37fb0cd1a296..65b0a9a3fb9c 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -71,33 +71,6 @@ 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)
-{
-#ifndef ASSABET_PAL_VIDEO
-	if (on) {
-		ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
-		udelay(500);
-	} else
-#endif
-		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
-}
-
 
 /*
  * Assabet flash support code.
@@ -206,7 +179,49 @@ static struct mcp_plat_data assabet_mcp_data = {
 	.sclk_rate	= 11981000,
 };
 
+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
@@ -224,8 +239,22 @@ static struct sa1100fb_mach_info lq039q2ds54_info = {
 
 	.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,
@@ -236,6 +265,10 @@ static struct sa1100fb_mach_info pal_info = {
 
 	.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
 
@@ -266,9 +299,6 @@ 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;
-
 	if (machine_has_neponset()) {
 		/*
 		 * Angel sets this, but other bootloaders may not.
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index f57808fb1827..9cb4062b1e9b 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -374,12 +374,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:
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index 3b903f42464d..5c68be858e0c 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -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);
 
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
index 1f8a271dc668..f23e7d0b2fba 100644
--- a/arch/arm/mach-sa1100/h3100.c
+++ b/arch/arm/mach-sa1100/h3100.c
@@ -52,6 +52,8 @@ static struct sa1100fb_mach_info h3100_lcd_info = {
 
 	.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)
@@ -96,7 +98,6 @@ static void __init h3100_mach_init(void)
 	h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
 	h3xxx_mach_init();
 
-	sa1100fb_lcd_power = h3100_lcd_power;
 	sa11x0_register_lcd(&h3100_lcd_info);
 	sa11x0_register_irda(&h3100_irda_data);
 }
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 3dd39bfe348d..2feac56ec90d 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -79,6 +79,8 @@ static struct sa1100fb_mach_info h3600_lcd_info = {
 	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 
 	.rgb[RGB_16] = &h3600_rgb_16,
+
+	.lcd_power = h3600_lcd_power,
 };
 
 
@@ -146,7 +148,6 @@ static void __init h3600_mach_init(void)
 	h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
 	h3xxx_mach_init();
 
-	sa1100fb_lcd_power = h3600_lcd_power;
 	sa11x0_register_lcd(&h3600_lcd_info);
 	sa11x0_register_irda(&h3600_irda_data);
 }
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index d645c6d5fd9f..c9f1e7cd95f8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -194,9 +194,6 @@
 
 #include "sa1100fb.h"
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
 static const struct sa1100fb_rgb rgb_4 = {
 	.red	= { .offset = 0,  .length = 4, },
 	.green	= { .offset = 0,  .length = 4, },
@@ -426,22 +423,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);
 }
 
 /*
@@ -483,7 +468,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;
@@ -740,16 +725,16 @@ static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
 {
 	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)
 {
 	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)
@@ -1197,6 +1182,7 @@ static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 	fbi->task_state			= (u_char)-1;
 	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
 					  fbi->max_bpp / 8;
+	fbi->inf			= inf;
 
 	/* Copy the RGB bitfield overrides */
 	for (i = 0; i < NR_RGB; i++)
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 9ff9ba9a281a..3a634abbec14 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -65,6 +65,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)
diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h
index e73c813c87f0..4ab409653785 100644
--- a/include/video/sa1100fb.h
+++ b/include/video/sa1100fb.h
@@ -54,6 +54,10 @@ struct sa1100fb_mach_info {
 
 	/* 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

From d1a378876c2ab3ea119eea502e8d48e25ef253e4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 12:21:18 +0000
Subject: [PATCH 085/115] FB: sa1100: remove assabet specific initialization

Remove the assabet specific initialization for PAL output mode -
we call the lcd_power function before we enable the LCD controller,
which will disable the LCD panel to prevent it receiving incorrect
timings.  Therefore, this setup here is redundant.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index c9f1e7cd95f8..f6e27f4da1d8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -182,7 +182,6 @@
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <mach/assabet.h>
 #include <mach/shannon.h>
 
 /*
@@ -190,8 +189,6 @@
  */
 #define DEBUG_VAR 1
 
-#undef ASSABET_PAL_VIDEO
-
 #include "sa1100fb.h"
 
 static const struct sa1100fb_rgb rgb_4 = {
@@ -1229,11 +1226,6 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 		goto failed;
 	}
 
-#ifdef ASSABET_PAL_VIDEO
-	if (machine_is_assabet())
-		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
-#endif
-
 	/*
 	 * This makes sure that our colour bitfield
 	 * descriptors are correctly initialised.

From ba5fd193f4fd35e5e1771de15cc1aba11d19590d Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 12:32:14 +0000
Subject: [PATCH 086/115] FB: sa1100: use inf members directly

Now that the LCD information is available while the driver is loaded,
we don't need to cache that information into our driver private data
structure.  Get rid of it.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 31 ++++++++++++-------------------
 drivers/video/sa1100fb.h | 10 ----------
 2 files changed, 12 insertions(+), 29 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index f6e27f4da1d8..d1d97cab24c8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -298,7 +298,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;
@@ -372,10 +372,10 @@ 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);
 
@@ -440,7 +440,7 @@ static int sa1100fb_set_par(struct fb_info *info)
 
 	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 {
 		/*
@@ -481,7 +481,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);
@@ -652,7 +652,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
 			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);
 
@@ -667,7 +667,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 =
@@ -677,7 +677,7 @@ 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);
 
@@ -1154,13 +1154,10 @@ static struct sa1100fb_info * __devinit 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;
@@ -1171,14 +1168,10 @@ static struct sa1100fb_info * __devinit 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 */
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 3a634abbec14..e968e1d69520 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -23,10 +23,6 @@ struct sa1100fb_info {
 	struct device		*dev;
 	const struct sa1100fb_rgb *rgb[NR_RGB];
 
-	u_int			max_bpp;
-	u_int			max_xres;
-	u_int			max_yres;
-
 	/*
 	 * These are the addresses we mapped
 	 * the framebuffer memory region to.
@@ -44,12 +40,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;

From 058502eb38a0f687e5af37209488d03656f87ffe Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Wed, 18 Jan 2012 12:52:59 +0000
Subject: [PATCH 087/115] FB: sa1100: make GPIO configuration setting safe

The sa1100fb driver needs to set the GPIO direction and alternate
function register according to the panel that we're driving.  We've
done this in the driver by read-modify-writing the register, which
may cause problems with races.  Fix this with a minimal change.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index d1d97cab24c8..b644f0f1268c 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -761,8 +761,19 @@ 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);
 	}
 }
 

From 9bb13eed37cc17fd176346c2866e2584772953bb Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Wed, 18 Jan 2012 13:47:14 +0000
Subject: [PATCH 088/115] FB: sa11x0: fix shannon GPSR/GPCR accesses

The GPIO set and clear registers should only be written, rather than
read, modified, and written.  A read-modify-write will have undesired
side effects.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/video/sa1100fb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index b644f0f1268c..f3f55eb61ca1 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -798,7 +798,7 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 
 	if (machine_is_shannon()) {
 		GPDR |= SHANNON_GPIO_DISP_EN;
-		GPSR |= SHANNON_GPIO_DISP_EN;
+		GPSR = SHANNON_GPIO_DISP_EN;
 	}
 
 	dev_dbg(fbi->dev, "DBAR1 = 0x%08lx\n", DBAR1);
@@ -816,7 +816,7 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 	dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
 	if (machine_is_shannon()) {
-		GPCR |= SHANNON_GPIO_DISP_EN;
+		GPCR = SHANNON_GPIO_DISP_EN;
 	}	
 
 	set_current_state(TASK_UNINTERRUPTIBLE);

From 00d94979c37fcba3486e9cc76a2eee750172a6a4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Wed, 18 Jan 2012 13:51:04 +0000
Subject: [PATCH 089/115] FB: sa11x0: convert shannon display enable accesses
 to use GPIO subsystem

Rather than accessing GPSR and GPCR directly, use the GPIO subsystem
instead.

Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/include/mach/shannon.h |  2 +-
 drivers/video/sa1100fb.c                    | 24 ++++++++++++++-------
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/shannon.h b/arch/arm/mach-sa1100/include/mach/shannon.h
index ec27d6e12140..a0d1114c45ed 100644
--- a/arch/arm/mach-sa1100/include/mach/shannon.h
+++ b/arch/arm/mach-sa1100/include/mach/shannon.h
@@ -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
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index f3f55eb61ca1..379b2c5000a3 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -173,6 +173,7 @@
 #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>
@@ -796,10 +797,8 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 	DBAR2 = fbi->dbar2;
 	LCCR0 |= LCCR0_LEN;
 
-	if (machine_is_shannon()) {
-		GPDR |= SHANNON_GPIO_DISP_EN;
-		GPSR = SHANNON_GPIO_DISP_EN;
-	}
+	if (machine_is_shannon())
+		gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
 
 	dev_dbg(fbi->dev, "DBAR1 = 0x%08lx\n", DBAR1);
 	dev_dbg(fbi->dev, "DBAR2 = 0x%08lx\n", DBAR2);
@@ -815,9 +814,8 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 
 	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);
@@ -1230,6 +1228,13 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 		goto failed;
 	}
 
+	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
 	 * descriptors are correctly initialised.
@@ -1240,7 +1245,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;
@@ -1252,6 +1257,9 @@ 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:

From 7cb66dcc828662c8cacb74af08478433cef102b1 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 21 Feb 2012 12:15:09 +0000
Subject: [PATCH 090/115] FB: sa11x0: convert to use platform resource and
 ioremap()

Convert the sa11x0 framebuffer driver to obtain the base address of its
hardware registers from the platform resources, and ioremap this rather
than relying on the static mappings.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/include/mach/SA-1100.h | 10 ---
 drivers/video/sa1100fb.c                    | 68 +++++++++++++--------
 drivers/video/sa1100fb.h                    | 11 ++++
 3 files changed, 54 insertions(+), 35 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h
index bae8296f5dbf..3a4d4e067ed8 100644
--- a/arch/arm/mach-sa1100/include/mach/SA-1100.h
+++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h
@@ -1903,16 +1903,6 @@
 #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/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 379b2c5000a3..b6325848ad61 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -705,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;
@@ -789,28 +792,29 @@ 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;
+	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%08lx\n", DBAR1);
-	dev_dbg(fbi->dev, "DBAR2 = 0x%08lx\n", DBAR2);
-	dev_dbg(fbi->dev, "LCCR0 = 0x%08lx\n", LCCR0);
-	dev_dbg(fbi->dev, "LCCR1 = 0x%08lx\n", LCCR1);
-	dev_dbg(fbi->dev, "LCCR2 = 0x%08lx\n", LCCR2);
-	dev_dbg(fbi->dev, "LCCR3 = 0x%08lx\n", LCCR3);
+	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;
 
 	dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
@@ -820,9 +824,14 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 	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);
@@ -834,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;
 }
 
@@ -1198,6 +1208,7 @@ static struct sa1100fb_info * __devinit 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) {
@@ -1205,11 +1216,12 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 		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);
@@ -1217,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)
@@ -1263,9 +1279,11 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
  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;
 }
 
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index e968e1d69520..fc5d4292fad6 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -10,6 +10,16 @@
  * for more details.
  */
 
+#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 {
 	unsigned long lccr0;
@@ -22,6 +32,7 @@ struct sa1100fb_info {
 	struct fb_info		fb;
 	struct device		*dev;
 	const struct sa1100fb_rgb *rgb[NR_RGB];
+	void __iomem		*base;
 
 	/*
 	 * These are the addresses we mapped

From 6365bead25efc84a4cf4aa9b0a7638f8a970cdff Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 9 Jan 2012 21:44:07 +0000
Subject: [PATCH 091/115] DMA: sa11x0: add SA-11x0 DMA driver

Add support for the SA-11x0 DMA driver, which replaces the private
API version in arch/arm/mach-sa1100/dma.c.

We model this as a set of virtual DMA channels, one for each request
signal, and assign the virtual DMA channel to a physical DMA channel
when there is work to be done.  This allows DMA users to claim their
channels, and hold them while not in use, without affecting the
availability of the physical channels.

Another advantage over this approach, compared to the private version,
is that a channel can be reconfigured on the fly without having to
release and re-request it - which for the IrDA driver, allows us to
use DMA for SIR mode transmit without eating up three physical
channels.  As IrDA is half-duplex, we actually only need one physical
channel, and this architecture allows us to achieve that.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/Kconfig        |    9 +
 drivers/dma/Makefile       |    1 +
 drivers/dma/sa11x0-dma.c   | 1109 ++++++++++++++++++++++++++++++++++++
 include/linux/sa11x0-dma.h |   24 +
 4 files changed, 1143 insertions(+)
 create mode 100644 drivers/dma/sa11x0-dma.c
 create mode 100644 include/linux/sa11x0-dma.h

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index f1a274994bb1..4a6c46dea8a0 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -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
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 009a222e8283..86b795baba98 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -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
index 000000000000..16a6b48883cf
--- /dev/null
+++ b/drivers/dma/sa11x0-dma.c
@@ -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");
diff --git a/include/linux/sa11x0-dma.h b/include/linux/sa11x0-dma.h
new file mode 100644
index 000000000000..65839a58b8e5
--- /dev/null
+++ b/include/linux/sa11x0-dma.h
@@ -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

From 7931d92f4f38100061cf6b8a9737967057f94871 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 9 Jan 2012 21:45:51 +0000
Subject: [PATCH 092/115] ARM: sa11x0: add SA-11x0 DMA device

Add sa11x0 DMA platform device and resources to the list of
generic platform devices for SA11x0 machines.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/generic.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index bb10ee2cb89f..52ea6229818f 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -14,6 +14,7 @@
 #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>
@@ -350,6 +351,29 @@ static struct platform_device sa11x0rtc_device = {
 	.id		= -1,
 };
 
+static struct resource sa11x0dma_resources[] = {
+	DEFINE_RES_MEM(__PREG(DDAR(0)), 6 * DMASp),
+	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,
@@ -358,6 +382,7 @@ static struct platform_device *sa11x0_devices[] __initdata = {
 	&sa11x0pcmcia_device,
 	&sa11x0fb_device,
 	&sa11x0rtc_device,
+	&sa11x0dma_device,
 };
 
 static int __init sa1100_init(void)

From bf95154ff6c84e04afd9ba7f2b54a4628beefdb9 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 13 Jan 2012 11:48:13 +0000
Subject: [PATCH 093/115] NET: sa11x0-ir: convert sa11x0-ir driver to use DMA
 engine API

Convert the sa11x0 IrDA driver to use the sa11x0 DMA engine driver
rather than our own platform specific DMA API.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/Kconfig     |   2 +-
 drivers/net/irda/sa1100_ir.c | 120 ++++++++++++++++++++++++++---------
 2 files changed, 92 insertions(+), 30 deletions(-)

diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index e535137eb2d0..468047866c8c 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -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"
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 9c748f38b9d5..620a48d00e2b 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -30,12 +30,13 @@
 #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 <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach/irda.h>
 
@@ -47,7 +48,8 @@ struct sa1100_buf {
 	struct device		*dev;
 	struct sk_buff		*skb;
 	struct scatterlist	sg;
-	dma_regs_t		*regs;
+	struct dma_chan		*chan;
+	dma_cookie_t		cookie;
 };
 
 struct sa1100_irda {
@@ -79,6 +81,75 @@ static int sa1100_irda_set_speed(struct sa1100_irda *, int);
 
 #define HPSIR_MAX_RXLEN		2047
 
+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.
  */
@@ -127,9 +198,9 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 	/*
 	 * Enable the DMA, receiver and receive interrupt.
 	 */
-	sa1100_clear_dma(si->dma_rx.regs);
-	sa1100_start_dma(si->dma_rx.regs, sg_dma_address(&si->dma_rx.sg),
-			 sg_dma_len(&si->dma_rx.sg));
+	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;
 }
 
@@ -326,8 +397,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 		return NETDEV_TX_OK;
 	}
 
-	sa1100_start_dma(si->dma_tx.regs, sg_dma_address(&si->dma_tx.sg),
-			 sg_dma_len(&si->dma_tx.sg));
+	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
@@ -345,7 +415,6 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
 static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
 {
 	struct sk_buff *skb = si->dma_rx.skb;
-	dma_addr_t dma_addr;
 	unsigned int len, stat, data;
 
 	if (!skb) {
@@ -356,8 +425,7 @@ 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->dma_rx.regs);
-	len = dma_addr - sg_dma_address(&si->dma_rx.sg);
+	len = sa1100_irda_dma_xferred(&si->dma_rx);
 	if (len > HPSIR_MAX_RXLEN)
 		len = HPSIR_MAX_RXLEN;
 	dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
@@ -421,7 +489,7 @@ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_ird
 	/*
 	 * Stop RX DMA
 	 */
-	sa1100_stop_dma(si->dma_rx.regs);
+	dmaengine_pause(si->dma_rx.chan);
 
 	/*
 	 * Framing error - we throw away the packet completely.
@@ -476,11 +544,9 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 	case 57600:	case 115200:
 		brd = 3686400 / (16 * speed) - 1;
 
-		/*
-		 * Stop the receive DMA.
-		 */
+		/* Stop the receive DMA, and configure transmit. */
 		if (IS_FIR(si))
-			sa1100_stop_dma(si->dma_rx.regs);
+			dmaengine_terminate_all(si->dma_rx.chan);
 
 		local_irq_save(flags);
 
@@ -698,8 +764,8 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si)
 	/*
 	 * Stop all DMA activity.
 	 */
-	sa1100_stop_dma(si->dma_rx.regs);
-	sa1100_stop_dma(si->dma_tx.regs);
+	dmaengine_terminate_all(si->dma_rx.chan);
+	dmaengine_terminate_all(si->dma_tx.chan);
 
 	/* Disable the port. */
 	Ser2UTCR3 = 0;
@@ -716,20 +782,16 @@ static int sa1100_irda_start(struct net_device *dev)
 
 	si->speed = 9600;
 
-	err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
-				 NULL, NULL, &si->dma_rx.regs);
+	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_firtxdma_irq, dev,
-				 &si->dma_tx.regs);
+	err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
+				&sa1100_irda_sir_tx);
 	if (err)
 		goto err_tx_dma;
 
-	si->dma_rx.dev = si->dev;
-	si->dma_tx.dev = si->dev;
-
 	/*
 	 * Setup the serial port for the specified speed.
 	 */
@@ -764,9 +826,9 @@ err_irlap:
 	si->open = 0;
 	sa1100_irda_shutdown(si);
 err_startup:
-	sa1100_free_dma(si->dma_tx.regs);
+	dma_release_channel(si->dma_tx.chan);
 err_tx_dma:
-	sa1100_free_dma(si->dma_rx.regs);
+	dma_release_channel(si->dma_rx.chan);
 err_rx_dma:
 	return err;
 }
@@ -810,8 +872,8 @@ static int sa1100_irda_stop(struct net_device *dev)
 	/*
 	 * Free resources
 	 */
-	sa1100_free_dma(si->dma_tx.regs);
-	sa1100_free_dma(si->dma_rx.regs);
+	dma_release_channel(si->dma_tx.chan);
+	dma_release_channel(si->dma_rx.chan);
 	free_irq(dev->irq, dev);
 
 	sa1100_set_power(si, 0);

From d138dacb4b8255c02e4380ce2aadab758a99d2c1 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 13 Jan 2012 11:50:03 +0000
Subject: [PATCH 094/115] NET: sa11x0-ir: add DMA support for SIR transmit mode

As the DMA engine API allows DMA channels to be reconfigured on the
fly, we can now support switching the DMA channel configuration to
support SIR transmit DMA without needing to claim an additional
physical DMA channel - thereby using up half the DMA channels just
for one driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/irda/sa1100_ir.c | 105 ++++++++++++++++++++---------------
 1 file changed, 60 insertions(+), 45 deletions(-)

diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 620a48d00e2b..a0d1913a58d3 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -81,6 +81,13 @@ static int sa1100_irda_set_speed(struct sa1100_irda *, int);
 
 #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),
@@ -215,6 +222,36 @@ static void sa1100_irda_check_speed(struct sa1100_irda *si)
 /*
  * HP-SIR format support.
  */
+static void sa1100_irda_sirtxdma_irq(void *id)
+{
+	struct net_device *dev = id;
+	struct sa1100_irda *si = netdev_priv(dev);
+
+	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;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
+
+	/* We need to ensure that the transmitter has finished. */
+	do
+		rmb();
+	while (Ser2UTSR1 & UTSR1_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;
+
+	sa1100_irda_check_speed(si);
+
+	/* I'm hungry! */
+	netif_wake_queue(dev);
+}
+
 static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	struct sa1100_irda *si)
 {
@@ -222,14 +259,22 @@ static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
 	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 characters received.
-	 */
-	Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
+	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;
+	}
 
-	dev_kfree_skb(skb);
+	sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, 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 NETDEV_TX_OK;
 }
@@ -288,43 +333,6 @@ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_ird
 
 	}
 
-	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);
-
-		if (si->tx_buff.len == 0) {
-			dev->stats.tx_packets++;
-			dev->stats.tx_bytes += si->tx_buff.data -
-					      si->tx_buff.head;
-
-			/*
-			 * We need to ensure that the transmitter has
-			 * finished.
-			 */
-			do
-				rmb();
-			while (Ser2UTSR1 & UTSR1_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;
-
-			sa1100_irda_check_speed(si);
-
-			/* I'm hungry! */
-			netif_wake_queue(dev);
-		}
-	}
-
 	return IRQ_HANDLED;
 }
 
@@ -545,8 +553,11 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 		brd = 3686400 / (16 * speed) - 1;
 
 		/* Stop the receive DMA, and configure transmit. */
-		if (IS_FIR(si))
+		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);
 
@@ -574,6 +585,10 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 		break;
 
 	case 4000000:
+		if (!IS_FIR(si))
+			dmaengine_slave_config(si->dma_tx.chan,
+						&sa1100_irda_fir_tx);
+
 		local_irq_save(flags);
 
 		Ser2HSSR0 = 0xff;

From 07be45f57ebe037977c8033a008e9012617b1915 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 13:34:21 +0000
Subject: [PATCH 095/115] ARM: sa1111: provide a generic way to prevent devices
 from registering

Some platforms don't want certain devices to be registered, because,
eg, the interface is not wired.  Provide a way for platforms to
prevent various devices from being registered via a devid bitmask in
the platform data.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c               | 7 ++-----
 arch/arm/include/asm/hardware/sa1111.h | 1 +
 arch/arm/mach-pxa/lubbock.c            | 1 +
 arch/arm/mach-sa1100/badge4.c          | 1 +
 arch/arm/mach-sa1100/jornada720.c      | 1 +
 arch/arm/mach-sa1100/neponset.c        | 1 +
 6 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 4bdf1bb283dc..17694cf64aa6 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -833,11 +833,8 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 	g_sa1111 = sachip;
 
 	has_devs = ~0;
-	if (machine_is_assabet() || machine_is_jornada720() ||
-	    machine_is_badge4())
-		has_devs &= ~SA1111_DEVID_PS2_MSE;
-	else
-		has_devs &= ~SA1111_DEVID_SAC;
+	if (pd)
+		has_devs &= ~pd->disable_devs;
 
 	for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
 		if (sa1111_devices[i].devid & has_devs)
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 37ad29d482f4..74afe20fffff 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -584,6 +584,7 @@ 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);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6ebd276aebeb..6bb3f47b1f14 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -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 = {
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index d84924993bad..8fb80f02c2a9 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -66,6 +66,7 @@ static void badge4_sa1111_disable(void *data, unsigned devid)
 
 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,
 };
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index ee121d6f0480..dcd6d026aa68 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -211,6 +211,7 @@ static struct resource sa1111_resources[] = {
 
 static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= IRQ_BOARD_END,
+	.disable_devs	= SA1111_DEVID_PS2_MSE,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b4fa53a1427e..b40a7192f09f 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -242,6 +242,7 @@ static struct resource sa1111_resources[] = {
 
 static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= IRQ_BOARD_END,
+	.disable_devs	= SA1111_DEVID_PS2_MSE,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;

From 6995f5b007c6b774e7d0c7528ced171145c03a09 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 14:28:25 +0000
Subject: [PATCH 096/115] ARM: sa1111: delete unused physical GPIO register
 definitions

Get rid of the unused GPIO register definitions - we access GPIO
registers through the base + offset method, and having the phys
address definitions is unnecessary duplication.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/sa1111.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 74afe20fffff..5ba2e13ed2b6 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -327,22 +327,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)

From 4f8d9cae15b5b5c89ec17c8168215aa06a5c9b2c Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 11:29:43 +0000
Subject: [PATCH 097/115] ARM: sa1111: move PS/2 interface register definitions
 to sa1111p2.c

Move the PS/2 interface register definitions into the driver, rather
than keeping them in a common location.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/sa1111.h | 39 +------------------
 drivers/input/serio/sa1111ps2.c        | 52 ++++++++++++++++++--------
 2 files changed, 37 insertions(+), 54 deletions(-)

diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 5ba2e13ed2b6..dc15bf8ff39d 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -409,47 +409,10 @@
 #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
  *
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index ad7d23b5c6fe..5ebabe3fc845 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 @@ 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]);
@@ -151,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;
 }
 
@@ -159,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]);
 
@@ -179,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;
 	}
 }
@@ -189,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);
 }
 
@@ -224,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;
 }
@@ -278,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.

From ea8c00ac18198763bceb7ca53d26df4aa8d3c414 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 11:32:09 +0000
Subject: [PATCH 098/115] ARM: sa1111: move PCMCIA interface register
 definitions to sa1111_generic.c

Move the PCMCIA interface register definitions into the driver, rather
than keeping them in a common place.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/sa1111.h | 45 ++------------------------
 drivers/pcmcia/sa1111_generic.c        | 44 ++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 48 deletions(-)

diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index dc15bf8ff39d..29e3e5673883 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -413,50 +413,9 @@
 #define SA1111_KBD		0x0a00
 #define SA1111_MSE		0x0c00
 
-/*
- * PCMCIA Interface
- *
- * Registers
- *    PCSR	Status Register
- *    PCCR	Control Register
- *    PCSSR	Sleep State Register
- */
+/* PCMCIA Interface */
+#define SA1111_PCMCIA		0x1600
 
-#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)
 
 
 
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 0735c3e6a8b0..33568e18998b 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 @@ 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;
@@ -187,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);

From 2213536d78a2ed96e870396b06ee53f4a54a1e42 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon, 16 Jan 2012 11:37:03 +0000
Subject: [PATCH 099/115] ARM: sa1111: move USB interface register definitions
 to ohci-sa1111.c

Move the USB interface register definitions into the driver, rather
than keeping them in a common place.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/sa1111.h | 26 +----------------------
 drivers/usb/host/ohci-sa1111.c         | 29 +++++++++++++++++++++-----
 2 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 29e3e5673883..7c2bbc7f0be1 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -132,33 +132,9 @@
 #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
  *
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 48300080433c..585e53eabff6 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -22,6 +22,25 @@
 #error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
 #endif
 
+#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)
+
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
@@ -45,7 +64,7 @@ static int 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
@@ -54,7 +73,7 @@ static int sa1111_start_hc(struct sa1111_dev *dev)
 	ret = sa1111_enable_device(dev);
 	if (ret == 0) {
 		udelay(11);
-		sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
+		sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
 	}
 
 	return ret;
@@ -69,9 +88,9 @@ static void sa1111_stop_hc(struct sa1111_dev *dev)
 	/*
 	 * 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.
@@ -85,7 +104,7 @@ static void sa1111_stop_hc(struct sa1111_dev *dev)
 #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,
 	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),

From 09a2ba2fa0eba3da747db860ac1c8c0956665316 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 09:31:31 +0000
Subject: [PATCH 100/115] ARM: sa1111: register sa1111 devices with dmabounce
 in bus notifier

Use the bus notifier to register sa1111 devices with dmabounce, rather
than after the device has been registered, potentially racing with
driver binding.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 129 ++++++++++++++++++++++-----------------
 1 file changed, 74 insertions(+), 55 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 17694cf64aa6..7b4351b28a5e 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -603,36 +603,6 @@ 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);
@@ -660,7 +630,6 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 	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);
@@ -671,6 +640,16 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 	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,
+	 * 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;
+		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",
@@ -680,36 +659,12 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 		goto out;
 	}
 
-
 	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:
 	return ret;
 }
 
@@ -1411,9 +1366,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;
@@ -1422,6 +1438,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);
 }
 

From 21d1c7702e74337717a1133fe8665f6591768581 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 10:22:49 +0000
Subject: [PATCH 101/115] ARM: sa1111: only setup DMA for DMA capable devices

It's pointless registering the PS/2 interfaces with the dmabounce code
when there's no DMA support for these in hardware, so only setup the
DMA masks for two subdevices which support DMA - the OHCI and SAC.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 7b4351b28a5e..d78499f84bd1 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -121,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];
 };
@@ -129,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,
@@ -142,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,
@@ -641,10 +644,10 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 		dev->irq[i] = sachip->irq_base + info->irq[i];
 
 	/*
-	 * 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;

From 924e1d4910a1f7d53f949a92a5d7793e572bb21d Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 10:20:00 +0000
Subject: [PATCH 102/115] ARM: sa1111: cleanup sub-device registration and
 unregistration

Move the releasing of resources out of the release function - this
allows a cleaner and more conventional arrangement of the registration
failure paths and a saner unregistration process for these devices.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index d78499f84bd1..8d86338a54ca 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -610,7 +610,6 @@ static void sa1111_dev_release(struct device *_dev)
 {
 	struct sa1111_dev *dev = SA1111_DEV(_dev);
 
-	release_resource(&dev->res);
 	kfree(dev);
 }
 
@@ -625,9 +624,10 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 	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;
@@ -657,17 +657,19 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 	if (ret) {
 		printk("SA1111: 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_register(&dev->dev);
-	if (ret) {
-		release_resource(&dev->res);
-		kfree(dev);
-	}
+	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;
 }
 
@@ -813,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;
 }
 

From 22eeaff367ac85a09643b2b8a5af064ec8773f63 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 10:28:09 +0000
Subject: [PATCH 103/115] ARM: sa1111: use dev_err() rather than printk()

Use dev_err() to report device specific errors rather than printk().

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/common/sa1111.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 8d86338a54ca..9173d112ea01 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -655,7 +655,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
 
 	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);
 		goto err_resource;
 	}

From 876c1f27852ff1e45e1164da15847d3b25600160 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sun, 29 Jan 2012 10:37:36 +0000
Subject: [PATCH 104/115] ARM: sa11x0: don't static map sa1111

The sa1111 support will ioremap() the device; there is no need for
platforms to setup a static mapping for this.  Remove the static
mapping for this device from badge4, jornada720 and neponset.

Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/badge4.c     | 5 -----
 arch/arm/mach-sa1100/jornada720.c | 5 -----
 arch/arm/mach-sa1100/neponset.c   | 5 -----
 3 files changed, 15 deletions(-)

diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index 8fb80f02c2a9..645ffa1ddc7c 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -285,11 +285,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
 	}
 };
 
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index dcd6d026aa68..5d2ceb40dac9 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -285,11 +285,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
 	}
 };
 
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b40a7192f09f..290afedde749 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -333,11 +333,6 @@ static struct map_desc neponset_io_desc[] __initdata = {
 		.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
 	}
 };
 

From 9cb0f819eb88f573703e9a73d9883febcfcfa1c3 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 10:37:46 +0000
Subject: [PATCH 105/115] USB: sa1111: sparse and checkpatch cleanups

Clean up the ohci-sa1111 driver formatting to be more compliant with
current standards, and add 'static' to various function definitions
to avoid sparse complaints about undeclared functions.  Remove the
unnecessary local declaration of 'usb_disabled', which can be found
instead in linux/usb.h.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/usb/host/ohci-sa1111.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 585e53eabff6..50ebeb310fda 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -41,8 +41,6 @@
 #define USB_STATUS_NHCIMFCLR      (1 << 10)
 #define USB_STATUS_USBPWRSENSE    (1 << 11)
 
-extern int usb_disabled(void);
-
 /*-------------------------------------------------------------------------*/
 
 static int sa1111_start_hc(struct sa1111_dev *dev)
@@ -82,6 +80,7 @@ static int sa1111_start_hc(struct sa1111_dev *dev)
 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__);
 
@@ -106,7 +105,7 @@ 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,
+	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 "),
@@ -131,15 +130,16 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label)
  *
  * 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 usb_hcd_sa1111_probe(const struct hc_driver *driver,
+	struct sa1111_dev *dev)
 {
 	struct usb_hcd *hcd;
 	int retval;
 
-	hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+	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);
 
@@ -148,6 +148,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
 		retval = -EBUSY;
 		goto err1;
 	}
+
 	hcd->regs = dev->mapbase;
 
 	ret = sa1111_start_hc(dev);
@@ -180,9 +181,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
  * 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)
+static void usb_hcd_sa1111_remove(struct usb_hcd *hcd, struct sa1111_dev *dev)
 {
 	usb_remove_hcd(hcd);
 	sa1111_stop_hc(dev);
@@ -192,18 +192,19 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
 
 /*-------------------------------------------------------------------------*/
 
-static int __devinit
-ohci_sa1111_start (struct usb_hcd *hcd)
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
 {
-	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	int		ret;
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int ret;
 
-	if ((ret = ohci_init(ohci)) < 0)
+	ret = ohci_init(ohci);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = ohci_run (ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
-		ohci_stop (hcd);
+	ret = ohci_run(ohci);
+	if (ret < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
 		return ret;
 	}
 	return 0;

From 3f878dbcd6ca4bbdbac0a1380d25161a7ba610ab Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 10:39:57 +0000
Subject: [PATCH 106/115] USB: sa1111: get rid of nasty printk(KERN_DEBUG "%s:
 ...", __FILE__)

Use dev_dbg() instead, it's more friendly.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/usb/host/ohci-sa1111.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 50ebeb310fda..e797f18acb33 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -48,8 +48,7 @@ static int sa1111_start_hc(struct sa1111_dev *dev)
 	unsigned int usb_rst = 0;
 	int ret;
 
-	printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
-	       __FILE__);
+	dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
 
 	if (machine_is_xp860() ||
 	    machine_has_neponset() ||
@@ -81,8 +80,7 @@ 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.

From 132db99ae2c6f6a586fc932507fcf4484d90c8fa Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 10:52:34 +0000
Subject: [PATCH 107/115] USB: sa1111: reorganize ohci-sa1111.c

Combine usb_hcd_sa1111_probe() and ohci_hcd_sa1111_drv_probe(), doing
the same for the remove methods.

Move sa1111_start_hc and sa1111_stop_hc to be located next to these
the probe/release functions, as they're only called from them.

Get rid of the /*----*/ breaker lines.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/usb/host/ohci-sa1111.c | 227 ++++++++++++++-------------------
 1 file changed, 93 insertions(+), 134 deletions(-)

diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index e797f18acb33..83f3a40db538 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -41,7 +41,78 @@
 #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 int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	ret = ohci_init(ohci);
+	if (ret < 0)
+		return ret;
+
+	ret = ohci_run(ohci);
+	if (ret < 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 sa1111_start_hc(struct sa1111_dev *dev)
 {
@@ -95,46 +166,21 @@ static void sa1111_stop_hc(struct sa1111_dev *dev)
 	sa1111_disable_device(dev);
 }
 
-
-/*-------------------------------------------------------------------------*/
-
-#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
-
-/*-------------------------------------------------------------------------*/
-
-/* 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.
  */
-static 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;
 
@@ -143,7 +189,7 @@ static int usb_hcd_sa1111_probe(const struct hc_driver *driver,
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 		dbg("request_mem_region failed");
-		retval = -EBUSY;
+		ret = -EBUSY;
 		goto err1;
 	}
 
@@ -155,120 +201,34 @@ static int usb_hcd_sa1111_probe(const struct hc_driver *driver,
 
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	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.
  */
-static 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;
-
-	ret = ohci_init(ohci);
-	if (ret < 0)
-		return ret;
-
-	ret = ohci_run(ohci);
-	if (ret < 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)
-{
-	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
-
-	usb_hcd_sa1111_remove(hcd, dev);
 	return 0;
 }
 
@@ -278,7 +238,6 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
 		.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,
 };
-

From 846a70487e2a0e5045c6a428a0969d3e0490b359 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 11:10:20 +0000
Subject: [PATCH 108/115] USB: sa1111: add OHCI shutdown methods

Add OHCI shutdown methods to cleanly shutdown the OHCI controller on
system shutdowns and reboots.  This avoids the controller continuing
to run should be soft-reboot the platform, potentially scribbling
over system memory.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/usb/host/ohci-sa1111.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 83f3a40db538..95c3f0fb48d3 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -89,6 +89,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
 	 */
 	.start =		ohci_sa1111_start,
 	.stop =			ohci_stop,
+	.shutdown =		ohci_shutdown,
 
 	/*
 	 * managing i/o requests and associated device resources
@@ -232,6 +233,16 @@ static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 	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",
@@ -240,4 +251,5 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
 	.devid		= SA1111_DEVID_USB,
 	.probe		= ohci_hcd_sa1111_probe,
 	.remove		= ohci_hcd_sa1111_remove,
+	.shutdown	= ohci_hcd_sa1111_shutdown,
 };

From 81e6ca3eb74d6bdbab181dd2db378f49f76f0d97 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 26 Jan 2012 11:45:27 +0000
Subject: [PATCH 109/115] USB: sa1111: add hcd .reset method

Add the .reset method to the HCD, and update the .start method
accordingly for this change.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/usb/host/ohci-sa1111.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 95c3f0fb48d3..e1004fb37bd9 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -55,22 +55,25 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label)
 }
 #endif
 
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
+
 static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
 	int ret;
 
-	ret = ohci_init(ohci);
-	if (ret < 0)
-		return ret;
-
 	ret = ohci_run(ohci);
 	if (ret < 0) {
-		err("can't start %s", hcd->self.bus_name);
+		ohci_err(ohci, "can't start\n");
 		ohci_stop(hcd);
-		return ret;
 	}
-	return 0;
+	return ret;
 }
 
 static const struct hc_driver ohci_sa1111_hc_driver = {
@@ -87,6 +90,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
 	/*
 	 * basic lifecycle operations
 	 */
+	.reset =		ohci_sa1111_reset,
 	.start =		ohci_sa1111_start,
 	.stop =			ohci_stop,
 	.shutdown =		ohci_shutdown,
@@ -200,8 +204,6 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
 	if (ret)
 		goto err2;
 
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
 	ret = usb_add_hcd(hcd, dev->irq[1], 0);
 	if (ret == 0)
 		return ret;

From 9903405be58c481e926d485b8fe50a1b9e4048be Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 13 Jan 2012 12:07:24 +0000
Subject: [PATCH 110/115] ARM: sa11x0: remove old SoC private DMA driver

Now that all users are converted over to using the DMA engine API,
we can get rid of the old platform dependent DMA driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/Makefile           |   2 +-
 arch/arm/mach-sa1100/dma.c              | 348 ------------------------
 arch/arm/mach-sa1100/include/mach/dma.h | 117 --------
 3 files changed, 1 insertion(+), 466 deletions(-)
 delete mode 100644 arch/arm/mach-sa1100/dma.c
 delete mode 100644 arch/arm/mach-sa1100/include/mach/dma.h

diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index ed7408d3216c..60b97ec01676 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -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-  :=
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
deleted file mode 100644
index ad660350c296..000000000000
--- a/arch/arm/mach-sa1100/dma.c
+++ /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);
-
diff --git a/arch/arm/mach-sa1100/include/mach/dma.h b/arch/arm/mach-sa1100/include/mach/dma.h
deleted file mode 100644
index dda1b351310d..000000000000
--- a/arch/arm/mach-sa1100/include/mach/dma.h
+++ /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 */

From c21320104ec5b8ffa0d62865d43ee56cbfccc2de Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Sat, 14 Jan 2012 16:57:02 +0000
Subject: [PATCH 111/115] ARM: sa11x0: remove unused DMA controller definitions

Remove the new unused DMA controller definitions from mach/SA-1100.h.
These are now private to the SA-11x0 DMA engine driver and contained
within the driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/generic.c              |   2 +-
 arch/arm/mach-sa1100/include/mach/SA-1100.h | 219 +-------------------
 2 files changed, 3 insertions(+), 218 deletions(-)

diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 1752686e9abc..01a20ea35b53 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -291,7 +291,7 @@ static struct platform_device sa11x0rtc_device = {
 };
 
 static struct resource sa11x0dma_resources[] = {
-	DEFINE_RES_MEM(__PREG(DDAR(0)), 6 * DMASp),
+	DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
 	DEFINE_RES_IRQ(IRQ_DMA0),
 	DEFINE_RES_IRQ(IRQ_DMA1),
 	DEFINE_RES_IRQ(IRQ_DMA2),
diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h
index bae8296f5dbf..335a1ff21faf 100644
--- a/arch/arm/mach-sa1100/include/mach/SA-1100.h
+++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h
@@ -1590,224 +1590,9 @@
 
 /*
  * 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
 
 
 /*

From 905cdc88b6eb9074c203be4883bce6c170757338 Mon Sep 17 00:00:00 2001
From: Rob Herring <rob.herring@calxeda.com>
Date: Thu, 23 Feb 2012 14:27:58 +0100
Subject: [PATCH 112/115] ARM: 7340/1: rtc: sa1100: include mach/irqs.h instead
 of asm/irq.h

Since asm/irq.h may not include mach/irqs.h, include mach/irqs.h directly.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/rtc/rtc-sa1100.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index cb9a585312cc..e8f1adde4d82 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -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>

From 3638dd2b45ceac2e9526f0ee83b0923db3546979 Mon Sep 17 00:00:00 2001
From: Rob Herring <rob.herring@calxeda.com>
Date: Thu, 23 Feb 2012 14:28:36 +0100
Subject: [PATCH 113/115] ARM: 7341/1: input: prepare jornada720 keyboard and
 ts for sa11x0 sparse irq

In preparation for sa11x0 sparse irq conversion, explicitly include
mach/irqs.h as it will not be included for sparse irq.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/input/keyboard/jornada720_kbd.c   | 1 +
 drivers/input/touchscreen/jornada720_ts.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index eeafc30b207b..9d639fa1afbd 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -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");
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index c3848ad2325b..d9be6eac99b1 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -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");

From f314f33be77d6a48ae19748e3dc4a6657042b525 Mon Sep 17 00:00:00 2001
From: Rob Herring <rob.herring@calxeda.com>
Date: Fri, 24 Feb 2012 00:06:51 +0100
Subject: [PATCH 114/115] ARM: 7342/2: sa1100: prepare for sparse irq
 conversion

In preparation to convert SA1100 to sparse irq, set .nr_irqs for each machine
and explicitly include mach/irqs.h as needed.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sa1100/assabet.c           | 3 ++-
 arch/arm/mach-sa1100/badge4.c            | 1 +
 arch/arm/mach-sa1100/cerf.c              | 3 ++-
 arch/arm/mach-sa1100/collie.c            | 3 ++-
 arch/arm/mach-sa1100/generic.c           | 4 +++-
 arch/arm/mach-sa1100/h3100.c             | 2 ++
 arch/arm/mach-sa1100/h3600.c             | 2 ++
 arch/arm/mach-sa1100/hackkit.c           | 6 ++++--
 arch/arm/mach-sa1100/include/mach/irqs.h | 2 ++
 arch/arm/mach-sa1100/irq.c               | 1 +
 arch/arm/mach-sa1100/jornada720.c        | 6 ++++--
 arch/arm/mach-sa1100/lart.c              | 2 ++
 arch/arm/mach-sa1100/nanoengine.c        | 2 ++
 arch/arm/mach-sa1100/neponset.c          | 1 +
 arch/arm/mach-sa1100/pleb.c              | 1 +
 arch/arm/mach-sa1100/shannon.c           | 2 ++
 arch/arm/mach-sa1100/simpad.c            | 5 +++--
 arch/arm/mach-sa1100/ssp.c               | 2 +-
 arch/arm/mach-sa1100/time.c              | 1 +
 drivers/gpio/gpio-sa1100.c               | 1 +
 drivers/tty/serial/sa1100.c              | 1 +
 21 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index e708a93a7ddb..375d3f779a88 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -25,7 +25,6 @@
 
 #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>
@@ -39,6 +38,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/assabet.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -534,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,
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index 5839c9d8bb92..8c805425b684 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -304,6 +304,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
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 8015604cfc22..4a61f60e0502 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -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>
 
@@ -30,6 +29,7 @@
 
 #include <mach/cerf.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
@@ -130,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,
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index d4339d639475..48885b7efd6b 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -33,7 +33,6 @@
 
 #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>
@@ -47,6 +46,7 @@
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -393,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/generic.c b/arch/arm/mach-sa1100/generic.c
index 97e9bdf7f297..b18470420d3e 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -23,12 +23,14 @@
 #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;
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
index f23e7d0b2fba..b2e8d0f418e0 100644
--- a/arch/arm/mach-sa1100/h3100.c
+++ b/arch/arm/mach-sa1100/h3100.c
@@ -21,6 +21,7 @@
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -105,6 +106,7 @@ static void __init h3100_mach_init(void)
 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,
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 2feac56ec90d..cb6659f294fe 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -21,6 +21,7 @@
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -155,6 +156,7 @@ static void __init h3600_mach_init(void)
 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,
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 37d381ad5464..5535475bf583 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -22,12 +22,10 @@
 #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"
 
 /**********************************************************************
@@ -194,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,
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index 9e07634a4670..0ad78218c9f3 100644
--- a/arch/arm/mach-sa1100/include/mach/irqs.h
+++ b/arch/arm/mach-sa1100/include/mach/irqs.h
@@ -82,3 +82,5 @@
 #else
 #define NR_IRQS			(IRQ_BOARD_START)
 #endif
+
+#define SA1100_NR_IRQS NR_IRQS
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 5d12a305f53e..516ccc25d7fd 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -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"
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 8be8130baf63..b7dcb1887aca 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -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"
 
 /*
@@ -344,6 +345,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,
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index 570f75fb73a2..eb6534e0b0d0 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -17,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"
 
@@ -143,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,
diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
index 3923911000de..8f6446b9f025 100644
--- a/arch/arm/mach-sa1100/nanoengine.c
+++ b/arch/arm/mach-sa1100/nanoengine.c
@@ -28,6 +28,7 @@
 
 #include <mach/hardware.h>
 #include <mach/nanoengine.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -107,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,
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 3297aa22cd77..b04a8f1928fc 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -21,6 +21,7 @@
 #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
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index ca5d33b6041a..1602575a0d5c 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -131,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,
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 08bb1228961f..ca8bf59b9047 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -21,6 +21,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/shannon.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -99,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,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 3da4c1f11cf5..3efae03cb3d7 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -7,7 +7,7 @@
 #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>
@@ -16,7 +16,6 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
@@ -27,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>
@@ -393,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,
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
index b20ff93b84a5..e22fca9ad5ec 100644
--- a/arch/arm/mach-sa1100/ssp.c
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -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
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 69e33535dee6..6af26e8d55e6 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -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)
 {
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 7eecf69362ee..8ea3b33d4b40 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -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)
 {
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index ef7a21a6a01b..2ca5959ec3fa 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -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 */

From 375dec92777c96015a13a23eaeb4f23281fb8662 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Thu, 23 Feb 2012 14:29:33 +0100
Subject: [PATCH 115/115] ARM: 7343/1: sa11x0: convert to sparse IRQ

Now that Neponset, UCB1x00 and SA1111 are all converted to use the IRQ
allocation interfaces, we can enable sparse IRQ support for SA11x0
platforms.
---
 arch/arm/Kconfig                         |  1 +
 arch/arm/mach-sa1100/badge4.c            |  1 -
 arch/arm/mach-sa1100/include/mach/irqs.h | 21 ++++++++++++---------
 arch/arm/mach-sa1100/jornada720.c        |  1 -
 arch/arm/mach-sa1100/neponset.c          |  1 -
 5 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a48aecc17eac..34aed718faed 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -760,6 +760,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.
 
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index 8c805425b684..e0f0c030258c 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -57,7 +57,6 @@ static void badge4_sa1111_disable(void *data, unsigned devid)
 }
 
 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,
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index 0ad78218c9f3..3790298b7142 100644
--- a/arch/arm/mach-sa1100/include/mach/irqs.h
+++ b/arch/arm/mach-sa1100/include/mach/irqs.h
@@ -71,16 +71,19 @@
 /*
  * 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
 
-#define SA1100_NR_IRQS NR_IRQS
+#ifndef NR_IRQS
+#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#endif
+#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index b7dcb1887aca..ca7a7e834720 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -195,7 +195,6 @@ static struct resource sa1111_resources[] = {
 };
 
 static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
 	.disable_devs	= SA1111_DEVID_PS2_MSE,
 };
 
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b04a8f1928fc..6c58f01b358a 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -229,7 +229,6 @@ static struct irq_chip nochip = {
 };
 
 static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
 	.disable_devs	= SA1111_DEVID_PS2_MSE,
 };