All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state
@ 2012-01-25 14:30 Russell King - ARM Linux
  2012-01-25 14:30 ` [PATCH 01/33] Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources." Russell King - ARM Linux
                   ` (34 more replies)
  0 siblings, 35 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 20, 2012 at 06:04:56PM +0000, Russell King - ARM Linux wrote:
> Samuel,
> 
> The following patch set restores the SA11x0 MCP and UCB1x00 drivers back
> to a working state, as tested on the Assabet.
> 
> The first two patches are the revert I requested.  The others fix a
> problem with the UCB1x00's use of genirq (it returns from its interrupt
> handler with IRQs enabled, which causes genirq to barf), and delete the
> SA11x0 specific DMA definitions and SA11x0 specific DMA header file
> from the driver.  That is in preparation for me removing the existing
> SA11x0 private DMA backend in favour of a DMA engine implementation.
> 
> As the DMA changes have dependencies in my tree (on which other changes
> then depend on) I can't see this being sanely split from my tree, so
> I'll request acks for these changes.
> 
> I'll plan to send the first three patches to Linus as part of my next
> 'fixes' push if you agree.

I've not heard anything back from anyone, so I'm going to assume that's
silent approval.

However, I've taken some time to replace some of the parts of the patches
which have had to be reverted, which are fully tested on my Assabet, and
to augment the patches to bring the driver up to speed with things like
genirq, sparse IRQ, mutexes rather than semaphores, etc.

So, in this replacement set, the first seven patches are bug fixes of
various kinds:

Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources."
Revert "ARM: sa11x0: Implement autoloading of codec and codec pdata for
MFD: mcp-core: fix complaints from the genirq layer
MFD: mcp-core: fix mcp_priv() to be more type safe
MFD: ucb1x00-core: fix missing restore of io output data on resume
MFD: ucb1x00-core: fix gpiolib direction_output handling
MFD: ucb1x00-ts: fix resume failure

these I believe need to go in for -rc.  My plan is to send them when I
sent the rest of the ARM fixes, either tonight or tomorrow night.

Following this is what I consider to be development on top of what was
in v3.2, and the work which Jochen produced:

MFD: mcp-core: sanitize host creation/removal
MFD: mcp-sa11x0: remove DMA initializers and variables
MFD: mcp-sa11x0: move setup of PPC unit out of mcp-sa11x0.c
MFD: mcp-sa11x0: add .owner initializer
MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform resources
MFD: mcp-sa11x0: convert to use dev_pm_ops
MFD: mcp-sa11x0: use _noirq resume methods
MFD: mcp/ucb1x00: separate ucb1x00 driver data from the MCP data
MFD: ucb1x00-ts: provide input layer with device parent
MFD: ucb1x00-core: get rid of mach/hardware.h include
MFD: ucb1x00-core: add handling for ucb1x00 reset
MFD: ucb1x00-core: add .owner initializer and module alias
MFD: ucb1x00-core: use mutexes instead of semaphores
MFD: ucb1x00-core: clean up device handling in probe
MFD: ucb1x00-core: add owner and dev initializers to gpio structure
MFD: ucb1x00-core: scan drivers in same order they're registered
MFD: ucb1x00-core: add missing ucb1x00_enable()/ucb1x00_disable()
MFD: ucb1x00-core: disable mcp clock when bus is not required
MFD: mcp-sa11x0: complain if mcp clock is left enabled
MFD: ucb1x00-core: convert to use dev_pm_ops
MFD: mcp-core: remove legacy driver suspend/resume methods
MFD: ucb1x00: convert to use genirq
MFD: ucb1x00-core: add wakeup support
ARM: sa11x0: add assabet ucb1x00 platform data
MFD: ucb1x00-assabet: add support for UCB1x00 GPIO switches
MFD: mcp-sa11x0/assabet: move assabet reset handling out of mcp-sa11x0.c

This is purposely ordered - eg, things like converting this to genirq
requires the PM stuff to be fixed first to ensure that the IRQ registers
are accessible when genirq wants to resume from system suspend.

I've kept the core changes first, and the platform changes (for the
Assabet) as the final three patches.

The work which was taken from Jochen's original patches is:

1. Move the PPC initialization out of the driver.  I put it in a common
   function so we don't have individual platforms implementing the same
   bit of code multiple times.

2. Adding .owner initializers to MCP driver structures.

3. Using platform resources for SA11x0 MCP interface base address.

4. Using separate driver_data to pass platform specifics to the UCB1x00
   driver, rather than embedding them in the MCP data structure.

There's further work to be done on this driver, namely:

1. Fixing its use of a class device.  This was originally done because it
   seemed to make sense back in the early days of the driver model.  I
   don't think it makes that much sense, and it gets in the way of proper
   wakeup support.

2. Wakeup support - provided the UCB codec is connected to a wakeup capable
   upstream IRQ, and the power is not removed from the codec during suspend
   modes, the UCB is perfectly capable of doing wakeup.  I have a small
   patch on top of this which allows the touchscreen to do exactly that.
   The Assabet buttons can also wake the system up but I've not tested that.
   There's no reason they can't other than just not setting the relevant
   flag in the gpio_keys data structure.

3. Module auto-loading - this doesn't make sense when genirq requires the
   core UCB1x00 module to be built-in to have access to the various IRQ
   functions.  It's probably unsafe on multiprocessor or preempt systems
   to have IRQ code unload once IRQ decoding handlers have been registered.

Diffstat:

 arch/arm/mach-sa1100/assabet.c          |   28 +-
 arch/arm/mach-sa1100/cerf.c             |   12 +-
 arch/arm/mach-sa1100/collie.c           |   15 +-
 arch/arm/mach-sa1100/generic.c          |   14 +-
 arch/arm/mach-sa1100/generic.h          |    1 +
 arch/arm/mach-sa1100/include/mach/mcp.h |    2 -
 arch/arm/mach-sa1100/lart.c             |   11 +-
 arch/arm/mach-sa1100/shannon.c          |   12 +-
 arch/arm/mach-sa1100/simpad.c           |   16 +-
 drivers/mfd/Kconfig                     |    5 +-
 drivers/mfd/mcp-core.c                  |  106 ++-----
 drivers/mfd/mcp-sa11x0.c                |  265 +++++++++---------
 drivers/mfd/ucb1x00-assabet.c           |   46 +++-
 drivers/mfd/ucb1x00-core.c              |  484 ++++++++++++++++---------------
 drivers/mfd/ucb1x00-ts.c                |   73 +++---
 include/linux/mfd/mcp.h                 |   22 +-
 include/linux/mfd/ucb1x00.h             |   41 ++--
 include/linux/mod_devicetable.h         |   11 -
 scripts/mod/file2alias.c                |   10 -
 19 files changed, 547 insertions(+), 627 deletions(-)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 01/33] Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources."
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
@ 2012-01-25 14:30 ` Russell King - ARM Linux
  2012-01-25 14:30 ` [PATCH 02/33] Revert "ARM: sa11x0: Implement autoloading of codec and codec pdata for mcp bus." Russell King - ARM Linux
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

This reverts commit af9081ae64b941d32239b947882cd59ba855c5db.

This revert is necessary to revert 5dd7bf59e0e8563265b3e5b33276099ef628fcc7.
---
 arch/arm/mach-sa1100/assabet.c |   11 ---
 arch/arm/mach-sa1100/cerf.c    |   10 ---
 arch/arm/mach-sa1100/collie.c  |   10 ---
 arch/arm/mach-sa1100/generic.c |    7 +--
 arch/arm/mach-sa1100/lart.c    |    9 --
 arch/arm/mach-sa1100/shannon.c |   10 ---
 arch/arm/mach-sa1100/simpad.c  |   10 ---
 drivers/mfd/mcp-sa11x0.c       |  162 +++++++++++++---------------------------
 8 files changed, 53 insertions(+), 176 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index ebafe8a..d8aa1c2 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -253,17 +253,6 @@ static void __init assabet_init(void)
 	sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
 			    ARRAY_SIZE(assabet_flash_resources));
 	sa11x0_register_irda(&assabet_irda_data);
