[ARM] 3230/1: Sharp Scoop: Fix Shared Power Control Issues

Patch from Richard Purdie

The SL-Cxx00 devices have a power control register in SCOOP that is
shared by both CF and MMC/SD card slots. The CF reset code was resetting
this register leading to various lockups as the MMC power was suddenly
lost. This patch handles the CPR register in a more sensitive manner.

It also removes some unneeded collie specific calls as the reset code
handles this.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 0c3cbd9..b6de43e 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -33,7 +33,6 @@
 
 	SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100;  // 00
 	SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000;  // 04
-	SCOOP_REG(sdev->base,SCOOP_CPR) = 0x0000;  // 0C
 	SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000;  // 10
 	SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000;  // 18
 	SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF;  // 14
@@ -154,6 +153,7 @@
 
 	SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
 	reset_scoop(&pdev->dev);
+	SCOOP_REG(devptr->base, SCOOP_CPR) = 0x0000;
 	SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
 	SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
 
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 5d34abc..f2007db 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -127,10 +127,12 @@
 		        cpr &= ~0x0002;
 		if (device == SPITZ_PWR_SD)
 		        cpr &= ~0x0004;
-	        write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
 		if (!(cpr & 0x0002) && !(cpr & 0x0004)) {
+			write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, 0x0000);
 		        mdelay(1);
 		        reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+		} else {
+		        write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
 		}
 	}
 }
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index 56c5883..4fbd995 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -36,9 +36,18 @@
 struct scoop_pcmcia_config *platform_scoop_config;
 #define SCOOP_DEV platform_scoop_config->devs
 
-static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
+static void sharpsl_pcmcia_init_reset(struct soc_pcmcia_socket *skt)
 {
+	struct scoop_pcmcia_dev *scoopdev = &SCOOP_DEV[skt->nr];
+
 	reset_scoop(scoopdev->dev);
+
+	/* Shared power controls need to be handled carefully */
+	if (platform_scoop_config->power_ctrl)
+		platform_scoop_config->power_ctrl(scoopdev->dev, 0x0000, skt->nr);
+	else
+		write_scoop_reg(scoopdev->dev, SCOOP_CPR, 0x0000);
+
 	scoopdev->keep_vs = NO_KEEP_VS;
 	scoopdev->keep_rd = 0;
 }
@@ -208,26 +217,17 @@
 
 static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 {
-	sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
+	sharpsl_pcmcia_init_reset(skt);
 
 	/* Enable interrupt */
 	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
 	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
 	SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
-
-	if (machine_is_collie())
-		/* We need to disable SS_OUTPUT_ENA here. */
-		write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
 }
 
 static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-	/* CF_BUS_OFF */
-	sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
-
-	if (machine_is_collie())
-		/* We need to disable SS_OUTPUT_ENA here. */
-		write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+	sharpsl_pcmcia_init_reset(skt);
 }
 
 static struct pcmcia_low_level sharpsl_pcmcia_ops = {