[ARM] 4432/5: davinci: pin mux support

Support pin multiplexing configurations driver for TI DaVinci SoC

Signed-off-by: Vladimir Barinov <vbarinov@ru.mvista.com>
Acked-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 731c0a6..99ac2e5 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,7 +5,7 @@
 
 # Common objects
 obj-y 			:= time.o irq.o clock.o serial.o io.o id.o psc.o \
-			   gpio.o
+			   gpio.o mux.o
 
 # Board specific
 obj-$(CONFIG_MACH_DAVINCI_EVM)  += board-evm.o
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
new file mode 100644
index 0000000..92d26bd
--- /dev/null
+++ b/arch/arm/mach-davinci/mux.c
@@ -0,0 +1,41 @@
+/*
+ * DaVinci pin multiplexing configurations
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+
+/* System control register offsets */
+#define PINMUX0         0x00
+#define PINMUX1         0x04
+
+static DEFINE_SPINLOCK(mux_lock);
+
+void davinci_mux_peripheral(unsigned int mux, unsigned int enable)
+{
+	u32 pinmux, muxreg = PINMUX0;
+
+	if (mux >= DAVINCI_MUX_LEVEL2) {
+		muxreg = PINMUX1;
+		mux -= DAVINCI_MUX_LEVEL2;
+	}
+
+	spin_lock(&mux_lock);
+	pinmux = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + muxreg);
+	if (enable)
+		pinmux |= (1 << mux);
+	else
+		pinmux &= ~(1 << mux);
+	davinci_writel(pinmux, DAVINCI_SYSTEM_MODULE_BASE + muxreg);
+	spin_unlock(&mux_lock);
+}
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index e1b0050..1334416 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -25,39 +25,40 @@
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/arch/psc.h>
+#include <asm/arch/mux.h>
 
-#define PTCMD	     __REG(0x01C41120)
-#define PDSTAT	     __REG(0x01C41200)
-#define PDCTL1	     __REG(0x01C41304)
-#define EPCPR	     __REG(0x01C41070)
-#define PTSTAT	     __REG(0x01C41128)
+/* PSC register offsets */
+#define EPCPR		0x070
+#define PTCMD		0x120
+#define PTSTAT		0x128
+#define PDSTAT		0x200
+#define PDCTL1		0x304
+#define MDSTAT		0x800
+#define MDCTL		0xA00
 
-#define MDSTAT	     IO_ADDRESS(0x01C41800)
-#define MDCTL	     IO_ADDRESS(0x01C41A00)
-
-#define PINMUX0	     __REG(0x01c40000)
-#define PINMUX1	     __REG(0x01c40004)
-#define VDD3P3V_PWDN __REG(0x01C40048)
+/* System control register offsets */
+#define VDD3P3V_PWDN	0x48
 
 static void davinci_psc_mux(unsigned int id)
 {
 	switch (id) {
 	case DAVINCI_LPSC_ATA:
-		PINMUX0 |= (1 << 17) | (1 << 16);
+		davinci_mux_peripheral(DAVINCI_MUX_HDIREN, 1);
+		davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 1);
 		break;
 	case DAVINCI_LPSC_MMC_SD:
 		/* VDD power manupulations are done in U-Boot for CPMAC
 		 * so applies to MMC as well
 		 */
 		/*Set up the pull regiter for MMC */
-		VDD3P3V_PWDN = 0x0;
-		PINMUX1 &= (~(1 << 9));
+		davinci_writel(0, DAVINCI_SYSTEM_MODULE_BASE + VDD3P3V_PWDN);
+		davinci_mux_peripheral(DAVINCI_MUX_MSTK, 0);
 		break;
 	case DAVINCI_LPSC_I2C:
-		PINMUX1 |= (1 << 7);
+		davinci_mux_peripheral(DAVINCI_MUX_I2C, 1);
 		break;
 	case DAVINCI_LPSC_McBSP:
-		PINMUX1 |= (1 << 10);
+		davinci_mux_peripheral(DAVINCI_MUX_ASP, 1);
 		break;
 	default:
 		break;
@@ -67,33 +68,59 @@
 /* Enable or disable a PSC domain */
 void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
 {
-	volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id);
-	volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id);
+	u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask;
 
 	if (id < 0)
 		return;
 
+	mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id);
 	if (enable)
-		*mdctl |= 0x00000003;	/* Enable Module */
+		mdctl |= 0x00000003;	/* Enable Module */
 	else
-		*mdctl &= 0xFFFFFFF2;	/* Disable Module */
+		mdctl &= 0xFFFFFFF2;	/* Disable Module */
+	davinci_writel(mdctl, DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id);
 
-	if ((PDSTAT & 0x00000001) == 0) {
-		PDCTL1 |= 0x1;
-		PTCMD = (1 << domain);
-		while ((((EPCPR >> domain) & 1) == 0));
+	pdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDSTAT);
+	if ((pdstat & 0x00000001) == 0) {
+		pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+		pdctl1 |= 0x1;
+		davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
 
-		PDCTL1 |= 0x100;
-		while (!(((PTSTAT >> domain) & 1) == 0));
+		ptcmd = 1 << domain;
+		davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD);
+
+		do {
+			epcpr = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+					      EPCPR);
+		} while ((((epcpr >> domain) & 1) == 0));
+
+		pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+		pdctl1 |= 0x100;
+		davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+
+		do {
+			ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+					       PTSTAT);
+		} while (!(((ptstat >> domain) & 1) == 0));
 	} else {
-		PTCMD = (1 << domain);
-		while (!(((PTSTAT >> domain) & 1) == 0));
+		ptcmd = 1 << domain;
+		davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD);
+
+		do {
+			ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+					       PTSTAT);
+		} while (!(((ptstat >> domain) & 1) == 0));
 	}
 
 	if (enable)
-		while (!((*mdstat & 0x0000001F) == 0x3));
+		mdstat_mask = 0x3;
 	else
-		while (!((*mdstat & 0x0000001F) == 0x2));
+		mdstat_mask = 0x2;
+
+	do {
+		mdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+				       MDSTAT + 4 * id);
+	} while (!((mdstat & 0x0000001F) == mdstat_mask));
 
 	if (enable)
 		davinci_psc_mux(id);