-
-	/*
-	 * 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);
-
-	ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
 	sa11x0_register_mcp(&assabet_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index d12d0f4..fcadc4c 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -131,16 +131,6 @@ static void __init cerf_init(void)
 {
 	platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
 	sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
-
-	/*
-	 * 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);
-
 	sa11x0_register_mcp(&cerf_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index c483912..6b7c74b 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -357,16 +357,6 @@ static void __init collie_init(void)
 
 	sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
 			    ARRAY_SIZE(collie_flash_resources));
-
-	/*
-	 * 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);
-
 	sa11x0_register_mcp(&collie_mcp_data);
 
 	sharpsl_save_param();
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index e3a28ca..480d2ea 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -217,15 +217,10 @@ static struct platform_device sa11x0uart3_device = {
 static struct resource sa11x0mcp_resources[] = {
 	[0] = {
 		.start	= __PREG(Ser4MCCR0),
-		.end	= __PREG(Ser4MCCR0) + 0x1C - 1,
+		.end	= __PREG(Ser4MCCR0) + 0xffff,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= __PREG(Ser4MCCR1),
-		.end	= __PREG(Ser4MCCR1) + 0x4 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
 		.start	= IRQ_Ser4MCP,
 		.end	= IRQ_Ser4MCP,
 		.flags	= IORESOURCE_IRQ,
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index d117cea..48a8f4e 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -29,15 +29,6 @@ static struct mcp_plat_data lart_mcp_data = {
 
 static void __init lart_init(void)
 {
-	/*
-	 * 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);
-
 	sa11x0_register_mcp(&lart_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 748d344..3807c91 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -61,16 +61,6 @@ static struct mcp_plat_data shannon_mcp_data = {
 static void __init shannon_init(void)
 {
 	sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
-
-	/*
-	 * 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);
-
 	sa11x0_register_mcp(&shannon_mcp_data);
 }
 
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 458ecec..d9b765c 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -384,16 +384,6 @@ static int __init simpad_init(void)
 
 	sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
 			      ARRAY_SIZE(simpad_flash_resources));
-
-	/*
-	 * 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);
-
 	sa11x0_register_mcp(&simpad_mcp_data);
 
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 9adc2eb..da4e077 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -19,7 +19,6 @@
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mcp.h>
-#include <linux/io.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
@@ -27,19 +26,12 @@
 #include <asm/system.h>
 #include <mach/mcp.h>
 
-/* Register offsets */
-#define MCCR0	0x00
-#define MCDR0	0x08
-#define MCDR1	0x0C
-#define MCDR2	0x10
-#define MCSR	0x18
-#define MCCR1	0x00
+#include <mach/assabet.h>
+
 
 struct mcp_sa11x0 {
-	u32		mccr0;
-	u32		mccr1;
-	unsigned char	*mccr0_base;
-	unsigned char	*mccr1_base;
+	u32	mccr0;
+	u32	mccr1;
 };
 
 #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
@@ -47,25 +39,25 @@ struct mcp_sa11x0 {
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-	struct mcp_sa11x0 *priv = priv(mcp);
+	unsigned int mccr0;
 
 	divisor /= 32;
 
-	priv->mccr0 &= ~0x00007f00;
-	priv->mccr0 |= divisor << 8;
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+	mccr0 = Ser4MCCR0 & ~0x00007f00;
+	mccr0 |= divisor << 8;
+	Ser4MCCR0 = mccr0;
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-	struct mcp_sa11x0 *priv = priv(mcp);
+	unsigned int mccr0;
 
 	divisor /= 32;
 
-	priv->mccr0 &= ~0x0000007f;
-	priv->mccr0 |= divisor;
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+	mccr0 = Ser4MCCR0 & ~0x0000007f;
+	mccr0 |= divisor;
+	Ser4MCCR0 = mccr0;
 }
 
 /*
@@ -79,16 +71,12 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
 	int ret = -ETIME;
 	int i;
-	u32 mcpreg;
-	struct mcp_sa11x0 *priv = priv(mcp);
 
-	mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
-	__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
+	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
 
 	for (i = 0; i < 2; i++) {
 		udelay(mcp->rw_timeout);
-		mcpreg = __raw_readl(priv->mccr0_base + MCSR);
-		if (mcpreg & MCSR_CWC) {
+		if (Ser4MCSR & MCSR_CWC) {
 			ret = 0;
 			break;
 		}
@@ -109,18 +97,13 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
 	int ret = -ETIME;
 	int i;
-	u32 mcpreg;
-	struct mcp_sa11x0 *priv = priv(mcp);
 
-	mcpreg = reg << 17 | MCDR2_Rd;
-	__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
+	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
 
 	for (i = 0; i < 2; i++) {
 		udelay(mcp->rw_timeout);
-		mcpreg = __raw_readl(priv->mccr0_base + MCSR);
-		if (mcpreg & MCSR_CRC) {
-			ret = __raw_readl(priv->mccr0_base + MCDR2)
-				& 0xffff;
+		if (Ser4MCSR & MCSR_CRC) {
+			ret = Ser4MCDR2 & 0xffff;
 			break;
 		}
 	}
@@ -133,19 +116,13 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-	struct mcp_sa11x0 *priv = priv(mcp);
-
-	__raw_writel(-1, priv->mccr0_base + MCSR);
-	priv->mccr0 |= MCCR0_MCE;
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+	Ser4MCSR = -1;
+	Ser4MCCR0 |= MCCR0_MCE;
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-	struct mcp_sa11x0 *priv = priv(mcp);
-
-	priv->mccr0 &= ~MCCR0_MCE;
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+	Ser4MCCR0 &= ~MCCR0_MCE;
 }
 
 /*
@@ -165,9 +142,6 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	struct mcp_plat_data *data = pdev->dev.platform_data;
 	struct mcp *mcp;
 	int ret;
-	struct mcp_sa11x0 *priv;
-	struct resource *res_mem0, *res_mem1;
-	u32 size0, size1;
 
 	if (!data)
 		return -ENODEV;
@@ -175,59 +149,46 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	if (!data->codec)
 		return -ENODEV;
 
-	res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res_mem0)
-		return -ENODEV;
-	size0 = res_mem0->end - res_mem0->start + 1;
-
-	res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res_mem1)
-		return -ENODEV;
-	size1 = res_mem1->end - res_mem1->start + 1;
-
-	if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
+	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
 		return -EBUSY;
 
-	if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
-		ret = -EBUSY;
-		goto release;
-	}
-
 	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
 	if (!mcp) {
 		ret = -ENOMEM;
-		goto release2;
+		goto release;
 	}
 
-	priv = priv(mcp);
-
 	mcp->owner		= THIS_MODULE;
 	mcp->ops		= &mcp_sa11x0;
 	mcp->sclk_rate		= data->sclk_rate;
-	mcp->dma_audio_rd	= DDAR_DevAdd(res_mem0->start + MCDR0)
-				+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
-	mcp->dma_audio_wr	= DDAR_DevAdd(res_mem0->start + MCDR0)
-				+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
-	mcp->dma_telco_rd	= DDAR_DevAdd(res_mem0->start + MCDR1)
-				+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
-	mcp->dma_telco_wr	= DDAR_DevAdd(res_mem0->start + MCDR1)
-				+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+	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->codec		= data->codec;
 
 	platform_set_drvdata(pdev, mcp);
 
+	if (machine_is_assabet()) {
+		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.
 	 */
-	priv->mccr0_base = ioremap(res_mem0->start, size0);
-	priv->mccr1_base = ioremap(res_mem1->start, size1);
-
-	__raw_writel(-1, priv->mccr0_base + MCSR);
-	priv->mccr1 = data->mccr1;
-	priv->mccr0 = data->mccr0 | 0x7f7f;
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
-	__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
+	Ser4MCSR = -1;
+	Ser4MCCR1 = data->mccr1;
+	Ser4MCCR0 = data->mccr0 | 0x7f7f;
 
 	/*
 	 * Calculate the read/write timeout (us) from the bit clock
@@ -241,49 +202,32 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	if (ret == 0)
 		goto out;
 
- release2:
-	release_mem_region(res_mem1->start, size1);
  release:
-	release_mem_region(res_mem0->start, size0);
+	release_mem_region(0x80060000, 0x60);
 	platform_set_drvdata(pdev, NULL);
 
  out:
 	return ret;
 }
 
-static int mcp_sa11x0_remove(struct platform_device *pdev)
+static int mcp_sa11x0_remove(struct platform_device *dev)
 {
-	struct mcp *mcp = platform_get_drvdata(pdev);
-	struct mcp_sa11x0 *priv = priv(mcp);
-	struct resource *res_mem;
-	u32 size;
+	struct mcp *mcp = platform_get_drvdata(dev);
 
-	platform_set_drvdata(pdev, NULL);
+	platform_set_drvdata(dev, NULL);
 	mcp_host_unregister(mcp);
+	release_mem_region(0x80060000, 0x60);
 
-	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res_mem) {
-		size = res_mem->end - res_mem->start + 1;
-		release_mem_region(res_mem->start, size);
-	}
-	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (res_mem) {
-		size = res_mem->end - res_mem->start + 1;
-		release_mem_region(res_mem->start, size);
-	}
-	iounmap(priv->mccr0_base);
-	iounmap(priv->mccr1_base);
 	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 *priv = priv(mcp);
-	u32 mccr0;
 
-	mccr0 = priv->mccr0 & ~MCCR0_MCE;
-	__raw_writel(mccr0, priv->mccr0_base + MCCR0);
+	priv(mcp)->mccr0 = Ser4MCCR0;
+	priv(mcp)->mccr1 = Ser4MCCR1;
+	Ser4MCCR0 &= ~MCCR0_MCE;
 
 	return 0;
 }
@@ -291,10 +235,9 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 static int mcp_sa11x0_resume(struct platform_device *dev)
 {
 	struct mcp *mcp = platform_get_drvdata(dev);
-	struct mcp_sa11x0 *priv = priv(mcp);
 
-	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
-	__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
+	Ser4MCCR1 = priv(mcp)->mccr1;
+	Ser4MCCR0 = priv(mcp)->mccr0;
 
 	return 0;
 }
@@ -311,7 +254,6 @@ static struct platform_driver mcp_sa11x0_driver = {
 	.resume		= mcp_sa11x0_resume,
 	.driver		= {
 		.name	= "sa11x0-mcp",
-		.owner  = THIS_MODULE,
 	},
 };
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 02/33] Revert "ARM: sa11x0: Implement autoloading of codec and codec pdata for mcp bus."
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
  2012-01-25 14:30 ` [PATCH 01/33] Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources." Russell King - ARM Linux
@ 2012-01-25 14:30 ` Russell King - ARM Linux
  2012-01-25 14:31 ` [PATCH 03/33] MFD: mcp-core: fix complaints from the genirq layer Russell King - ARM Linux
                   ` (32 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

This reverts commit 5dd7bf59e0e8563265b3e5b33276099ef628fcc7.

Conflicts:

	scripts/mod/file2alias.c

This change is wrong on many levels.  First and foremost, it causes a
regression.  On boot on Assabet, which this patch gives a codec id of
'ucb1x00', it gives:

	ucb1x00 ID not found: 1005

0x1005 is a valid ID for the UCB1300 device.

Secondly, this patch is way over the top in terms of complexity.  The
only device which has been seen to be connected with this MCP code is
the UCB1x00 (UCB1200, UCB1300 etc) devices, and they all use the same
driver.  Adding a match table, requiring the codec string to match the
hardware ID read out of the ID register, etc is completely over the top
when we can just read the hardware ID register.
---
 arch/arm/mach-sa1100/assabet.c          |    1 -
 arch/arm/mach-sa1100/cerf.c             |    1 -
 arch/arm/mach-sa1100/collie.c           |    8 +----
 arch/arm/mach-sa1100/include/mach/mcp.h |    2 -
 arch/arm/mach-sa1100/lart.c             |    1 -
 arch/arm/mach-sa1100/shannon.c          |    1 -
 arch/arm/mach-sa1100/simpad.c           |    8 +----
 drivers/mfd/mcp-core.c                  |   44 +---------------------------
 drivers/mfd/mcp-sa11x0.c                |    7 +---
 drivers/mfd/ucb1x00-core.c              |   48 +++++++-----------------------
 drivers/mfd/ucb1x00-ts.c                |    2 +-
 include/linux/mfd/mcp.h                 |    7 +---
 include/linux/mfd/ucb1x00.h             |    5 +--
 include/linux/mod_devicetable.h         |   11 -------
 scripts/mod/file2alias.c                |   10 ------
 15 files changed, 21 insertions(+), 135 deletions(-)

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index d8aa1c2..0c4b76a 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -202,7 +202,6 @@ static struct irda_platform_data assabet_irda_data = {
 static struct mcp_plat_data assabet_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
-	.codec		= "ucb1x00",
 };
 
 static void __init assabet_init(void)
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index fcadc4c..11bb6d0 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -124,7 +124,6 @@ static void __init cerf_map_io(void)
 static struct mcp_plat_data cerf_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
-	.codec		= "ucb1x00",
 };
 
 static void __init cerf_init(void)
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 6b7c74b..b9060e2 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -27,7 +27,6 @@
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
-#include <linux/mfd/ucb1x00.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -86,15 +85,10 @@ 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,
-	.codec		= "ucb1x00",
-	.codec_pdata	= &collie_ucb1x00_data,
+	.gpio_base	= COLLIE_TC35143_GPIO_BASE,
 };
 
 /*
diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h
index 586cec8..ed1a331 100644
--- a/arch/arm/mach-sa1100/include/mach/mcp.h
+++ b/arch/arm/mach-sa1100/include/mach/mcp.h
@@ -17,8 +17,6 @@ struct mcp_plat_data {
 	u32 mccr1;
 	unsigned int sclk_rate;
 	int gpio_base;
-	const char *codec;
-	void *codec_pdata;
 };
 
 #endif
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index 48a8f4e..af4e276 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -24,7 +24,6 @@
 static struct mcp_plat_data lart_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
-	.codec		= "ucb1x00",
 };
 
 static void __init lart_init(void)
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 3807c91..318b2b7 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -55,7 +55,6 @@ static struct resource shannon_flash_resource = {
 static struct mcp_plat_data shannon_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
-	.codec		= "ucb1x00",
 };
 
 static void __init shannon_init(void)
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index d9b765c..e17c04d 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -14,7 +14,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/mfd/ucb1x00.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -188,15 +187,10 @@ 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,
-	.codec		= "ucb1300",
-	.codec_pdata	= &simpad_ucb1x00_data,
+	.gpio_base	= SIMPAD_UCB1X00_GPIO_BASE,
 };
 
 
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 63be60b..84815f9 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -26,35 +26,9 @@
 #define to_mcp(d)		container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)	container_of(d, struct mcp_driver, drv)
 
-static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
-						const char *codec)
-{
-	while (id->name[0]) {
-		if (strcmp(codec, id->name) == 0)
-			return id;
-		id++;
-	}
-	return NULL;
-}
-
-const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
-{
-	const struct mcp_driver *driver =
-		to_mcp_driver(mcp->attached_device.driver);
-
-	return mcp_match_id(driver->id_table, mcp->codec);
-}
-EXPORT_SYMBOL(mcp_get_device_id);
-
 static int mcp_bus_match(struct device *dev, struct device_driver *drv)
 {
-	const struct mcp *mcp = to_mcp(dev);
-	const struct mcp_driver *driver = to_mcp_driver(drv);
-
-	if (driver->id_table)
-		return !!mcp_match_id(driver->id_table, mcp->codec);
-
-	return 0;
+	return 1;
 }
 
 static int mcp_bus_probe(struct device *dev)
@@ -100,18 +74,9 @@ static int mcp_bus_resume(struct device *dev)
 	return ret;
 }
 
-static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-	struct mcp *mcp = to_mcp(dev);
-
-	add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
-	return 0;
-}
-
 static struct bus_type mcp_bus_type = {
 	.name		= "mcp",
 	.match		= mcp_bus_match,
-	.uevent		= mcp_bus_uevent,
 	.probe		= mcp_bus_probe,
 	.remove		= mcp_bus_remove,
 	.suspend	= mcp_bus_suspend,
@@ -247,14 +212,9 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp, void *pdata)
+int mcp_host_register(struct mcp *mcp)
 {
-	if (!mcp->codec)
-		return -EINVAL;
-
-	mcp->attached_device.platform_data = pdata;
 	dev_set_name(&mcp->attached_device, "mcp0");
-	request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
 	return device_register(&mcp->attached_device);
 }
 EXPORT_SYMBOL(mcp_host_register);
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index da4e077..02c53a0 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -146,9 +146,6 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	if (!data)
 		return -ENODEV;
 
-	if (!data->codec)
-		return -ENODEV;
-
 	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
 		return -EBUSY;
 
@@ -165,7 +162,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	mcp->dma_audio_wr	= DMA_Ser4MCP0Wr;
 	mcp->dma_telco_rd	= DMA_Ser4MCP1Rd;
 	mcp->dma_telco_wr	= DMA_Ser4MCP1Wr;
-	mcp->codec		= data->codec;
+	mcp->gpio_base		= data->gpio_base;
 
 	platform_set_drvdata(pdev, mcp);
 
@@ -198,7 +195,7 @@ 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, data->codec_pdata);
+	ret = mcp_host_register(mcp);
 	if (ret == 0)
 		goto out;
 
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 91c4f25..b281217 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -36,15 +36,6 @@ static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);
 
-static struct mcp_device_id ucb1x00_id[] = {
-	{ "ucb1x00", 0 },  /* auto-detection */
-	{ "ucb1200", UCB_ID_1200 },
-	{ "ucb1300", UCB_ID_1300 },
-	{ "tc35143", UCB_ID_TC35143 },
-	{ }
-};
-MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
-
 /**
  *	ucb1x00_io_set_dir - set IO direction
  *	@ucb: UCB1x00 structure describing chip
@@ -536,33 +527,17 @@ static struct class ucb1x00_class = {
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
-	const struct mcp_device_id *mid;
 	struct ucb1x00 *ucb;
 	struct ucb1x00_driver *drv;
-	struct ucb1x00_plat_data *pdata;
 	unsigned int id;
 	int ret = -ENODEV;
 	int temp;
 
 	mcp_enable(mcp);
 	id = mcp_reg_read(mcp, UCB_ID);
-	mid = mcp_get_device_id(mcp);
 
-	if (mid && mid->driver_data) {
-		if (id != mid->driver_data) {
-			printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
-				mid->name, (unsigned int) mid->driver_data, id);
-			goto err_disable;
-		}
-	} else {
-		mid = &ucb1x00_id[1];
-		while (mid->driver_data) {
-			if (id == mid->driver_data)
-				break;
-			mid++;
-		}
-		printk(KERN_WARNING "%s ID not found: %04x\n",
-			ucb1x00_id[0].name, id);
+	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;
 	}
 
@@ -571,28 +546,28 @@ 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, mid->name);
+	dev_set_name(&ucb->dev, "ucb1x00");
 
 	spin_lock_init(&ucb->lock);
 	spin_lock_init(&ucb->io_lock);
 	sema_init(&ucb->adc_sem, 1);
 
-	ucb->id  = mid;
+	ucb->id  = id;
 	ucb->mcp = mcp;
 	ucb->irq = ucb1x00_detect_irq(ucb);
 	if (ucb->irq == NO_IRQ) {
-		printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
+		printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
 		ret = -ENODEV;
 		goto err_free;
 	}
 
 	ucb->gpio.base = -1;
-	if (pdata && (pdata->gpio_base >= 0)) {
+	if (mcp->gpio_base != 0) {
 		ucb->gpio.label = dev_name(&ucb->dev);
-		ucb->gpio.base = pdata->gpio_base;
+		ucb->gpio.base = mcp->gpio_base;
 		ucb->gpio.ngpio = 10;
 		ucb->gpio.set = ucb1x00_gpio_set;
 		ucb->gpio.get = ucb1x00_gpio_get;
@@ -605,10 +580,10 @@ static int ucb1x00_probe(struct mcp *mcp)
 		dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
 	ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-			  mid->name, ucb);
+			  "UCB1x00", ucb);
 	if (ret) {
-		printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
-			mid->name, ucb->irq, ret);
+		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+			ucb->irq, ret);
 		goto err_gpio;
 	}
 
@@ -730,7 +705,6 @@ static struct mcp_driver ucb1x00_driver = {
 	.remove		= ucb1x00_remove,
 	.suspend	= ucb1x00_suspend,
 	.resume		= ucb1x00_resume,
-	.id_table	= ucb1x00_id,
 };
 
 static int __init ucb1x00_init(void)
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 40ec3c1..38ffbd5 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
 	ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
 
 	idev->name       = "Touchscreen panel";
-	idev->id.product = ts->ucb->id->driver_data;
+	idev->id.product = ts->ucb->id;
 	idev->open       = ucb1x00_ts_open;
 	idev->close      = ucb1x00_ts_close;
 
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index 1515e64..ee496708 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -10,7 +10,6 @@
 #ifndef MCP_H
 #define MCP_H
 
-#include <linux/mod_devicetable.h>
 #include <mach/dma.h>
 
 struct mcp_ops;
@@ -27,7 +26,7 @@ struct mcp {
 	dma_device_t	dma_telco_rd;
 	dma_device_t	dma_telco_wr;
 	struct device	attached_device;
-	const char	*codec;
+	int		gpio_base;
 };
 
 struct mcp_ops {
@@ -45,11 +44,10 @@ void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
 unsigned int mcp_reg_read(struct mcp *, unsigned int);
 void mcp_enable(struct mcp *);
 void mcp_disable(struct mcp *);
-const struct mcp_device_id *mcp_get_device_id(const struct mcp *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 *);
+int mcp_host_register(struct mcp *);
 void mcp_host_unregister(struct mcp *);
 
 struct mcp_driver {
@@ -58,7 +56,6 @@ struct mcp_driver {
 	void (*remove)(struct mcp *);
 	int (*suspend)(struct mcp *, pm_message_t);
 	int (*resume)(struct mcp *);
-	const struct mcp_device_id *id_table;
 };
 
 int mcp_driver_register(struct mcp_driver *);
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index bc19e5f..4321f04 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -104,9 +104,6 @@
 #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;
@@ -119,7 +116,7 @@ struct ucb1x00 {
 	unsigned int		irq;
 	struct semaphore	adc_sem;
 	spinlock_t		io_lock;
-	const struct mcp_device_id *id;
+	u16			id;
 	u16			io_dir;
 	u16			io_out;
 	u16			adc_cr;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index b29e7f6..83ac071 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -436,17 +436,6 @@ struct spi_device_id {
 			__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
-/* mcp */
-
-#define MCP_NAME_SIZE	20
-#define MCP_MODULE_PREFIX "mcp:"
-
-struct mcp_device_id {
-	char name[MCP_NAME_SIZE];
-	kernel_ulong_t driver_data	/* Data private to the driver */
-			__attribute__((aligned(sizeof(kernel_ulong_t))));
-};
-
 /* dmi */
 enum dmi_field {
 	DMI_NONE,
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index c0e14b3..e8c9695 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -823,16 +823,6 @@ static int do_spi_entry(const char *filename, struct spi_device_id *id,
 }
 ADD_TO_DEVTABLE("spi", struct spi_device_id, do_spi_entry);
 
-/* Looks like: mcp:S */
-static int do_mcp_entry(const char *filename, struct mcp_device_id *id,
-			char *alias)
-{
-	sprintf(alias, MCP_MODULE_PREFIX "%s", id->name);
-
-	return 1;
-}
-ADD_TO_DEVTABLE("mcp", struct mcp_device_id, do_mcp_entry); 
-
 static const struct dmifield {
 	const char *prefix;
 	int field;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 03/33] MFD: mcp-core: fix complaints from the genirq layer
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
  2012-01-25 14:30 ` [PATCH 01/33] Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources." Russell King - ARM Linux
  2012-01-25 14:30 ` [PATCH 02/33] Revert "ARM: sa11x0: Implement autoloading of codec and codec pdata for mcp bus." Russell King - ARM Linux
@ 2012-01-25 14:31 ` Russell King - ARM Linux
  2012-01-25 14:31 ` [PATCH 04/33] MFD: mcp-core: fix mcp_priv() to be more type safe Russell King - ARM Linux
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

The genirq layer complains if an interrupt handler returns with
interrupts enabled.  The UCB1x00 handler does just this, because
ucb1x00_enable() calls mcp_enable(), which uses spin_lock_irq()
rather than spin_lock_irqsave().  Convert this, and the divisor
setting functions to use spin_lock_irqsave().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-core.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 84815f9..86cc3f7 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -93,9 +93,11 @@ static struct bus_type mcp_bus_type = {
  */
 void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
 {
-	spin_lock_irq(&mcp->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mcp->lock, flags);
 	mcp->ops->set_telecom_divisor(mcp, div);
-	spin_unlock_irq(&mcp->lock);
+	spin_unlock_irqrestore(&mcp->lock, flags);
 }
 EXPORT_SYMBOL(mcp_set_telecom_divisor);
 
@@ -108,9 +110,11 @@ EXPORT_SYMBOL(mcp_set_telecom_divisor);
  */
 void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
 {
-	spin_lock_irq(&mcp->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mcp->lock, flags);
 	mcp->ops->set_audio_divisor(mcp, div);
-	spin_unlock_irq(&mcp->lock);
+	spin_unlock_irqrestore(&mcp->lock, flags);
 }
 EXPORT_SYMBOL(mcp_set_audio_divisor);
 
@@ -163,10 +167,11 @@ EXPORT_SYMBOL(mcp_reg_read);
  */
 void mcp_enable(struct mcp *mcp)
 {
-	spin_lock_irq(&mcp->lock);
+	unsigned long flags;
+	spin_lock_irqsave(&mcp->lock, flags);
 	if (mcp->use_count++ == 0)
 		mcp->ops->enable(mcp);
-	spin_unlock_irq(&mcp->lock);
+	spin_unlock_irqrestore(&mcp->lock, flags);
 }
 EXPORT_SYMBOL(mcp_enable);
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 04/33] MFD: mcp-core: fix mcp_priv() to be more type safe
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (2 preceding siblings ...)
  2012-01-25 14:31 ` [PATCH 03/33] MFD: mcp-core: fix complaints from the genirq layer Russell King - ARM Linux
@ 2012-01-25 14:31 ` Russell King - ARM Linux
  2012-01-25 14:31 ` [PATCH 05/33] MFD: ucb1x00-core: fix missing restore of io output data on resume Russell King - ARM Linux
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

mcp_priv() does unexpected things when passed a void pointer.  Make it
a typed inline function, which ensures that it works correctly in
these cases.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 include/linux/mfd/mcp.h |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index ee496708..f88c1cc 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -64,6 +64,9 @@ void mcp_driver_unregister(struct mcp_driver *);
 #define mcp_get_drvdata(mcp)	dev_get_drvdata(&(mcp)->attached_device)
 #define mcp_set_drvdata(mcp,d)	dev_set_drvdata(&(mcp)->attached_device, d)
 
-#define mcp_priv(mcp)		((void *)((mcp)+1))
+static inline void *mcp_priv(struct mcp *mcp)
+{
+	return mcp + 1;
+}
 
 #endif
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 05/33] MFD: ucb1x00-core: fix missing restore of io output data on resume
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (3 preceding siblings ...)
  2012-01-25 14:31 ` [PATCH 04/33] MFD: mcp-core: fix mcp_priv() to be more type safe Russell King - ARM Linux
@ 2012-01-25 14:31 ` Russell King - ARM Linux
  2012-01-25 14:32 ` [PATCH 06/33] MFD: ucb1x00-core: fix gpiolib direction_output handling Russell King - ARM Linux
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

We were not restoring the UCB1x00 gpio output data on resume, resulting
in incorrect GPIO output data after a resume.  Add the missing register
write.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index b281217..8ebda97 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -687,6 +687,7 @@ static int ucb1x00_resume(struct mcp *mcp)
 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
 	struct ucb1x00_dev *dev;
 
+	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
 	mutex_lock(&ucb1x00_mutex);
 	list_for_each_entry(dev, &ucb->devs, dev_node) {
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 06/33] MFD: ucb1x00-core: fix gpiolib direction_output handling
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (4 preceding siblings ...)
  2012-01-25 14:31 ` [PATCH 05/33] MFD: ucb1x00-core: fix missing restore of io output data on resume Russell King - ARM Linux
@ 2012-01-25 14:32 ` Russell King - ARM Linux
  2012-01-25 14:32 ` [PATCH 07/33] MFD: ucb1x00-ts: fix resume failure Russell King - ARM Linux
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:32 UTC (permalink / raw)
  To: linux-arm-kernel

gpiolib drivers should first set the output data before setting the
direction to avoid putting glitches on an output signal.  As an
additional bonus, we tweak the code to avoid unnecessary register
writes to the output and direction registers if they have no need
to be updated.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 8ebda97..febc90c 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -148,16 +148,22 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
 {
 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
 	unsigned long flags;
+	unsigned old, mask = 1 << offset;
 
 	spin_lock_irqsave(&ucb->io_lock, flags);
-	ucb->io_dir |= (1 << offset);
-	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
-
+	old = ucb->io_out;
 	if (value)
-		ucb->io_out |= 1 << offset;
+		ucb->io_out |= mask;
 	else
-		ucb->io_out &= ~(1 << offset);
-	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+		ucb->io_out &= ~mask;
+
+	if (old != ucb->io_out)
+		ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+
+	if (!(ucb->io_dir & mask)) {
+		ucb->io_dir |= mask;
+		ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+	}
 	spin_unlock_irqrestore(&ucb->io_lock, flags);
 
 	return 0;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 07/33] MFD: ucb1x00-ts: fix resume failure
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (5 preceding siblings ...)
  2012-01-25 14:32 ` [PATCH 06/33] MFD: ucb1x00-core: fix gpiolib direction_output handling Russell King - ARM Linux
@ 2012-01-25 14:32 ` Russell King - ARM Linux
  2012-01-25 14:32 ` [PATCH 08/33] MFD: mcp-core: sanitize host creation/removal Russell King - ARM Linux
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:32 UTC (permalink / raw)
  To: linux-arm-kernel

If the ucb1x00 touchscreen is resumed while the touchscreen is being
touched, the main thread stops responding.  This occurs because two
things happen:

1. When we suspended, we were woken up, and executed the loop.
   Finding that the touchscreen was not pressed, we prepare to
   schedule for a maximum timeout, before being stopped in
   try_to_freeze().

2. an irq occurs, we disable the irq, and mark it as disabled,
   and wake the thread.  This wake occurs while the thread is
   still within __refrigerator()

3. The thread is unfrozen, and __refrigerator() sets the threads
   state back to INTERRUPTIBLE.

We then drop into schedule_timeout() with an infinite timeout and the
IRQ disabled.  This prevents any further screen touches activating
the thread.

Fix this by using kthread_freezable_should_stop() which handles the
freezing issues for us outside of the hotspot where the task state
matters.  Include a flag to ignore the touchscreen until it is
released to avoid sending unintended data to the application.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-ts.c |   32 +++++---------------------------
 1 files changed, 5 insertions(+), 27 deletions(-)

diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 38ffbd5..63a3cbd 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -47,7 +47,6 @@ struct ucb1x00_ts {
 	u16			x_res;
 	u16			y_res;
 
-	unsigned int		restart:1;
 	unsigned int		adcsync:1;
 };
 
@@ -207,15 +206,17 @@ static int ucb1x00_thread(void *_ts)
 {
 	struct ucb1x00_ts *ts = _ts;
 	DECLARE_WAITQUEUE(wait, current);
+	bool frozen, ignore = false;
 	int valid = 0;
 
 	set_freezable();
 	add_wait_queue(&ts->irq_wait, &wait);
-	while (!kthread_should_stop()) {
+	while (!kthread_freezable_should_stop(&frozen)) {
 		unsigned int x, y, p;
 		signed long timeout;
 
-		ts->restart = 0;
+		if (frozen)
+			ignore = true;
 
 		ucb1x00_adc_enable(ts->ucb);
 
@@ -258,7 +259,7 @@ static int ucb1x00_thread(void *_ts)
 			 * space.  We therefore leave it to user space
 			 * to do any filtering they please.
 			 */
-			if (!ts->restart) {
+			if (!ignore) {
 				ucb1x00_ts_evt_add(ts, p, x, y);
 				valid = 1;
 			}
@@ -267,8 +268,6 @@ static int ucb1x00_thread(void *_ts)
 			timeout = HZ / 100;
 		}
 
-		try_to_freeze();
-
 		schedule_timeout(timeout);
 	}
 
@@ -340,26 +339,6 @@ static void ucb1x00_ts_close(struct input_dev *idev)
 	ucb1x00_disable(ts->ucb);
 }
 
-#ifdef CONFIG_PM
-static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
-{
-	struct ucb1x00_ts *ts = dev->priv;
-
-	if (ts->rtask != NULL) {
-		/*
-		 * Restart the TS thread to ensure the
-		 * TS interrupt mode is set up again
-		 * after sleep.
-		 */
-		ts->restart = 1;
-		wake_up(&ts->irq_wait);
-	}
-	return 0;
-}
-#else
-#define ucb1x00_ts_resume NULL
-#endif
-
 
 /*
  * Initialisation.
@@ -425,7 +404,6 @@ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
 static struct ucb1x00_driver ucb1x00_ts_driver = {
 	.add		= ucb1x00_ts_add,
 	.remove		= ucb1x00_ts_remove,
-	.resume		= ucb1x00_ts_resume,
 };
 
 static int __init ucb1x00_ts_init(void)
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 08/33] MFD: mcp-core: sanitize host creation/removal
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (6 preceding siblings ...)
  2012-01-25 14:32 ` [PATCH 07/33] MFD: ucb1x00-ts: fix resume failure Russell King - ARM Linux
@ 2012-01-25 14:32 ` Russell King - ARM Linux
  2012-01-25 14:33 ` [PATCH 09/33] MFD: mcp-sa11x0: remove DMA initializers and variables Russell King - ARM Linux
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:32 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 86cc3f7..cc76431 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 02c53a0..33cadc0 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 f88c1cc..79a6b13 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/33] MFD: mcp-sa11x0: remove DMA initializers and variables
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (7 preceding siblings ...)
  2012-01-25 14:32 ` [PATCH 08/33] MFD: mcp-core: sanitize host creation/removal Russell King - ARM Linux
@ 2012-01-25 14:33 ` Russell King - ARM Linux
  2012-01-25 14:33 ` [PATCH 10/33] MFD: mcp-sa11x0: move setup of PPC unit out of mcp-sa11x0.c Russell King - ARM Linux
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:33 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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, 0 insertions(+), 17 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index cc76431..280a4f8 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 33cadc0..d2ebc64 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 cea9da6..b7be613 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 febc90c..f2fb420 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 63a3cbd..ec6ffb6 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 79a6b13..dfe7e51 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;
 };
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 10/33] MFD: mcp-sa11x0: move setup of PPC unit out of mcp-sa11x0.c
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (8 preceding siblings ...)
  2012-01-25 14:33 ` [PATCH 09/33] MFD: mcp-sa11x0: remove DMA initializers and variables Russell King - ARM Linux
@ 2012-01-25 14:33 ` Russell King - ARM Linux
  2012-01-25 14:33 ` [PATCH 11/33] MFD: mcp-sa11x0: add .owner initializer Russell King - ARM Linux
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:33 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 0c4b76a..3a19145 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 11bb6d0..bc11879 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 b9060e2..efa2bc1 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 480d2ea..1416094 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 33268cf..9236ff4 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 af4e276..eba64b7 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 318b2b7..3efb4ac 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 e17c04d..3aa36ec 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 d2ebc64..5373a7a 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -166,15 +166,6 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
 	}
 
 	/*
-	 * 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.
 	 */
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 11/33] MFD: mcp-sa11x0: add .owner initializer
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (9 preceding siblings ...)
  2012-01-25 14:33 ` [PATCH 10/33] MFD: mcp-sa11x0: move setup of PPC unit out of mcp-sa11x0.c Russell King - ARM Linux
@ 2012-01-25 14:33 ` Russell King - ARM Linux
  2012-01-25 14:34 ` [PATCH 12/33] MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform resources Russell King - ARM Linux
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:33 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 5373a7a..703e76a 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");
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/33] MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform resources
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (10 preceding siblings ...)
  2012-01-25 14:33 ` [PATCH 11/33] MFD: mcp-sa11x0: add .owner initializer Russell King - ARM Linux
@ 2012-01-25 14:34 ` Russell King - ARM Linux
  2012-01-25 14:34 ` [PATCH 13/33] MFD: mcp-sa11x0: convert to use dev_pm_ops Russell King - ARM Linux
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:34 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 1416094..9379c53 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 703e76a..4d06db7 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;
+
+	if (!request_mem_region(mem0->start, resource_size(mem0),
+				DRIVER_NAME)) {
+		ret = -EBUSY;
+		goto err_mem0;
+	}
 
-	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+	if (!request_mem_region(mem1->start, resource_size(mem1),
+				DRIVER_NAME)) {
+		ret = -EBUSY;
+		goto err_mem1;
+	}
+
+	mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
 	if (!mcp) {
 		ret = -ENOMEM;
-		goto release;
+		goto err_alloc;
 	}
 
 	mcp->owner		= THIS_MODULE;
@@ -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;
 
-	mcp_host_free(mcp);
- release:
-	release_mem_region(0x80060000, 0x60);
-	platform_set_drvdata(pdev, NULL);
+	platform_set_drvdata(dev, NULL);
 
- out:
+ err_ioremap:
+	iounmap(m->base1);
+	iounmap(m->base0);
+	mcp_host_free(mcp);
+ err_alloc:
+	release_mem_region(mem1->start, resource_size(mem1));
+ err_mem1:
+	release_mem_region(mem0->start, resource_size(mem0));
+ err_mem0:
 	return ret;
 }
 
 static int mcp_sa11x0_remove(struct platform_device *dev)
 {
 	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(mcp);
+	struct resource *mem0, *mem1;
+
+	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;
 }
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 13/33] MFD: mcp-sa11x0: convert to use dev_pm_ops
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (11 preceding siblings ...)
  2012-01-25 14:34 ` [PATCH 12/33] MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform resources Russell King - ARM Linux
@ 2012-01-25 14:34 ` Russell King - ARM Linux
  2012-01-25 14:34 ` [PATCH 14/33] MFD: mcp-sa11x0: use _noirq resume methods Russell King - ARM Linux
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:34 UTC (permalink / raw)
  To: linux-arm-kernel

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

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

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 4d06db7..46167f6 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,
 	},
 };
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 14/33] MFD: mcp-sa11x0: use _noirq resume methods
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (12 preceding siblings ...)
  2012-01-25 14:34 ` [PATCH 13/33] MFD: mcp-sa11x0: convert to use dev_pm_ops Russell King - ARM Linux
@ 2012-01-25 14:34 ` Russell King - ARM Linux
  2012-01-25 14:35 ` [PATCH 15/33] MFD: mcp/ucb1x00: separate ucb1x00 driver data from the MCP data Russell King - ARM Linux
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:34 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 46167f6..420710b 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 = {
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 15/33] MFD: mcp/ucb1x00: separate ucb1x00 driver data from the MCP data
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (13 preceding siblings ...)
  2012-01-25 14:34 ` [PATCH 14/33] MFD: mcp-sa11x0: use _noirq resume methods Russell King - ARM Linux
@ 2012-01-25 14:35 ` Russell King - ARM Linux
  2012-01-25 14:35 ` [PATCH 16/33] MFD: ucb1x00-ts: provide input layer with device parent Russell King - ARM Linux
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 efa2bc1..0e73597 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 ed1a331..4b2860ae 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 3aa36ec..74da17a 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 280a4f8..c409d63 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 420710b..960ebc7 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 f2fb420..6825169 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 dfe7e51..bfcdf6d 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 4321f04..731b23a 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 16/33] MFD: ucb1x00-ts: provide input layer with device parent
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (14 preceding siblings ...)
  2012-01-25 14:35 ` [PATCH 15/33] MFD: mcp/ucb1x00: separate ucb1x00 driver data from the MCP data Russell King - ARM Linux
@ 2012-01-25 14:35 ` Russell King - ARM Linux
  2012-01-25 14:35 ` [PATCH 17/33] MFD: ucb1x00-core: get rid of mach/hardware.h include Russell King - ARM Linux
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-ts.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index ec6ffb6..742d0c7 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);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 17/33] MFD: ucb1x00-core: get rid of mach/hardware.h include
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (15 preceding siblings ...)
  2012-01-25 14:35 ` [PATCH 16/33] MFD: ucb1x00-ts: provide input layer with device parent Russell King - ARM Linux
@ 2012-01-25 14:35 ` Russell King - ARM Linux
  2012-01-25 14:36 ` [PATCH 18/33] MFD: ucb1x00-core: add handling for ucb1x00 reset Russell King - ARM Linux
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 6825169..cc1c0dc 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);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 18/33] MFD: ucb1x00-core: add handling for ucb1x00 reset
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (16 preceding siblings ...)
  2012-01-25 14:35 ` [PATCH 17/33] MFD: ucb1x00-core: get rid of mach/hardware.h include Russell King - ARM Linux
@ 2012-01-25 14:36 ` Russell King - ARM Linux
  2012-01-25 14:36 ` [PATCH 19/33] MFD: ucb1x00-core: add .owner initializer and module alias Russell King - ARM Linux
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 cc1c0dc..42eee63 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 731b23a..fd088cc 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;
 };
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 19/33] MFD: ucb1x00-core: add .owner initializer and module alias
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (17 preceding siblings ...)
  2012-01-25 14:36 ` [PATCH 18/33] MFD: ucb1x00-core: add handling for ucb1x00 reset Russell King - ARM Linux
@ 2012-01-25 14:36 ` Russell King - ARM Linux
  2012-01-25 14:36 ` [PATCH 20/33] MFD: ucb1x00-core: use mutexes instead of semaphores Russell King - ARM Linux
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 42eee63..c2757c1 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");
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 20/33] MFD: ucb1x00-core: use mutexes instead of semaphores
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (18 preceding siblings ...)
  2012-01-25 14:36 ` [PATCH 19/33] MFD: ucb1x00-core: add .owner initializer and module alias Russell King - ARM Linux
@ 2012-01-25 14:36 ` Russell King - ARM Linux
  2012-01-25 14:37 ` [PATCH 21/33] MFD: ucb1x00-core: clean up device handling in probe Russell King - ARM Linux
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

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

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 c2757c1..7386f82 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 fd088cc..a4b9543 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 21/33] MFD: ucb1x00-core: clean up device handling in probe
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (19 preceding siblings ...)
  2012-01-25 14:36 ` [PATCH 20/33] MFD: ucb1x00-core: use mutexes instead of semaphores Russell King - ARM Linux
@ 2012-01-25 14:37 ` Russell King - ARM Linux
  2012-01-25 14:37 ` [PATCH 22/33] MFD: ucb1x00-core: add owner and dev initializers to gpio structure Russell King - ARM Linux
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

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

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

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 7386f82..74d9fcf 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:
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 22/33] MFD: ucb1x00-core: add owner and dev initializers to gpio structure
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (20 preceding siblings ...)
  2012-01-25 14:37 ` [PATCH 21/33] MFD: ucb1x00-core: clean up device handling in probe Russell King - ARM Linux
@ 2012-01-25 14:37 ` Russell King - ARM Linux
  2012-01-25 14:37 ` [PATCH 23/33] MFD: ucb1x00-core: scan drivers in same order they're registered Russell King - ARM Linux
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 74d9fcf..30ef726 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 23/33] MFD: ucb1x00-core: scan drivers in same order they're registered
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (21 preceding siblings ...)
  2012-01-25 14:37 ` [PATCH 22/33] MFD: ucb1x00-core: add owner and dev initializers to gpio structure Russell King - ARM Linux
@ 2012-01-25 14:37 ` Russell King - ARM Linux
  2012-01-25 14:38 ` [PATCH 24/33] MFD: ucb1x00-core: add missing ucb1x00_enable()/ucb1x00_disable() Russell King - ARM Linux
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 30ef726..162496d 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);
 	}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 24/33] MFD: ucb1x00-core: add missing ucb1x00_enable()/ucb1x00_disable()
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (22 preceding siblings ...)
  2012-01-25 14:37 ` [PATCH 23/33] MFD: ucb1x00-core: scan drivers in same order they're registered Russell King - ARM Linux
@ 2012-01-25 14:38 ` Russell King - ARM Linux
  2012-01-25 14:38 ` [PATCH 25/33] MFD: ucb1x00-core: disable mcp clock when bus is not required Russell King - ARM Linux
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-core.c |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 162496d..9f8ea52 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)
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 25/33] MFD: ucb1x00-core: disable mcp clock when bus is not required
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (23 preceding siblings ...)
  2012-01-25 14:38 ` [PATCH 24/33] MFD: ucb1x00-core: add missing ucb1x00_enable()/ucb1x00_disable() Russell King - ARM Linux
@ 2012-01-25 14:38 ` Russell King - ARM Linux
  2012-01-25 14:38 ` [PATCH 26/33] MFD: mcp-sa11x0: complain if mcp clock is left enabled Russell King - ARM Linux
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 9f8ea52..ed2a4b2 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);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 26/33] MFD: mcp-sa11x0: complain if mcp clock is left enabled
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (24 preceding siblings ...)
  2012-01-25 14:38 ` [PATCH 25/33] MFD: ucb1x00-core: disable mcp clock when bus is not required Russell King - ARM Linux
@ 2012-01-25 14:38 ` Russell King - ARM Linux
  2012-01-25 14:39 ` [PATCH 27/33] MFD: ucb1x00-core: convert to use dev_pm_ops Russell King - ARM Linux
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/mcp-sa11x0.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 960ebc7..c381436 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 27/33] MFD: ucb1x00-core: convert to use dev_pm_ops
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (25 preceding siblings ...)
  2012-01-25 14:38 ` [PATCH 26/33] MFD: mcp-sa11x0: complain if mcp clock is left enabled Russell King - ARM Linux
@ 2012-01-25 14:39 ` Russell King - ARM Linux
  2012-01-25 14:39 ` [PATCH 28/33] MFD: mcp-core: remove legacy driver suspend/resume methods Russell King - ARM Linux
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

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

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 ed2a4b2..6fab825 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 a4b9543..253c12c 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);
 };
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 28/33] MFD: mcp-core: remove legacy driver suspend/resume methods
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (26 preceding siblings ...)
  2012-01-25 14:39 ` [PATCH 27/33] MFD: ucb1x00-core: convert to use dev_pm_ops Russell King - ARM Linux
@ 2012-01-25 14:39 ` Russell King - ARM Linux
  2012-01-25 14:39 ` [PATCH 29/33] MFD: ucb1x00: convert to use genirq Russell King - ARM Linux
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

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

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, 0 insertions(+), 30 deletions(-)

diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index c409d63..6acf2e0 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 bfcdf6d..a9e8bd1 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 *);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 29/33] MFD: ucb1x00: convert to use genirq
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (27 preceding siblings ...)
  2012-01-25 14:39 ` [PATCH 28/33] MFD: mcp-core: remove legacy driver suspend/resume methods Russell King - ARM Linux
@ 2012-01-25 14:39 ` Russell King - ARM Linux
  2012-01-25 14:40 ` [PATCH 30/33] MFD: ucb1x00-core: add wakeup support Russell King - ARM Linux
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/Kconfig         |    5 +-
 drivers/mfd/ucb1x00-core.c  |  247 +++++++++++++++++--------------------------
 drivers/mfd/ucb1x00-ts.c    |   37 +++++--
 include/linux/mfd/ucb1x00.h |   22 +---
 4 files changed, 132 insertions(+), 179 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index cd13e9f..28a301b 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 6fab825..400604d 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;
+	raw_spin_lock(&ucb->irq_lock);
+	ucb->irq_mask |= mask;
+	ucb1x00_irq_update(ucb, mask);
+	raw_spin_unlock(&ucb->irq_lock);
+}
 
-	spin_lock_irq(&ucb->lock);
-	if (irq->devid == devid) {
-		ucb->irq_ris_enbl &= ~(1 << idx);
-		ucb->irq_fal_enbl &= ~(1 << idx);
+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);
 
-		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);
+	raw_spin_lock(&ucb->irq_lock);
+	if (type & IRQ_TYPE_EDGE_RISING)
+		ucb->irq_ris_enbl |= mask;
+	else
+		ucb->irq_ris_enbl &= ~mask;
 
-		irq->fn = NULL;
-		irq->devid = NULL;
-		ret = 0;
+	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);
 	}
-	spin_unlock_irq(&ucb->lock);
-	return ret;
+	raw_spin_unlock(&ucb->irq_lock);
 
-bad:
-	printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-	return -EINVAL;
+	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 742d0c7..1e0e20c 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 253c12c..6fb9074 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
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 30/33] MFD: ucb1x00-core: add wakeup support
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (28 preceding siblings ...)
  2012-01-25 14:39 ` [PATCH 29/33] MFD: ucb1x00: convert to use genirq Russell King - ARM Linux
@ 2012-01-25 14:40 ` Russell King - ARM Linux
  2012-01-25 14:40 ` [PATCH 31/33] ARM: sa11x0: add assabet ucb1x00 platform data Russell King - ARM Linux
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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(+), 0 deletions(-)

diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 400604d..70f02da 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 6fb9074..28af417 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;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 31/33] ARM: sa11x0: add assabet ucb1x00 platform data
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (29 preceding siblings ...)
  2012-01-25 14:40 ` [PATCH 30/33] MFD: ucb1x00-core: add wakeup support Russell King - ARM Linux
@ 2012-01-25 14:40 ` Russell King - ARM Linux
  2012-01-25 14:40 ` [PATCH 32/33] MFD: ucb1x00-assabet: add support for UCB1x00 GPIO switches Russell King - ARM Linux
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

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

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

diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 3a19145..c45402f 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)
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 32/33] MFD: ucb1x00-assabet: add support for UCB1x00 GPIO switches
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (30 preceding siblings ...)
  2012-01-25 14:40 ` [PATCH 31/33] ARM: sa11x0: add assabet ucb1x00 platform data Russell King - ARM Linux
@ 2012-01-25 14:40 ` Russell King - ARM Linux
  2012-01-25 14:41 ` [PATCH 33/33] MFD: mcp-sa11x0/assabet: move assabet reset handling out of mcp-sa11x0.c Russell King - ARM Linux
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mfd/ucb1x00-assabet.c |   43 +++++++++++++++++++++++++++++++++++++---
 1 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index b7be613..b63c075 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/device.h>
+#include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/mfd/ucb1x00.h>
 
 #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);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 33/33] MFD: mcp-sa11x0/assabet: move assabet reset handling out of mcp-sa11x0.c
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (31 preceding siblings ...)
  2012-01-25 14:40 ` [PATCH 32/33] MFD: ucb1x00-assabet: add support for UCB1x00 GPIO switches Russell King - ARM Linux
@ 2012-01-25 14:41 ` Russell King - ARM Linux
  2012-01-25 14:54 ` [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Mark Brown
  2012-01-27  9:46 ` Jochen Friedrich
  34 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 14:41 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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 c45402f..b5955ad 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 c381436..1c0ceac 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.
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (32 preceding siblings ...)
  2012-01-25 14:41 ` [PATCH 33/33] MFD: mcp-sa11x0/assabet: move assabet reset handling out of mcp-sa11x0.c Russell King - ARM Linux
@ 2012-01-25 14:54 ` Mark Brown
  2012-01-25 21:14   ` Russell King - ARM Linux
  2012-01-27  9:46 ` Jochen Friedrich
  34 siblings, 1 reply; 38+ messages in thread
From: Mark Brown @ 2012-01-25 14:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 25, 2012 at 02:30:00PM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 20, 2012 at 06:04:56PM +0000, Russell King - ARM Linux wrote:

> > The following patch set restores the SA11x0 MCP and UCB1x00 drivers back
> > to a working state, as tested on the Assabet.

> I've not heard anything back from anyone, so I'm going to assume that's
> silent approval.

FWIW Samuel tends to review patches every few weeks to every month, it's
not unusual for several weeks to patch before things get looked at.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state
  2012-01-25 14:54 ` [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Mark Brown
@ 2012-01-25 21:14   ` Russell King - ARM Linux
  2012-01-26 20:30     ` Samuel Ortiz
  0 siblings, 1 reply; 38+ messages in thread
From: Russell King - ARM Linux @ 2012-01-25 21:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 25, 2012 at 02:54:20PM +0000, Mark Brown wrote:
> On Wed, Jan 25, 2012 at 02:30:00PM +0000, Russell King - ARM Linux wrote:
> > On Fri, Jan 20, 2012 at 06:04:56PM +0000, Russell King - ARM Linux wrote:
> 
> > > The following patch set restores the SA11x0 MCP and UCB1x00 drivers back
> > > to a working state, as tested on the Assabet.
> 
> > I've not heard anything back from anyone, so I'm going to assume that's
> > silent approval.
> 
> FWIW Samuel tends to review patches every few weeks to every month, it's
> not unusual for several weeks to patch before things get looked at.

That's not going to be much use - by that time we'll be at -rc4 or so,
which means that reverting the rather large changes becomes much more
of an eye-brow raising request than it would do at -rc1 time.  We're
already at the theoretical dawn of -rc2, one week after -rc1.

So, I think the only thing I can do is push the fixes upstream myself
and hope that Samuel doesn't have an issue with it (he shouldn't have,
as I'm marked in the code as the author of it, and I still have working
hardware to test this stuff on... so in theory I should know what I'm
doing with it!)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state
  2012-01-25 21:14   ` Russell King - ARM Linux
@ 2012-01-26 20:30     ` Samuel Ortiz
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Ortiz @ 2012-01-26 20:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 25, 2012 at 09:14:27PM +0000, Russell King - ARM Linux wrote:
> On Wed, Jan 25, 2012 at 02:54:20PM +0000, Mark Brown wrote:
> > On Wed, Jan 25, 2012 at 02:30:00PM +0000, Russell King - ARM Linux wrote:
> > > On Fri, Jan 20, 2012 at 06:04:56PM +0000, Russell King - ARM Linux wrote:
> > 
> > > > The following patch set restores the SA11x0 MCP and UCB1x00 drivers back
> > > > to a working state, as tested on the Assabet.
> > 
> > > I've not heard anything back from anyone, so I'm going to assume that's
> > > silent approval.
> > 
> > FWIW Samuel tends to review patches every few weeks to every month, it's
> > not unusual for several weeks to patch before things get looked at.
> 
> That's not going to be much use - by that time we'll be at -rc4 or so,
> which means that reverting the rather large changes becomes much more
> of an eye-brow raising request than it would do at -rc1 time.  We're
> already at the theoretical dawn of -rc2, one week after -rc1.
> 
> So, I think the only thing I can do is push the fixes upstream myself
> and hope that Samuel doesn't have an issue with it 
No, I'm fine with it. I currently won't have time to build a proper pull
request for this one, so please go ahead and push it to Linus.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state
  2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
                   ` (33 preceding siblings ...)
  2012-01-25 14:54 ` [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Mark Brown
@ 2012-01-27  9:46 ` Jochen Friedrich
  34 siblings, 0 replies; 38+ messages in thread
From: Jochen Friedrich @ 2012-01-27  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 25.01.2012 15:30, Russell King - ARM Linux wrote:

> I've not heard anything back from anyone, so I'm going to assume that's
> silent approval.

Sorry, I just had a busy week...

FWIW: Acked-by: Jochen Friedrich <jochen@scram.de>

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2012-01-27  9:46 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-25 14:30 [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Russell King - ARM Linux
2012-01-25 14:30 ` [PATCH 01/33] Revert "ARM: sa1100: Refactor mcp-sa11x0 to use platform resources." Russell King - ARM Linux
2012-01-25 14:30 ` [PATCH 02/33] Revert "ARM: sa11x0: Implement autoloading of codec and codec pdata for mcp bus." Russell King - ARM Linux
2012-01-25 14:31 ` [PATCH 03/33] MFD: mcp-core: fix complaints from the genirq layer Russell King - ARM Linux
2012-01-25 14:31 ` [PATCH 04/33] MFD: mcp-core: fix mcp_priv() to be more type safe Russell King - ARM Linux
2012-01-25 14:31 ` [PATCH 05/33] MFD: ucb1x00-core: fix missing restore of io output data on resume Russell King - ARM Linux
2012-01-25 14:32 ` [PATCH 06/33] MFD: ucb1x00-core: fix gpiolib direction_output handling Russell King - ARM Linux
2012-01-25 14:32 ` [PATCH 07/33] MFD: ucb1x00-ts: fix resume failure Russell King - ARM Linux
2012-01-25 14:32 ` [PATCH 08/33] MFD: mcp-core: sanitize host creation/removal Russell King - ARM Linux
2012-01-25 14:33 ` [PATCH 09/33] MFD: mcp-sa11x0: remove DMA initializers and variables Russell King - ARM Linux
2012-01-25 14:33 ` [PATCH 10/33] MFD: mcp-sa11x0: move setup of PPC unit out of mcp-sa11x0.c Russell King - ARM Linux
2012-01-25 14:33 ` [PATCH 11/33] MFD: mcp-sa11x0: add .owner initializer Russell King - ARM Linux
2012-01-25 14:34 ` [PATCH 12/33] MFD: mcp-sa11x0: convert mcp-sa11x0 to use platform resources Russell King - ARM Linux
2012-01-25 14:34 ` [PATCH 13/33] MFD: mcp-sa11x0: convert to use dev_pm_ops Russell King - ARM Linux
2012-01-25 14:34 ` [PATCH 14/33] MFD: mcp-sa11x0: use _noirq resume methods Russell King - ARM Linux
2012-01-25 14:35 ` [PATCH 15/33] MFD: mcp/ucb1x00: separate ucb1x00 driver data from the MCP data Russell King - ARM Linux
2012-01-25 14:35 ` [PATCH 16/33] MFD: ucb1x00-ts: provide input layer with device parent Russell King - ARM Linux
2012-01-25 14:35 ` [PATCH 17/33] MFD: ucb1x00-core: get rid of mach/hardware.h include Russell King - ARM Linux
2012-01-25 14:36 ` [PATCH 18/33] MFD: ucb1x00-core: add handling for ucb1x00 reset Russell King - ARM Linux
2012-01-25 14:36 ` [PATCH 19/33] MFD: ucb1x00-core: add .owner initializer and module alias Russell King - ARM Linux
2012-01-25 14:36 ` [PATCH 20/33] MFD: ucb1x00-core: use mutexes instead of semaphores Russell King - ARM Linux
2012-01-25 14:37 ` [PATCH 21/33] MFD: ucb1x00-core: clean up device handling in probe Russell King - ARM Linux
2012-01-25 14:37 ` [PATCH 22/33] MFD: ucb1x00-core: add owner and dev initializers to gpio structure Russell King - ARM Linux
2012-01-25 14:37 ` [PATCH 23/33] MFD: ucb1x00-core: scan drivers in same order they're registered Russell King - ARM Linux
2012-01-25 14:38 ` [PATCH 24/33] MFD: ucb1x00-core: add missing ucb1x00_enable()/ucb1x00_disable() Russell King - ARM Linux
2012-01-25 14:38 ` [PATCH 25/33] MFD: ucb1x00-core: disable mcp clock when bus is not required Russell King - ARM Linux
2012-01-25 14:38 ` [PATCH 26/33] MFD: mcp-sa11x0: complain if mcp clock is left enabled Russell King - ARM Linux
2012-01-25 14:39 ` [PATCH 27/33] MFD: ucb1x00-core: convert to use dev_pm_ops Russell King - ARM Linux
2012-01-25 14:39 ` [PATCH 28/33] MFD: mcp-core: remove legacy driver suspend/resume methods Russell King - ARM Linux
2012-01-25 14:39 ` [PATCH 29/33] MFD: ucb1x00: convert to use genirq Russell King - ARM Linux
2012-01-25 14:40 ` [PATCH 30/33] MFD: ucb1x00-core: add wakeup support Russell King - ARM Linux
2012-01-25 14:40 ` [PATCH 31/33] ARM: sa11x0: add assabet ucb1x00 platform data Russell King - ARM Linux
2012-01-25 14:40 ` [PATCH 32/33] MFD: ucb1x00-assabet: add support for UCB1x00 GPIO switches Russell King - ARM Linux
2012-01-25 14:41 ` [PATCH 33/33] MFD: mcp-sa11x0/assabet: move assabet reset handling out of mcp-sa11x0.c Russell King - ARM Linux
2012-01-25 14:54 ` [PATCH 00/33] Restore SA11x0 MCP/UCB drivers to a working state Mark Brown
2012-01-25 21:14   ` Russell King - ARM Linux
2012-01-26 20:30     ` Samuel Ortiz
2012-01-27  9:46 ` Jochen Friedrich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.