Merge "msm: camera: ISPIF changes for V2" into msm-3.0
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index eb9b463..b2dbee3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -134,6 +134,15 @@
 	default y
 	depends on SMP && PREEMPT
 
+config ARM_TICKET_LOCKS
+	bool
+	help
+	  Enable ticket locks, which help preserve fairness among
+	  contended locks and prevent livelock in multicore systems.
+	  Say 'y' if system stability is important.
+	default y if ARCH_MSM_SCORPIONMP
+	depends on SMP
+
 config RWSEM_GENERIC_SPINLOCK
 	bool
 	default y
@@ -1350,7 +1359,7 @@
 		 ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
 		 MSM_SMP || ARCH_SHMOBILE
 	select USE_GENERIC_SMP_HELPERS
-	select HAVE_ARM_SCU if !MSM_SMP
+	select HAVE_ARM_SCU
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
@@ -2146,7 +2155,7 @@
 source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
-	depends on !ARCH_S5P64X0 && !ARCH_S5PC100 && !ARCH_FSM9XXX && !ARCH_MSM9615
+	depends on !ARCH_S5P64X0 && !ARCH_S5PC100 && !ARCH_FSM9XXX
 	depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
 		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
 	def_bool y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 11821ee..8be0165 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -17,7 +17,7 @@
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
+CONFIG_OPROFILE=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
@@ -52,7 +52,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-# CONFIG_CP_ACCESS is not set
+CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 827d5d9..ed4fd41 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -16,7 +16,7 @@
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
+CONFIG_OPROFILE=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
@@ -51,7 +51,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-# CONFIG_CP_ACCESS is not set
+CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 9f31996..143fe2b 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -171,6 +171,7 @@
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 # CONFIG_RFKILL_PM is not set
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index b7a7b34..ad49cdd 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -170,6 +170,7 @@
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 # CONFIG_RFKILL_PM is not set
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 2cd7953..0f03453 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -210,6 +210,7 @@
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 CONFIG_BLK_DEV_LOOP=y
@@ -319,7 +320,7 @@
 CONFIG_FB_MSM_MDP40=y
 CONFIG_FB_MSM_OVERLAY=y
 CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
-CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT=y
+CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 705021a..4b2b909 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -201,6 +201,7 @@
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 CONFIG_BLK_DEV_LOOP=y
@@ -310,7 +311,7 @@
 CONFIG_FB_MSM_MDP40=y
 CONFIG_FB_MSM_OVERLAY=y
 CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
-CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT=y
+CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 2f512c5..ddbe87c 100755
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -59,6 +59,7 @@
 CONFIG_MSM_WCNSS_SSR_8960=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_QDSS=y
@@ -214,6 +215,7 @@
 CONFIG_SMC91X=y
 CONFIG_SMC911X=y
 CONFIG_SMSC911X=y
+CONFIG_KS8851=m
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
 CONFIG_WCNSS_CORE=m
@@ -283,6 +285,7 @@
 CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
 CONFIG_FB_MSM_MDP40=y
 CONFIG_FB_MSM_OVERLAY=y
 CONFIG_FB_MSM_OVERLAY_WRITEBACK=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 2dbdb8f..52a4d20 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -53,6 +53,7 @@
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -61,6 +62,7 @@
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_PM=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_MISC_DEVICES=y
@@ -98,6 +100,39 @@
 CONFIG_REGULATOR=y
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_CLKGATE is not set
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SDIO_SUPPORT=y
+# CONFIG_MMC_MSM_CARD_HW_DETECTION is not set
+CONFIG_MMC_MSM_SDC1_SUPPORT=y
+# CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT is not set
+CONFIG_MMC_MSM_SDC2_SUPPORT=y
+# CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT is not set
+# CONFIG_MMC_MSM_SDC3_SUPPORT is not set
+# CONFIG_MMC_MSM_SDC4_SUPPORT is not set
+# CONFIG_MMC_MSM_SDC5_SUPPORT is not set
+# CONFIG_MMC_MSM_SPS_SUPPORT is not set
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 89ad180..2635c8b 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	5
+#define NR_IPI	6
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 65fa3c8..582c9b3 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -58,6 +58,7 @@
 #endif
 }
 
+#ifndef CONFIG_ARM_TICKET_LOCKS
 /*
  * ARMv6 Spin-locking.
  *
@@ -126,6 +127,131 @@
 
 	dsb_sev();
 }
+#else
+/*
+ * ARM Ticket spin-locking
+ *
+ * Ticket locks are conceptually two parts, one indicating the current head of
+ * the queue, and the other indicating the current tail. The lock is acquired
+ * by atomically noting the tail and incrementing it by one (thus adding
+ * ourself to the queue and noting our position), then waiting until the head
+ * becomes equal to the the initial value of the tail.
+ *
+ * Unlocked value: 0
+ * Locked value: now_serving != next_ticket
+ *
+ *   31             17  16    15  14                    0
+ *  +----------------------------------------------------+
+ *  |  now_serving          |     next_ticket            |
+ *  +----------------------------------------------------+
+ */
+
+#define TICKET_SHIFT	16
+#define TICKET_BITS	16
+#define	TICKET_MASK	0xFFFF
+
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+	unsigned long tmp, ticket, next_ticket;
+
+	/* Grab the next ticket and wait for it to be "served" */
+	__asm__ __volatile__(
+"1:	ldrex	%[ticket], [%[lockaddr]]\n"
+"	uadd16	%[next_ticket], %[ticket], %[val1]\n"
+"	strex	%[tmp], %[next_ticket], [%[lockaddr]]\n"
+"	teq	%[tmp], #0\n"
+"	bne	1b\n"
+"	uxth	%[ticket], %[ticket]\n"
+"2:\n"
+#ifdef CONFIG_CPU_32v6K
+"	wfene\n"
+#endif
+"	ldr	%[tmp], [%[lockaddr]]\n"
+"	cmp	%[ticket], %[tmp], lsr #16\n"
+"	bne	2b"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp), [next_ticket]"=&r" (next_ticket)
+	: [lockaddr]"r" (&lock->lock), [val1]"r" (1)
+	: "cc");
+	smp_mb();
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+	unsigned long tmp, ticket, next_ticket;
+
+	/* Grab lock if now_serving == next_ticket and access is exclusive */
+	__asm__ __volatile__(
+"	ldrex	%[ticket], [%[lockaddr]]\n"
+"	ror	%[tmp], %[ticket], #16\n"
+"	eors	%[tmp], %[tmp], %[ticket]\n"
+"	bne	1f\n"
+"	uadd16	%[next_ticket], %[ticket], %[val1]\n"
+"	strex	%[tmp], %[next_ticket], [%[lockaddr]]\n"
+"1:"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
+	  [next_ticket]"=&r" (next_ticket)
+	: [lockaddr]"r" (&lock->lock), [val1]"r" (1)
+	: "cc");
+	if (!tmp)
+		smp_mb();
+	return !tmp;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+	unsigned long ticket, tmp;
+
+	smp_mb();
+
+	/* Bump now_serving by 1 */
+	__asm__ __volatile__(
+"1:	ldrex	%[ticket], [%[lockaddr]]\n"
+"	uadd16	%[ticket], %[ticket], %[serving1]\n"
+"	strex	%[tmp], %[ticket], [%[lockaddr]]\n"
+"	teq	%[tmp], #0\n"
+"	bne	1b"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp)
+	: [lockaddr]"r" (&lock->lock), [serving1]"r" (0x00010000)
+	: "cc");
+	dsb_sev();
+}
+
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+	unsigned long ticket;
+
+	/* Wait for now_serving == next_ticket */
+	__asm__ __volatile__(
+#ifdef CONFIG_CPU_32v6K
+"	cmpne	%[lockaddr], %[lockaddr]\n"
+"1:	wfene\n"
+#else
+"1:\n"
+#endif
+"	ldr	%[ticket], [%[lockaddr]]\n"
+"	eor	%[ticket], %[ticket], %[ticket], lsr #16\n"
+"	uxth	%[ticket], %[ticket]\n"
+"	cmp	%[ticket], #0\n"
+"	bne	1b"
+	: [ticket]"=&r" (ticket)
+	: [lockaddr]"r" (&lock->lock)
+	: "cc");
+}
+
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+	unsigned long tmp = ACCESS_ONCE(lock->lock);
+	return (((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK) != 0;
+}
+
+static inline int arch_spin_is_contended(arch_spinlock_t *lock)
+{
+	unsigned long tmp = ACCESS_ONCE(lock->lock);
+	return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
+}
+#endif
 
 /*
  * RWLOCKS
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index a9d1a5c..5478f55 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -48,6 +48,7 @@
 struct secondary_data secondary_data;
 
 enum ipi_msg_type {
+	IPI_CPU_START = 1,
 	IPI_TIMER = 2,
 	IPI_RESCHEDULE,
 	IPI_CALL_FUNC,
@@ -399,7 +400,8 @@
 }
 
 static const char *ipi_types[NR_IPI] = {
-#define S(x,s)	[x - IPI_TIMER] = s
+#define S(x,s)	[x - IPI_CPU_START] = s
+	S(IPI_CPU_START, "CPU start interrupts"),
 	S(IPI_TIMER, "Timer broadcast interrupts"),
 	S(IPI_RESCHEDULE, "Rescheduling interrupts"),
 	S(IPI_CALL_FUNC, "Function call interrupts"),
@@ -563,10 +565,13 @@
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
-	if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI)
-		__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]);
+	if (ipinr >= IPI_CPU_START && ipinr < IPI_CPU_START + NR_IPI)
+		__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_CPU_START]);
 
 	switch (ipinr) {
+	case IPI_CPU_START:
+		/* Wake up from WFI/WFE using SGI */
+		break;
 	case IPI_TIMER:
 		ipi_timer();
 		break;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 1e5f485..2acc8e0 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -134,6 +134,15 @@
 	select MSM_NATIVE_RESTART
         select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_REMOTE_SPINLOCK_SFPB
+	select ARCH_POPULATES_NODE_MAP
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_HAS_HOLES_MEMORYMODEL
+	select MEMORY_HOTPLUG
+	select MEMORY_HOTREMOVE
+	select MIGRATION
+	select ARCH_MEMORY_PROBE
+	select ARCH_MEMORY_REMOVE
+	select DONT_RESERVE_FROM_MOVABLE_ZONE
 
 config ARCH_APQ8064
 	bool "APQ8064"
@@ -887,13 +896,6 @@
 	    prompt "Package 4"
 endchoice
 
-config MSM_IPC_ROUTER_SMD_XPRT
-	depends on MSM_SMD
-	default n
-	bool "MSM SMD XPRT Layer"
-	help
-	  SMD Transport Layer for IPC Router
-
 config MSM_RPC_SDIO_XPRT
 	depends on MSM_SDIO_AL
 	default y
@@ -1055,13 +1057,21 @@
 	  the ARM9 and ARM11
 
 config MSM_IPC_ROUTER
-	depends on MSM_IPC_ROUTER_SMD_XPRT
+	depends on NET
 	default n
 	bool "MSM IPC Router support"
 	help
 	  Support for the MSM IPC Router for communication between
 	  the APPs and the MODEM
 
+config MSM_IPC_ROUTER_SMD_XPRT
+	depends on MSM_SMD
+	depends on MSM_IPC_ROUTER
+	default n
+	bool "MSM SMD XPRT Layer"
+	help
+	  SMD Transport Layer for IPC Router
+
 config MSM_ONCRPCROUTER_DEBUG
 	depends on MSM_ONCRPCROUTER
 	default y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a469e7d..0d36b0a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -130,6 +130,7 @@
 ifdef CONFIG_PM
 	obj-$(CONFIG_ARCH_MSM8960) += pm-8x60.o
 	obj-$(CONFIG_ARCH_MSM8X60) += pm-8x60.o
+	obj-$(CONFIG_ARCH_MSM9615) += pm-8x60.o
 	obj-$(CONFIG_ARCH_QSD8X50) += pm2.o
 	obj-$(CONFIG_ARCH_MSM7X30) += pm2.o
 	obj-$(CONFIG_ARCH_MSM7X27) += pm2.o
@@ -157,7 +158,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o
 obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
 obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
-obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o rpm-regulator-8660.o
 obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
 
 ifdef CONFIG_MSM_SUBSYSTEM_RESTART
@@ -174,6 +175,7 @@
 ifdef CONFIG_CPU_IDLE
 	obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
 	obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
 endif
 
 obj-$(CONFIG_ARCH_FSM9XXX) += devices-fsm9xxx.o
@@ -207,7 +209,8 @@
 obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o
 obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
 obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
-obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator-8960.o memory_topology.o
+obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
+obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator.o rpm-regulator-8960.o
 obj-$(CONFIG_MACH_MSM8960_SIM) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
@@ -216,7 +219,8 @@
 obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o
 obj-$(CONFIG_ARCH_APQ8064) += board-apq8064.o devices-8064.o board-apq8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o
-obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o
+obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
+obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator.o rpm-regulator-9615.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index a5a6ff1..1d0e1a8 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -223,8 +223,6 @@
 static struct l2_level *l2_freq_tbl;
 static struct acpu_level *acpu_freq_tbl;
 static int l2_freq_tbl_size;
-static int cpu_boot_idx;
-static int l2_boot_idx;
 
 /* Instantaneous bandwidth requests in MB/s. */
 #define BW_MBPS(_bw) \
@@ -415,10 +413,6 @@
 	/* Wait for switch to complete. */
 	mb();
 	udelay(1);
-
-	/* Re-enable secondary source clock gating. */
-	regval &= ~SECCLKAGD;
-	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 }
 
 /* Enable an already-configured HFPLL. */
@@ -875,9 +869,11 @@
 
 static void __init per_cpu_init(void *data)
 {
+	struct acpu_level *max_acpu_level = data;
 	int cpu = smp_processor_id();
-	init_clock_sources(&scalable[cpu], &acpu_freq_tbl[cpu_boot_idx].speed);
-	scalable[cpu].l2_vote = &l2_freq_tbl[l2_boot_idx];
+
+	init_clock_sources(&scalable[cpu], &max_acpu_level->speed);
+	scalable[cpu].l2_vote = max_acpu_level->l2_level;
 }
 
 /* Register with bus driver. */
@@ -988,6 +984,35 @@
 	.notifier_call = acpuclock_cpu_callback,
 };
 
+static struct acpu_level * __init select_freq_plan(void)
+{
+	struct acpu_level *l, *max_acpu_level = NULL;
+
+	/* Select frequency tables. */
+	if (cpu_is_msm8960()) {
+		scalable = scalable_8960;
+		acpu_freq_tbl = acpu_freq_tbl_8960;
+		l2_freq_tbl = l2_freq_tbl_8960;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960);
+	} else if (cpu_is_apq8064()) {
+		scalable = scalable_8064;
+		acpu_freq_tbl = acpu_freq_tbl_8064;
+		l2_freq_tbl = l2_freq_tbl_8064;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
+	} else {
+		BUG();
+	}
+
+	/* Find the max supported scaling frequency. */
+	for (l = acpu_freq_tbl; l->speed.khz != 0; l++)
+		if (l->use_for_scaling)
+			max_acpu_level = l;
+	BUG_ON(!max_acpu_level);
+	pr_info("Max ACPU freq: %u KHz\n", max_acpu_level->speed.khz);
+
+	return max_acpu_level;
+}
+
 static struct acpuclk_data acpuclk_8960_data = {
 	.set_rate = acpuclk_8960_set_rate,
 	.get_rate = acpuclk_8960_get_rate,
@@ -997,24 +1022,9 @@
 
 static int __init acpuclk_8960_init(struct acpuclk_soc_data *soc_data)
 {
-	if (cpu_is_msm8960()) {
-		scalable = scalable_8960;
-		acpu_freq_tbl = acpu_freq_tbl_8960;
-		l2_freq_tbl = l2_freq_tbl_8960;
-		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960);
-		l2_boot_idx = 11;
-		cpu_boot_idx = 11;
-	} else if (cpu_is_apq8064()) {
-		scalable = scalable_8064;
-		acpu_freq_tbl = acpu_freq_tbl_8064;
-		l2_freq_tbl = l2_freq_tbl_8064;
-		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
-		l2_boot_idx = 11;
-		cpu_boot_idx = 11;
-	}
-
-	init_clock_sources(&scalable[L2], &l2_freq_tbl[l2_boot_idx].speed);
-	on_each_cpu(per_cpu_init, NULL, true);
+	struct acpu_level *max_acpu_level = select_freq_plan();
+	init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
+	on_each_cpu(per_cpu_init, max_acpu_level, true);
 
 	regulator_init();
 	bus_init();
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 728dbf1..5ed4456 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -201,6 +201,7 @@
 	rx_skb->data = (unsigned char *)(rx_hdr + 1);
 	rx_skb->tail = rx_skb->data + rx_hdr->pkt_len;
 	rx_skb->len = rx_hdr->pkt_len;
+	rx_skb->truesize = rx_hdr->pkt_len + sizeof(struct sk_buff);
 
 	event_data = (unsigned long)(rx_skb);
 
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index ed93c3a..aa6ce58 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -25,6 +25,8 @@
 #include "timer.h"
 #include "devices.h"
 #include "board-9615.h"
+#include "cpuidle.h"
+#include "pm.h"
 
 static struct platform_device *common_devices[] = {
 	&msm9615_device_dmov,
@@ -415,6 +417,36 @@
 #else
 static void __init msm9615_init_mmc(void) { }
 #endif
+static  struct msm_cpuidle_state msm_cstates[] __initdata = {
+	{0, 0, "C0", "WFI",
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+	{0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+	{0, 2, "C2", "POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
+};
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+	},
+};
 
 static int __init gpiomux_init(void)
 {
@@ -460,6 +492,10 @@
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 
 	msm9615_init_mmc();
+	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
+	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
+						msm_pm_data);
 }
 
 static void __init msm9615_cdp_init(void)
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 5f205f4..9629b5c 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -58,16 +58,17 @@
 #include <linux/android_pmem.h>
 #include <mach/camera.h>
 
+#ifdef CONFIG_USB_G_ANDROID
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#endif
+
 #include "devices.h"
 #include "clock.h"
 #include "acpuclock.h"
 #include "msm-keypad-devices.h"
 #include "pm.h"
 
-#ifdef CONFIG_USB_ANDROID
-#include <linux/usb/android_composite.h>
-#endif
-
 #ifdef CONFIG_ARCH_MSM7X25
 #define MSM_PMEM_MDP_SIZE	0xb21000
 #define MSM_PMEM_ADSP_SIZE	0x97b000
@@ -103,135 +104,16 @@
 	},
 };
 
-#ifdef CONFIG_USB_FUNCTION
-static struct usb_mass_storage_platform_data usb_mass_storage_pdata = {
-	.nluns          = 0x02,
-	.buf_size       = 16384,
-	.vendor         = "GOOGLE",
-	.product        = "Mass storage",
-	.release        = 0xffff,
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
 };
 
-static struct platform_device mass_storage_device = {
-	.name           = "usb_mass_storage",
-	.id             = -1,
-	.dev            = {
-		.platform_data          = &usb_mass_storage_pdata,
-	},
-};
-#endif
-#ifdef CONFIG_USB_ANDROID
-static char *usb_functions_default[] = {
-	"diag",
-	"modem",
-	"nmea",
-	"rmnet",
-	"usb_mass_storage",
-};
-
-static char *usb_functions_default_adb[] = {
-	"diag",
-	"adb",
-	"modem",
-	"nmea",
-	"rmnet",
-	"usb_mass_storage",
-};
-
-static char *usb_functions_rndis[] = {
-	"rndis",
-};
-
-static char *usb_functions_rndis_adb[] = {
-	"rndis",
-	"adb",
-};
-
-static char *usb_functions_all[] = {
-#ifdef CONFIG_USB_ANDROID_RNDIS
-	"rndis",
-#endif
-#ifdef CONFIG_USB_ANDROID_DIAG
-	"diag",
-#endif
-	"adb",
-#ifdef CONFIG_USB_F_SERIAL
-	"modem",
-	"nmea",
-#endif
-#ifdef CONFIG_USB_ANDROID_RMNET
-	"rmnet",
-#endif
-	"usb_mass_storage",
-#ifdef CONFIG_USB_ANDROID_ACM
-	"acm",
-#endif
-};
-
-static struct android_usb_product usb_products[] = {
-	{
-		.product_id	= 0x9026,
-		.num_functions	= ARRAY_SIZE(usb_functions_default),
-		.functions	= usb_functions_default,
-	},
-	{
-		.product_id	= 0x9025,
-		.num_functions	= ARRAY_SIZE(usb_functions_default_adb),
-		.functions	= usb_functions_default_adb,
-	},
-	{
-		.product_id	= 0xf00e,
-		.num_functions	= ARRAY_SIZE(usb_functions_rndis),
-		.functions	= usb_functions_rndis,
-	},
-	{
-		.product_id	= 0x9024,
-		.num_functions	= ARRAY_SIZE(usb_functions_rndis_adb),
-		.functions	= usb_functions_rndis_adb,
-	},
-};
-
-static struct usb_mass_storage_platform_data mass_storage_pdata = {
-	.nluns		= 1,
-	.vendor		= "Qualcomm Incorporated",
-	.product        = "Mass storage",
-	.release	= 0x0100,
-	.can_stall	= 1,
-};
-
-static struct platform_device usb_mass_storage_device = {
-	.name	= "usb_mass_storage",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &mass_storage_pdata,
-	},
-};
-
-static struct usb_ether_platform_data rndis_pdata = {
-	/* ethaddr is filled by board_serialno_setup */
-	.vendorID	= 0x05C6,
-	.vendorDescr	= "Qualcomm Incorporated",
-};
-
-static struct platform_device rndis_device = {
-	.name	= "rndis",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &rndis_pdata,
-	},
-};
-
+#ifdef CONFIG_USB_G_ANDROID
 static struct android_usb_platform_data android_usb_pdata = {
-	.vendor_id	= 0x05C6,
-	.product_id	= 0x9026,
-	.version	= 0x0100,
-	.product_name		= "Qualcomm HSUSB Device",
-	.manufacturer_name	= "Qualcomm Incorporated",
-	.num_products = ARRAY_SIZE(usb_products),
-	.products = usb_products,
-	.num_functions = ARRAY_SIZE(usb_functions_all),
-	.functions = usb_functions_all,
-	.serial_number = "1234567890ABCDEF",
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
 };
 
 static struct platform_device android_usb_device = {
@@ -241,114 +123,6 @@
 		.platform_data = &android_usb_pdata,
 	},
 };
-
-static int __init board_serialno_setup(char *serialno)
-{
-	int i;
-	char *src = serialno;
-
-	/* create a fake MAC address from our serial number.
-	 * first byte is 0x02 to signify locally administered.
-	 */
-	rndis_pdata.ethaddr[0] = 0x02;
-	for (i = 0; *src; i++) {
-		/* XOR the USB serial across the remaining bytes */
-		rndis_pdata.ethaddr[i % (ETH_ALEN - 1) + 1] ^= *src++;
-	}
-
-	android_usb_pdata.serial_number = serialno;
-	return 1;
-}
-__setup("androidboot.serialno=", board_serialno_setup);
-#endif
-
-static struct platform_device smc91x_device = {
-	.name		= "smc91x",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(smc91x_resources),
-	.resource	= smc91x_resources,
-};
-
-#ifdef CONFIG_USB_FUNCTION
-static struct usb_function_map usb_functions_map[] = {
-	{"diag", 0},
-	{"adb", 1},
-	{"modem", 2},
-	{"nmea", 3},
-	{"mass_storage", 4},
-	{"ethernet", 5},
-	{"rmnet", 6},
-};
-
-/* dynamic composition */
-static struct usb_composition usb_func_composition[] = {
-	{
-		.product_id         = 0x9012,
-		.functions	    = 0x5, /* 0101 */
-	},
-
-	{
-		.product_id         = 0x9013,
-		.functions	    = 0x15, /* 10101 */
-	},
-
-	{
-		.product_id         = 0x9014,
-		.functions	    = 0x30, /* 110000 */
-	},
-
-	{
-		.product_id         = 0x9016,
-		.functions	    = 0xD, /* 01101 */
-	},
-
-	{
-		.product_id         = 0x9017,
-		.functions	    = 0x1D, /* 11101 */
-	},
-
-	{
-		.product_id         = 0xF000,
-		.functions	    = 0x10, /* 10000 */
-	},
-
-	{
-		.product_id         = 0xF009,
-		.functions	    = 0x20, /* 100000 */
-	},
-
-	{
-		.product_id         = 0x9018,
-		.functions	    = 0x1F, /* 011111 */
-	},
-#ifdef CONFIG_USB_FUNCTION_RMNET
-	{
-		.product_id         = 0x9021,
-		/* DIAG + RMNET */
-		.functions	    = 0x41,
-	},
-	{
-		.product_id         = 0x9022,
-		/* DIAG + ADB + RMNET */
-		.functions	    = 0x43,
-	},
-#endif
-
-};
-
-static struct msm_hsusb_platform_data msm_hsusb_pdata = {
-	.version	= 0x0100,
-	.phy_info	= (USB_PHY_INTEGRATED | USB_PHY_MODEL_65NM),
-	.vendor_id          = 0x5c6,
-	.product_name       = "Qualcomm HSUSB Device",
-	.serial_number      = "1234567890ABCDEF",
-	.manufacturer_name  = "Qualcomm Incorporated",
-	.compositions	= usb_func_composition,
-	.num_compositions = ARRAY_SIZE(usb_func_composition),
-	.function_map   = usb_functions_map,
-	.num_functions	= ARRAY_SIZE(usb_functions_map),
-	.config_gpio    = NULL,
-};
 #endif
 
 #ifdef CONFIG_USB_EHCI_MSM_72K
@@ -1410,22 +1184,10 @@
 #endif
 #endif
 
-#ifdef CONFIG_USB_FUNCTION
-	&msm_device_hsusb_peripheral,
-	&mass_storage_device,
-#endif
-
-#ifdef CONFIG_USB_ANDROID
-	&usb_mass_storage_device,
-	&rndis_device,
-#ifdef CONFIG_USB_ANDROID_DIAG
-	&usb_diag_device,
-#endif
-#ifdef CONFIG_USB_F_SERIAL
-	&usb_gadget_fserial_device,
-#endif
+#ifdef CONFIG_USB_G_ANDROID
 	&android_usb_device,
 #endif
+
 	&msm_device_i2c,
 	&smc91x_device,
 	&msm_device_tssc,
@@ -1891,13 +1653,6 @@
 
 	usb_mpp_init();
 
-#ifdef CONFIG_USB_FUNCTION
-	msm_hsusb_pdata.swfi_latency =
-		msm7x27_pm_data
-		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
-
-	msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata;
-#endif
 
 #ifdef CONFIG_USB_MSM_OTG_72K
 	msm_device_otg.dev.platform_data = &msm_otg_pdata;
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index f51c61d..67b1dcc 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -638,65 +638,80 @@
 			goto reg_disable;
 		}
 
+		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
+				bt_vregs[i].level, bt_vregs[i].level) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not set voltage for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not %sable regulator %s: %d\n",
+					__func__, "en", bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
 		if (bt_vregs[i].is_pin_controlled) {
-			rc = pmapp_vreg_pincntrl_vote(id,
+			rc = pmapp_vreg_lpm_pincntrl_vote(id,
 					bt_vregs[i].pmapp_id,
 					PMAPP_CLOCK_ID_D1,
 					on ? PMAPP_CLOCK_VOTE_ON :
 						PMAPP_CLOCK_VOTE_OFF);
-		} else {
-			rc = on ? regulator_enable(bt_vregs[i].reg) :
-				regulator_disable(bt_vregs[i].reg);
+			if (rc) {
+				dev_err(&msm_bt_power_device.dev,
+					"%s: pin control failed for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+				goto pin_cnt_fail;
+			}
 		}
+		rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
 
 		if (rc) {
 			dev_err(&msm_bt_power_device.dev,
 				"%s: could not %sable regulator %s: %d\n",
-				__func__, on ? "en" : "dis",
-				bt_vregs[i].name, rc);
-			i++;
+				__func__, "dis", bt_vregs[i].name, rc);
 			goto reg_disable;
 		}
 	}
 
 	return rc;
-
+pin_cnt_fail:
+	if (on)
+		regulator_disable(bt_vregs[i].reg);
 reg_disable:
-	while (i--) {
-		if (bt_vregs[i].is_pin_controlled) {
-			pmapp_vreg_pincntrl_vote(id, bt_vregs[i].pmapp_id,
-					PMAPP_CLOCK_ID_D1,
-					on ? PMAPP_CLOCK_VOTE_OFF :
-						PMAPP_CLOCK_VOTE_ON);
-		} else {
-			if (on)
-				regulator_disable(bt_vregs[i].reg);
-			else
-				regulator_enable(bt_vregs[i].reg);
+	while (i) {
+		if (on) {
+			i--;
+			regulator_disable(bt_vregs[i].reg);
+			regulator_put(bt_vregs[i].reg);
 		}
 	}
 	return rc;
 }
 
-static struct regulator *reg_bahama;
+static struct regulator *reg_s3;
 static unsigned int msm_bahama_setup_power(void)
 {
 	int rc = 0;
 
-	reg_bahama = regulator_get(NULL, "msme1");
-	if (IS_ERR(reg_bahama)) {
-		rc = PTR_ERR(reg_bahama);
+	reg_s3 = regulator_get(NULL, "msme1");
+	if (IS_ERR(reg_s3)) {
+		rc = PTR_ERR(reg_s3);
 		pr_err("%s: could not get regulator: %d\n", __func__, rc);
 		goto out;
 	}
 
-	rc = regulator_set_voltage(reg_bahama, 1800000, 1800000);
+	rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
 	if (rc) {
 		pr_err("%s: could not set voltage: %d\n", __func__, rc);
 		goto reg_fail;
 	}
 
-	rc = regulator_enable(reg_bahama);
+	rc = regulator_enable(reg_s3);
 	if (rc < 0) {
 		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
 		goto reg_fail;
@@ -722,11 +737,11 @@
 gpio_fail:
 	gpio_free(GPIO_BT_SYS_REST_EN);
 reg_disable:
-	regulator_disable(reg_bahama);
+	regulator_disable(reg_s3);
 reg_fail:
-	regulator_put(reg_bahama);
+	regulator_put(reg_s3);
 out:
-	reg_bahama = NULL;
+	reg_s3 = NULL;
 	return rc;
 }
 
@@ -734,12 +749,12 @@
 {
 	int rc = 0;
 
-	if (IS_ERR_OR_NULL(reg_bahama)) {
-		rc = reg_bahama ? PTR_ERR(reg_bahama) : -ENODEV;
+	if (IS_ERR_OR_NULL(reg_s3)) {
+		rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
 		goto out;
 	}
 
-	rc = regulator_disable(reg_bahama);
+	rc = regulator_disable(reg_s3);
 	if (rc) {
 		pr_err("%s: could not disable regulator: %d\n", __func__, rc);
 		goto out;
@@ -750,18 +765,15 @@
 		if (rc) {
 			pr_err("%s: bt_set_gpio = %d\n",
 					__func__, rc);
-			goto reg_enable;
 		}
 		gpio_free(GPIO_BT_SYS_REST_EN);
 	}
 
-	regulator_put(reg_bahama);
-	reg_bahama = NULL;
+	regulator_put(reg_s3);
+	reg_s3 = NULL;
 
 	return 0;
 
-reg_enable:
-	regulator_enable(reg_bahama);
 out:
 	return rc;
 }
@@ -933,21 +945,12 @@
 					__func__, bt_vregs[i].name, rc);
 			goto reg_get_fail;
 		}
-		rc = regulator_set_voltage(bt_vregs[i].reg,
-				bt_vregs[i].level, bt_vregs[i].level);
-		if (rc) {
-			dev_err(dev, "%s: could not set voltage for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_set_fail;
-		}
 	}
 
 	dev->platform_data = &bluetooth_power;
 
 	return rc;
 
-reg_set_fail:
-	i++;
 reg_get_fail:
 	while (i--) {
 		regulator_put(bt_vregs[i].reg);
@@ -1832,18 +1835,29 @@
 	}
 };
 
+#define PANEL_NAME_MAX_LEN	30
+#define LCDC_TOSHIBA_FWVGA_PANEL_NAME	"lcdc_toshiba_fwvga_pt"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
+
 static int msm_fb_detect_panel(const char *name)
 {
-	int ret = -EPERM;
+	if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+			strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
 
-	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
-		if (!strncmp(name, "lcdc_toshiba_fwvga_pt", 21))
-			ret = 0;
-	} else {
-		ret = -ENODEV;
-	}
-
-	return ret;
+#if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
+		if (machine_is_msm7x27a_surf() ||
+			machine_is_msm7625a_surf()) {
+			if (!strncmp(name, LCDC_TOSHIBA_FWVGA_PANEL_NAME,
+				strnlen(LCDC_TOSHIBA_FWVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		}
+#endif
+	return -ENODEV;
 }
 
 static struct msm_fb_platform_data msm_fb_pdata = {
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index 3b6da9a..e85202d 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-msm8960-regulator.c
@@ -383,8 +383,8 @@
 		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
-		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_NONE, \
-		 RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
 
@@ -394,15 +394,15 @@
 		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
-		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_NONE, \
-		 RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
 
 #define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
 	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
-		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_NONE, \
-		 RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
 
@@ -410,8 +410,8 @@
 		_supply_regulator, _freq) \
 	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
-		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_NONE, \
-		 RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
 
@@ -429,7 +429,7 @@
 			.supply_regulator	= _supply_regulator, \
 		}, \
 		.id	  = RPM_VREG_ID_PM8921_##_id##_PC, \
-		.pin_fn	  = RPM_VREG_PIN_FN_##_pin_fn, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8960_##_pin_fn, \
 		.pin_ctrl = _pin_ctrl, \
 	}
 
@@ -520,6 +520,9 @@
 	ARRAY_SIZE(msm_pm8921_regulator_pdata);
 
 struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
-	.init_data = msm_rpm_regulator_init_data,
-	.num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
+	.init_data		= msm_rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(msm_rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8960,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8921_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8921_S3,
 };
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 3ac41ed..2cf0a70 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -830,6 +830,26 @@
 };
 #endif
 
+#define DSP_RAM_BASE_8960 0x8da00000
+#define DSP_RAM_SIZE_8960 0x1800000
+static int dspcrashd_pdata_8960 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8960[] = {
+	{
+		.name   = "msm_dspcrashd",
+		.start  = DSP_RAM_BASE_8960,
+		.end    = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_dspcrashd_8960 = {
+	.name           = "msm_dspcrashd",
+	.num_resources  = ARRAY_SIZE(resources_dspcrashd_8960),
+	.resource       = resources_dspcrashd_8960,
+	.dev = { .platform_data = &dspcrashd_pdata_8960 },
+};
+
 static struct memtype_reserve msm8960_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
 	},
@@ -998,8 +1018,6 @@
 };
 #endif
 
-#ifdef CONFIG_MSM_BUS_SCALING
-
 static struct msm_bus_vectors cam_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_VFE,
@@ -1133,24 +1151,19 @@
 		ARRAY_SIZE(cam_bus_client_config),
 		.name = "msm_camera",
 };
-#endif
 
 struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.ioclk.mclk_clk_rate = 24000000,
 		.ioclk.vfe_clk_rate  = 228570000,
 		.csid_core = 0,
-#ifdef CONFIG_MSM_BUS_SCALING
 		.cam_bus_scale_table = &cam_bus_client_pdata,
-#endif
 	},
 	{
 		.ioclk.mclk_clk_rate = 24000000,
 		.ioclk.vfe_clk_rate  = 228570000,
 		.csid_core = 1,
-#ifdef CONFIG_MSM_BUS_SCALING
 		.cam_bus_scale_table = &cam_bus_client_pdata,
-#endif
 	},
 };
 
@@ -1334,10 +1347,15 @@
 
 #define MDP_VSYNC_GPIO 0
 
-#define TOSHIBA_PANEL_NAME "mipi_video_toshiba_wsvga"
-#define TOSHIBA_PANEL_NAME_LEN 24
-#define CHIMEI_PANEL_NAME "mipi_chimei_wxga"
-#define CHIMEI_PANEL_NAME_LEN 16
+#define PANEL_NAME_MAX_LEN	30
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME	"mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME	"mipi_video_chimei_wxga"
+#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME	"mipi_video_simulator_vga"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
+#define HDMI_PANEL_NAME	"hdmi_msm"
+#define TVOUT_PANEL_NAME	"tvout_msm"
 
 static struct resource msm_fb_resources[] = {
 	{
@@ -1345,35 +1363,66 @@
 	}
 };
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 static int msm_fb_detect_panel(const char *name)
 {
 	if (machine_is_msm8960_liquid()) {
-		if (!strncmp(name, CHIMEI_PANEL_NAME, CHIMEI_PANEL_NAME_LEN))
+		if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
 			return 0;
 	} else {
-		if (!strncmp(name, TOSHIBA_PANEL_NAME, TOSHIBA_PANEL_NAME_LEN))
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
 			return 0;
+
+#ifndef CONFIG_FB_MSM_MIPI_PANEL_DETECT
+		if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+				strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+#endif
 	}
 
-	pr_warning("%s: not supported '%s'", __func__, name);
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
 
+	if (!strncmp(name, TVOUT_PANEL_NAME,
+			strnlen(TVOUT_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	pr_warning("%s: not supported '%s'", __func__, name);
 	return -ENODEV;
 }
 
 static struct msm_fb_platform_data msm_fb_pdata = {
 	.detect_client = msm_fb_detect_panel,
 };
-#endif /* CONFIG_FB_MSM_MIPI_PANEL_DETECT */
 
 static struct platform_device msm_fb_device = {
 	.name   = "msm_fb",
 	.id     = 0,
 	.num_resources     = ARRAY_SIZE(msm_fb_resources),
 	.resource          = msm_fb_resources,
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	.dev.platform_data = &msm_fb_pdata,
-#endif /* CONFIG_FB_MSM_MIPI_PANEL_DETECT */
 };
 
 static bool dsi_power_on;
@@ -2629,8 +2678,18 @@
 
 static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
 	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
-	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_DOWN},
-	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_DOWN}
+	/*
+	 * SDC3 CMD line should be PULLed UP otherwise fluid platform will
+	 * see transitions (1 -> 0 and 0 -> 1) on card detection line,
+	 * which would result in false card detection interrupts.
+	 */
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	/*
+	 * Keeping DATA lines status to PULL UP will make sure that
+	 * there is no current leak during sleep if external pull up
+	 * is connected to DATA lines.
+	 */
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
 };
 
 struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
@@ -3479,6 +3538,7 @@
 	&msm_funnel_device,
 	&msm_ptm_device,
 #endif
+	&msm_device_dspcrashd_8960,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -3597,7 +3657,7 @@
 
 static void __init msm8960_gfx_init(void)
 {
-	uint32_t soc_platform_version = socinfo_get_platform_version();
+	uint32_t soc_platform_version = socinfo_get_version();
 	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
 		struct kgsl_device_platform_data *kgsl_3d0_pdata =
 				msm_kgsl_3d0.dev.platform_data;
@@ -3860,40 +3920,41 @@
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
 
-/**
- * 'flag' stores three values; led id, led mode, and max current of led.
- * The bit packing format is as follow,
- * reserved (1 byte) | max_current (2 bytes) | led_mode (1 nibble) |
- * led_id (1 nibble)
- */
-#define PM8XXX_SET_FLAG(led_id, led_mode, led_max_current)	\
-	(((led_id << PM8XXX_LED_ID_SHIFT) & PM8XXX_LED_ID_MASK) |\
-	((led_mode << PM8XXX_LED_MODE_SHIFT) & PM8XXX_LED_MODE_MASK) |\
-	((led_max_current << PM8XXX_LED_MAX_CURRENT_SHIFT) & \
-			PM8XXX_LED_MAX_CURRENT_MASK))
-
 static struct led_info pm8921_led_info[] = {
 	[0] = {
 		.name			= "led:usb",
 		.default_trigger	= "usb-online",
-		.flags			= PM8XXX_SET_FLAG(PM8XXX_ID_LED_0,
-						PM8XXX_LED_MODE_MANUAL,
-						PM8921_LC_LED_MAX_CURRENT),
 	},
 	[1] = {
 		.name			= "led:ac",
 		.default_trigger	= "ac-online",
-		.flags			= PM8XXX_SET_FLAG(PM8XXX_ID_LED_1,
-						PM8XXX_LED_MODE_MANUAL,
-						PM8921_LC_LED_MAX_CURRENT),
 	},
 };
 
-static struct led_platform_data pm8xxx_leds_pdata = {
+static struct led_platform_data pm8921_led_core_pdata = {
 	.num_leds = ARRAY_SIZE(pm8921_led_info),
 	.leds = pm8921_led_info,
 };
 
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+	[1] = {
+		.id = PM8XXX_ID_LED_1,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+		.led_core = &pm8921_led_core_pdata,
+		.configs = pm8921_led_configs,
+		.num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
 static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
 	.irq_pdata		= &pm8xxx_irq_pdata,
 	.gpio_pdata		= &pm8xxx_gpio_pdata,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 2af1087..6804a99 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -139,6 +139,13 @@
 #define LCDC_AUO_SPI_DEVICE_NAME		"lcdc_auo_nt35582"
 #define LCDC_NT35582_PANEL_NAME			"lcdc_nt35582_wvga"
 
+#define PANEL_NAME_MAX_LEN	30
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME	"mipi_video_toshiba_wvga"
+#define HDMI_PANEL_NAME	"hdmi_msm"
+#define TVOUT_PANEL_NAME	"tvout_msm"
+
 #define DSPS_PIL_GENERIC_NAME		"dsps"
 #define DSPS_PIL_FLUID_NAME		"dsps_fluid"
 
@@ -2663,7 +2670,6 @@
 	}
 };
 
-#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT
 static int msm_fb_detect_panel(const char *name)
 {
 	if (machine_is_msm8x60_fluid()) {
@@ -2671,33 +2677,61 @@
 		if (SOCINFO_VERSION_MAJOR(soc_platform_version) < 3) {
 #ifdef CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT
 			if (!strncmp(name, LCDC_SAMSUNG_OLED_PANEL_NAME,
-					strlen(LCDC_SAMSUNG_OLED_PANEL_NAME)))
+					strnlen(LCDC_SAMSUNG_OLED_PANEL_NAME,
+						PANEL_NAME_MAX_LEN)))
 				return 0;
 #endif
 		} else { /*P3 and up use AUO panel */
 #ifdef CONFIG_FB_MSM_LCDC_AUO_WVGA
 			if (!strncmp(name, LCDC_AUO_PANEL_NAME,
-					strlen(LCDC_AUO_PANEL_NAME)))
+					strnlen(LCDC_AUO_PANEL_NAME,
+						PANEL_NAME_MAX_LEN)))
 				return 0;
 #endif
 		}
-		if (!strncmp(name, LCDC_SAMSUNG_WSVGA_PANEL_NAME,
-				strlen(LCDC_SAMSUNG_WSVGA_PANEL_NAME)))
-			return -ENODEV;
 #ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
 	} else if machine_is_msm8x60_dragon() {
 	    if (!strncmp(name, LCDC_NT35582_PANEL_NAME,
-				sizeof(LCDC_NT35582_PANEL_NAME) - 1))
+				strnlen(LCDC_NT35582_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
 			return 0;
 #endif
 	} else {
 		if (!strncmp(name, LCDC_SAMSUNG_WSVGA_PANEL_NAME,
-				strlen(LCDC_SAMSUNG_WSVGA_PANEL_NAME)))
+				strnlen(LCDC_SAMSUNG_WSVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
 			return 0;
-		if (!strncmp(name, LCDC_SAMSUNG_OLED_PANEL_NAME,
-				strlen(LCDC_SAMSUNG_OLED_PANEL_NAME)))
-			return -ENODEV;
+
+#if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+					  PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+#endif
 	}
+
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	if (!strncmp(name, TVOUT_PANEL_NAME,
+			strnlen(TVOUT_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
 	pr_warning("%s: not supported '%s'", __func__, name);
 	return -ENODEV;
 }
@@ -2705,16 +2739,13 @@
 static struct msm_fb_platform_data msm_fb_pdata = {
 	.detect_client = msm_fb_detect_panel,
 };
-#endif /* CONFIG_FB_MSM_LCDC_AUTO_DETECT */
 
 static struct platform_device msm_fb_device = {
 	.name   = "msm_fb",
 	.id     = 0,
 	.num_resources     = ARRAY_SIZE(msm_fb_resources),
 	.resource          = msm_fb_resources,
-#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT
 	.dev.platform_data = &msm_fb_pdata,
-#endif /* CONFIG_FB_MSM_LCDC_AUTO_DETECT */
 };
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -3810,35 +3841,73 @@
 	REGULATOR_SUPPLY("8901_mvs0",		NULL),
 };
 
+/* Pin control regulators */
+static struct regulator_consumer_supply vreg_consumers_PM8058_L8_PC[] = {
+	REGULATOR_SUPPLY("8058_l8_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L20_PC[] = {
+	REGULATOR_SUPPLY("8058_l20_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L21_PC[] = {
+	REGULATOR_SUPPLY("8058_l21_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S2_PC[] = {
+	REGULATOR_SUPPLY("8058_s2_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L0_PC[] = {
+	REGULATOR_SUPPLY("8901_l0_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S4_PC[] = {
+	REGULATOR_SUPPLY("8901_s4_pc",		NULL),
+};
+
 #define RPM_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
 		      _default_uV, _peak_uA, _avg_uA, _pull_down, _pin_ctrl, \
-		      _freq, _pin_fn, _rpm_mode, _state, _sleep_selectable, \
+		      _freq, _pin_fn, _force_mode, _state, _sleep_selectable, \
 		      _always_on) \
-	[RPM_VREG_ID_##_id] = { \
+	{ \
 		.init_data = { \
 			.constraints = { \
-				.valid_modes_mask = _modes, \
-				.valid_ops_mask = _ops, \
-				.min_uV = _min_uV, \
-				.max_uV = _max_uV, \
-				.input_uV = _min_uV, \
-				.apply_uV = _apply_uV, \
-				.always_on = _always_on, \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
 			}, \
-			.consumer_supplies = vreg_consumers_##_id, \
-			.num_consumer_supplies = \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.num_consumer_supplies	= \
 				ARRAY_SIZE(vreg_consumers_##_id), \
 		}, \
-		.default_uV = _default_uV, \
-		.peak_uA = _peak_uA, \
-		.avg_uA = _avg_uA, \
-		.pull_down_enable = _pull_down, \
+		.id			= RPM_VREG_ID_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+	}
+
+/* Pin control initialization */
+#define RPM_PC(_id, _always_on, _pin_fn, _pin_ctrl) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+		}, \
+		.id	  = RPM_VREG_ID_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8660_##_pin_fn, \
 		.pin_ctrl = _pin_ctrl, \
-		.freq = _freq, \
-		.pin_fn = _pin_fn, \
-		.mode = _rpm_mode, \
-		.state = _state, \
-		.sleep_selectable = _sleep_selectable, \
 	}
 
 /*
@@ -3851,198 +3920,165 @@
  * .init_data.constraints.initial_mode.
  */
 
-#define RPM_VREG_INIT_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
-			  _max_uV, _init_peak_uA, _pin_ctrl) \
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_init_peak_uA) \
 	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
 		      REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
 		      REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
 		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
-		      _init_peak_uA, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
-		      RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
-		      RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
-
-#define RPM_VREG_INIT_LDO_PF(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
-			  _max_uV, _init_peak_uA, _pin_ctrl, _pin_fn) \
-	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
-		      REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
-		      REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
-		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
-		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
-		      _init_peak_uA, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
-		      _pin_fn, RPM_VREG_MODE_NONE, RPM_VREG_STATE_OFF, \
+		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
 		      _sleep_selectable, _always_on)
 
-#define RPM_VREG_INIT_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
-			   _max_uV, _init_peak_uA, _pin_ctrl, _freq) \
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _init_peak_uA, _freq) \
 	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
 		      REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
 		      REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
 		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
-		      _init_peak_uA, _pd, _pin_ctrl, _freq, \
-		      RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
-		      RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, _freq, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
 
-#define RPM_VREG_INIT_VS(_id, _always_on, _pd, _sleep_selectable, _pin_ctrl) \
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable) \
 	RPM_VREG_INIT(_id, 0, 0, REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE, \
 		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE, 0, 0, \
-		      1000, 1000, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
-		      RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
-		      RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+		      1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
 
-#define RPM_VREG_INIT_NCP(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
-			  _max_uV, _pin_ctrl) \
+#define RPM_NCP(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV) \
 	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
 		      REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, \
-		      _min_uV, 1000, 1000, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
-		      RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
-		      RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+		      _min_uV, 1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
 
-#define LDO50HMIN	RPM_VREG_LDO_50_HPM_MIN_LOAD
-#define LDO150HMIN	RPM_VREG_LDO_150_HPM_MIN_LOAD
-#define LDO300HMIN	RPM_VREG_LDO_300_HPM_MIN_LOAD
-#define SMPS_HMIN	RPM_VREG_SMPS_HPM_MIN_LOAD
-#define FTS_HMIN	RPM_VREG_FTSMPS_HPM_MIN_LOAD
+#define LDO50HMIN	RPM_VREG_8660_LDO_50_HPM_MIN_LOAD
+#define LDO150HMIN	RPM_VREG_8660_LDO_150_HPM_MIN_LOAD
+#define LDO300HMIN	RPM_VREG_8660_LDO_300_HPM_MIN_LOAD
+#define SMPS_HMIN	RPM_VREG_8660_SMPS_HPM_MIN_LOAD
+#define FTS_HMIN	RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD
 
-static struct rpm_vreg_pdata rpm_vreg_init_pdata[RPM_VREG_ID_MAX] = {
-	RPM_VREG_INIT_LDO(PM8058_L0,  0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L1,  0, 1, 0, 1200000, 1200000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L2,  0, 1, 0, 1800000, 2600000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L3,  0, 1, 0, 1800000, 1800000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L4,  0, 1, 0, 2850000, 2850000,  LDO50HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L6,  0, 1, 0, 3000000, 3600000,  LDO50HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L7,  0, 1, 0, 1800000, 1800000,  LDO50HMIN, 0),
-	RPM_VREG_INIT_LDO_PF(PM8058_L8,  0, 1, 0, 2900000, 3050000, LDO300HMIN,
-		RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
-	RPM_VREG_INIT_LDO(PM8058_L9,  0, 1, 0, 1800000, 1800000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L10, 0, 1, 0, 2600000, 2600000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L11, 0, 1, 0, 1500000, 1500000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L12, 0, 1, 0, 2900000, 2900000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L13, 0, 1, 0, 2050000, 2050000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L14, 0, 0, 0, 2850000, 2850000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L15, 0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L16, 1, 1, 0, 1800000, 1800000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L17, 0, 1, 0, 2600000, 2600000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L18, 0, 1, 0, 2200000, 2200000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L19, 0, 1, 0, 2500000, 2500000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO_PF(PM8058_L20, 0, 1, 0, 1800000, 1800000, LDO150HMIN,
-		RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
-	RPM_VREG_INIT_LDO_PF(PM8058_L21, 1, 1, 0, 1200000, 1200000, LDO150HMIN,
-		RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
-	RPM_VREG_INIT_LDO(PM8058_L22, 0, 1, 0, 1150000, 1150000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L23, 0, 1, 0, 1200000, 1200000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L24, 0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8058_L25, 0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
-
-	RPM_VREG_INIT_SMPS(PM8058_S0, 0, 1, 1,  500000, 1250000,  SMPS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8058_S1, 0, 1, 1,  500000, 1250000,  SMPS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8058_S2, 0, 1, 1, 1200000, 1400000,  SMPS_HMIN,
-		RPM_VREG_PIN_CTRL_A0, RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8058_S3, 1, 1, 0, 1800000, 1800000,  SMPS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8058_S4, 1, 1, 0, 2200000, 2200000,  SMPS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-
-	RPM_VREG_INIT_VS(PM8058_LVS0, 0, 1, 0,				 0),
-	RPM_VREG_INIT_VS(PM8058_LVS1, 0, 1, 0,				 0),
-
-	RPM_VREG_INIT_NCP(PM8058_NCP, 0, 1, 0, 1800000, 1800000,	 0),
-
-	RPM_VREG_INIT_LDO(PM8901_L0,  0, 1, 0, 1200000, 1200000, LDO300HMIN,
-		RPM_VREG_PIN_CTRL_A0),
-	RPM_VREG_INIT_LDO(PM8901_L1,  0, 1, 0, 3300000, 3300000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8901_L2,  0, 1, 0, 2850000, 3300000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8901_L3,  0, 1, 0, 3300000, 3300000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8901_L4,  0, 1, 0, 2600000, 2600000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8901_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
-	RPM_VREG_INIT_LDO(PM8901_L6,  0, 1, 0, 2200000, 2200000, LDO300HMIN, 0),
-
-	RPM_VREG_INIT_SMPS(PM8901_S2, 0, 1, 0, 1300000, 1300000,   FTS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8901_S3, 0, 1, 0, 1100000, 1100000,   FTS_HMIN, 0,
-		RPM_VREG_FREQ_1p60),
-	RPM_VREG_INIT_SMPS(PM8901_S4, 0, 1, 0, 1225000, 1225000,   FTS_HMIN,
-		RPM_VREG_PIN_CTRL_A0, RPM_VREG_FREQ_1p60),
-
-	RPM_VREG_INIT_VS(PM8901_LVS0, 1, 1, 0,				 0),
-	RPM_VREG_INIT_VS(PM8901_LVS1, 0, 1, 0,				 0),
-	RPM_VREG_INIT_VS(PM8901_LVS2, 0, 1, 0,				 0),
-	RPM_VREG_INIT_VS(PM8901_LVS3, 0, 1, 0,				 0),
-	RPM_VREG_INIT_VS(PM8901_MVS0, 0, 1, 0,				 0),
+/* RPM early regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_early_init_data[] = {
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip    freq */
+	RPM_SMPS(PM8058_S0, 0, 1, 1,  500000, 1250000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S1, 0, 1, 1,  500000, 1250000, SMPS_HMIN, 1p60),
 };
 
-#define RPM_VREG(_id) \
-	[_id] = { \
-		.name = "rpm-regulator", \
-		.id = _id, \
-		.dev = { \
-			.platform_data = &rpm_vreg_init_pdata[_id], \
-		}, \
-	}
+/* RPM regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_init_data[] = {
+	/*	ID        a_on pd ss min_uV   max_uV   init_ip */
+	RPM_LDO(PM8058_L0,  0, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L1,  0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8058_L2,  0, 1, 0, 1800000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8058_L3,  0, 1, 0, 1800000, 1800000, LDO150HMIN),
+	RPM_LDO(PM8058_L4,  0, 1, 0, 2850000, 2850000,  LDO50HMIN),
+	RPM_LDO(PM8058_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L6,  0, 1, 0, 3000000, 3600000,  LDO50HMIN),
+	RPM_LDO(PM8058_L7,  0, 1, 0, 1800000, 1800000,  LDO50HMIN),
+	RPM_LDO(PM8058_L8,  0, 1, 0, 2900000, 3050000, LDO300HMIN),
+	RPM_LDO(PM8058_L9,  0, 1, 0, 1800000, 1800000, LDO300HMIN),
+	RPM_LDO(PM8058_L10, 0, 1, 0, 2600000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8058_L11, 0, 1, 0, 1500000, 1500000, LDO150HMIN),
+	RPM_LDO(PM8058_L12, 0, 1, 0, 2900000, 2900000, LDO150HMIN),
+	RPM_LDO(PM8058_L13, 0, 1, 0, 2050000, 2050000, LDO300HMIN),
+	RPM_LDO(PM8058_L14, 0, 0, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L15, 0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L16, 1, 1, 0, 1800000, 1800000, LDO300HMIN),
+	RPM_LDO(PM8058_L17, 0, 1, 0, 2600000, 2600000, LDO150HMIN),
+	RPM_LDO(PM8058_L18, 0, 1, 0, 2200000, 2200000, LDO150HMIN),
+	RPM_LDO(PM8058_L19, 0, 1, 0, 2500000, 2500000, LDO150HMIN),
+	RPM_LDO(PM8058_L20, 0, 1, 0, 1800000, 1800000, LDO150HMIN),
+	RPM_LDO(PM8058_L21, 1, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L22, 0, 1, 0, 1150000, 1150000, LDO300HMIN),
+	RPM_LDO(PM8058_L23, 0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8058_L24, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L25, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
 
-static struct platform_device rpm_vreg_device[RPM_VREG_ID_MAX] = {
-	RPM_VREG(RPM_VREG_ID_PM8058_L0),
-	RPM_VREG(RPM_VREG_ID_PM8058_L1),
-	RPM_VREG(RPM_VREG_ID_PM8058_L2),
-	RPM_VREG(RPM_VREG_ID_PM8058_L3),
-	RPM_VREG(RPM_VREG_ID_PM8058_L4),
-	RPM_VREG(RPM_VREG_ID_PM8058_L5),
-	RPM_VREG(RPM_VREG_ID_PM8058_L6),
-	RPM_VREG(RPM_VREG_ID_PM8058_L7),
-	RPM_VREG(RPM_VREG_ID_PM8058_L8),
-	RPM_VREG(RPM_VREG_ID_PM8058_L9),
-	RPM_VREG(RPM_VREG_ID_PM8058_L10),
-	RPM_VREG(RPM_VREG_ID_PM8058_L11),
-	RPM_VREG(RPM_VREG_ID_PM8058_L12),
-	RPM_VREG(RPM_VREG_ID_PM8058_L13),
-	RPM_VREG(RPM_VREG_ID_PM8058_L14),
-	RPM_VREG(RPM_VREG_ID_PM8058_L15),
-	RPM_VREG(RPM_VREG_ID_PM8058_L16),
-	RPM_VREG(RPM_VREG_ID_PM8058_L17),
-	RPM_VREG(RPM_VREG_ID_PM8058_L18),
-	RPM_VREG(RPM_VREG_ID_PM8058_L19),
-	RPM_VREG(RPM_VREG_ID_PM8058_L20),
-	RPM_VREG(RPM_VREG_ID_PM8058_L21),
-	RPM_VREG(RPM_VREG_ID_PM8058_L22),
-	RPM_VREG(RPM_VREG_ID_PM8058_L23),
-	RPM_VREG(RPM_VREG_ID_PM8058_L24),
-	RPM_VREG(RPM_VREG_ID_PM8058_L25),
-	RPM_VREG(RPM_VREG_ID_PM8058_S0),
-	RPM_VREG(RPM_VREG_ID_PM8058_S1),
-	RPM_VREG(RPM_VREG_ID_PM8058_S2),
-	RPM_VREG(RPM_VREG_ID_PM8058_S3),
-	RPM_VREG(RPM_VREG_ID_PM8058_S4),
-	RPM_VREG(RPM_VREG_ID_PM8058_LVS0),
-	RPM_VREG(RPM_VREG_ID_PM8058_LVS1),
-	RPM_VREG(RPM_VREG_ID_PM8058_NCP),
-	RPM_VREG(RPM_VREG_ID_PM8901_L0),
-	RPM_VREG(RPM_VREG_ID_PM8901_L1),
-	RPM_VREG(RPM_VREG_ID_PM8901_L2),
-	RPM_VREG(RPM_VREG_ID_PM8901_L3),
-	RPM_VREG(RPM_VREG_ID_PM8901_L4),
-	RPM_VREG(RPM_VREG_ID_PM8901_L5),
-	RPM_VREG(RPM_VREG_ID_PM8901_L6),
-	RPM_VREG(RPM_VREG_ID_PM8901_S2),
-	RPM_VREG(RPM_VREG_ID_PM8901_S3),
-	RPM_VREG(RPM_VREG_ID_PM8901_S4),
-	RPM_VREG(RPM_VREG_ID_PM8901_LVS0),
-	RPM_VREG(RPM_VREG_ID_PM8901_LVS1),
-	RPM_VREG(RPM_VREG_ID_PM8901_LVS2),
-	RPM_VREG(RPM_VREG_ID_PM8901_LVS3),
-	RPM_VREG(RPM_VREG_ID_PM8901_MVS0),
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip    freq */
+	RPM_SMPS(PM8058_S2, 0, 1, 1, 1200000, 1400000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S3, 1, 1, 0, 1800000, 1800000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S4, 1, 1, 0, 2200000, 2200000, SMPS_HMIN, 1p60),
+
+	/*     ID         a_on pd ss */
+	RPM_VS(PM8058_LVS0, 0, 1, 0),
+	RPM_VS(PM8058_LVS1, 0, 1, 0),
+
+	/*	ID        a_on pd ss min_uV   max_uV */
+	RPM_NCP(PM8058_NCP, 0, 1, 0, 1800000, 1800000),
+
+	/*	ID        a_on pd ss min_uV   max_uV   init_ip */
+	RPM_LDO(PM8901_L0,  0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8901_L1,  0, 1, 0, 3300000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L2,  0, 1, 0, 2850000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L3,  0, 1, 0, 3300000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L4,  0, 1, 0, 2600000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8901_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8901_L6,  0, 1, 0, 2200000, 2200000, LDO300HMIN),
+
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip   freq */
+	RPM_SMPS(PM8901_S2, 0, 1, 0, 1300000, 1300000, FTS_HMIN, 1p60),
+	RPM_SMPS(PM8901_S3, 0, 1, 0, 1100000, 1100000, FTS_HMIN, 1p60),
+	RPM_SMPS(PM8901_S4, 0, 1, 0, 1225000, 1225000, FTS_HMIN, 1p60),
+
+	/*	ID        a_on pd ss */
+	RPM_VS(PM8901_LVS0, 1, 1, 0),
+	RPM_VS(PM8901_LVS1, 0, 1, 0),
+	RPM_VS(PM8901_LVS2, 0, 1, 0),
+	RPM_VS(PM8901_LVS3, 0, 1, 0),
+	RPM_VS(PM8901_MVS0, 0, 1, 0),
+
+	/*     ID         a_on pin_func pin_ctrl */
+	RPM_PC(PM8058_L8,   0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_L20,  0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_L21,  1, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_S2,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8058_A0),
+	RPM_PC(PM8901_L0,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8901_A0),
+	RPM_PC(PM8901_S4,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8901_A0),
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_early_pdata = {
+	.init_data		= rpm_regulator_early_init_data,
+	.num_regulators		= ARRAY_SIZE(rpm_regulator_early_init_data),
+	.version		= RPM_VREG_VERSION_8660,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8058_S0,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8058_S1,
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_pdata = {
+	.init_data		= rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8660,
+};
+
+static struct platform_device rpm_regulator_early_device = {
+	.name	= "rpm-regulator",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &rpm_regulator_early_pdata,
+	},
+};
+
+static struct platform_device rpm_regulator_device = {
+	.name	= "rpm-regulator",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &rpm_regulator_pdata,
+	},
 };
 
 static struct platform_device *early_regulators[] __initdata = {
 	&msm_device_saw_s0,
 	&msm_device_saw_s1,
-#ifdef CONFIG_PMIC8058
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_S0],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_S1],
-#endif
+	&rpm_regulator_early_device,
 };
 
 static struct platform_device *early_devices[] __initdata = {
@@ -4893,10 +4929,6 @@
 #ifdef CONFIG_MSM_SDIO_AL
 	&msm_device_sdio_al,
 #endif
-#ifdef CONFIG_MSM_SDIO_AL
-	&msm_device_sdio_al,
-#endif
-
 };
 
 #ifdef CONFIG_SND_SOC_MSM8660_APQ
@@ -5034,57 +5066,7 @@
 #ifdef CONFIG_SENSORS_MSM_ADC
 	&msm_adc_device,
 #endif
-#ifdef CONFIG_PMIC8058
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L0],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L1],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L2],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L3],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L4],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L5],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L6],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L7],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L8],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L9],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L10],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L11],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L12],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L13],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L14],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L15],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L16],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L17],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L18],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L19],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L20],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L21],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L22],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L23],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L24],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_L25],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_S2],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_S3],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_S4],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_LVS0],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_LVS1],
-	&rpm_vreg_device[RPM_VREG_ID_PM8058_NCP],
-#endif
-#ifdef CONFIG_PMIC8901
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L0],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L1],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L2],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L3],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L4],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L5],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_L6],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_S2],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_S3],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_S4],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_LVS0],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_LVS1],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_LVS2],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_LVS3],
-	&rpm_vreg_device[RPM_VREG_ID_PM8901_MVS0],
-#endif
+	&rpm_regulator_device,
 
 #if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
 		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -10091,10 +10073,15 @@
 	 * un-reworked SURF cannot resume from.
 	 */
 	if (machine_is_msm8x60_surf()) {
-		rpm_vreg_init_pdata[RPM_VREG_ID_PM8901_L4]
-			.init_data.constraints.always_on = 1;
-		rpm_vreg_init_pdata[RPM_VREG_ID_PM8901_L6]
-			.init_data.constraints.always_on = 1;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(rpm_regulator_init_data); i++)
+			if (rpm_regulator_init_data[i].id
+				== RPM_VREG_ID_PM8901_L4
+			    || rpm_regulator_init_data[i].id
+				== RPM_VREG_ID_PM8901_L6)
+				rpm_regulator_init_data[i]
+					.init_data.constraints.always_on = 1;
 	}
 
 	/*
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 5d7736f..50be14b 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2750,7 +2750,7 @@
 	{ CLK_LOOKUP("ebi1_lcdc_clk",	ebi_lcdc_clk.c,	NULL) },
 	{ CLK_LOOKUP("ebi1_mddi_clk",	ebi_mddi_clk.c,	NULL) },
 	{ CLK_LOOKUP("ebi1_tv_clk",	ebi_tv_clk.c,	NULL) },
-	{ CLK_LOOKUP("ebi1_vcd_clk",	ebi_vcd_clk.c,	NULL) },
+	{ CLK_LOOKUP("mem_clk",		ebi_vcd_clk.c,	"msm_vidc.0") },
 	{ CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL) },
 	{ CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov") },
 
@@ -2850,10 +2850,10 @@
 	OWN(APPS3, 11, "csi_pclk",	csi0_p_clk,	NULL),
 	OWN(APPS3,  0, "mdp_clk",	mdp_clk,	NULL),
 	OWN(APPS3,  0, "core_clk",	mdp_clk,	"footswitch-pcom.4"),
-	OWN(APPS3,  2, "mfc_clk",	mfc_clk,	NULL),
+	OWN(APPS3,  2, "core_clk",	mfc_clk,	"msm_vidc.0"),
 	OWN(APPS3,  2, "core_clk",	mfc_clk,	"footswitch-pcom.5"),
-	OWN(APPS3,  2, "mfc_div2_clk",	mfc_div2_clk,	NULL),
-	OWN(APPS3,  2, "mfc_pclk",	mfc_p_clk,	NULL),
+	OWN(APPS3,  2, "core_div2_clk",	mfc_div2_clk,	"msm_vidc.0"),
+	OWN(APPS3,  2, "iface_clk",	mfc_p_clk,	"msm_vidc.0"),
 	OWN(APPS3,  2, "iface_clk",	mfc_p_clk,	"footswitch-pcom.5"),
 	OWN(APPS3,  4, "vpe_clk",	vpe_clk,	NULL),
 	OWN(APPS3,  4, "core_clk",	vpe_clk,	"footswitch-pcom.9"),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index af313c0..ea2d9d2 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -252,6 +252,12 @@
 #define MM_PLL1_TEST_CTL_REG			REG_MM(0x0330)
 #define MM_PLL1_STATUS_REG			REG_MM(0x0334)
 #define MM_PLL3_MODE_REG			REG_MM(0x0338)
+#define MM_PLL3_L_VAL_REG			REG_MM(0x033C)
+#define MM_PLL3_M_VAL_REG			REG_MM(0x0340)
+#define MM_PLL3_N_VAL_REG			REG_MM(0x0344)
+#define MM_PLL3_CONFIG_REG			REG_MM(0x0348)
+#define MM_PLL3_TEST_CTL_REG			REG_MM(0x034C)
+#define MM_PLL3_STATUS_REG			REG_MM(0x0350)
 #define ROT_CC_REG				REG_MM(0x00E0)
 #define ROT_NS_REG				REG_MM(0x00E8)
 #define SAXI_EN_REG				REG_MM(0x0030)
@@ -786,6 +792,23 @@
 	},
 };
 
+/* For 8064, gfx3d_axi_clk is set as a dependency of gmem_axi_clk at runtime */
+static struct branch_clk gfx3d_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN5_REG,
+		.en_mask = BIT(25),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 30,
+	},
+	.c = {
+		.dbg_name = "gfx3d_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_axi_clk.c),
+	},
+};
+
 /* AHB Interfaces */
 static struct branch_clk amp_p_clk = {
 	.b = {
@@ -3390,6 +3413,7 @@
 	F_END
 };
 
+/* TODO: need to add 325MHz back once it is fixed in the simulation model */
 static struct clk_freq_tbl clk_tbl_gfx3d_8064[] = {
 	F_GFX3D(        0, gnd,   0,  0, NONE),
 	F_GFX3D( 27000000, pxo,   0,  0, LOW),
@@ -3405,7 +3429,6 @@
 	F_GFX3D(200000000, pll2,  1,  4, NOMINAL),
 	F_GFX3D(228571000, pll2,  2,  7, NOMINAL),
 	F_GFX3D(266667000, pll2,  1,  3, NOMINAL),
-	F_GFX3D(325000000, pll15, 1,  3, NOMINAL),
 	F_GFX3D(400000000, pll2,  1,  2, HIGH),
 	F_END
 };
@@ -3451,6 +3474,83 @@
 	},
 };
 
+#define F_VCAP(f, s, m, n, v) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(18, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+		.mnd_en_mask = (BIT(8) | BIT(5)) * !!(n), \
+		.sys_vdd = v, \
+	}
+
+static struct clk_freq_tbl clk_tbl_vcap[] = {
+	F_VCAP(        0, gnd,  0,  0, NONE),
+	F_VCAP( 27000000, pxo,  0,  0, LOW),
+	F_VCAP( 54860000, pll8, 1,  7, LOW),
+	F_VCAP( 64000000, pll8, 1,  6, LOW),
+	F_VCAP( 76800000, pll8, 1,  5, LOW),
+	F_VCAP(128000000, pll8, 1,  3, NOMINAL),
+	F_VCAP(160000000, pll2, 1,  5, NOMINAL),
+	F_VCAP(200000000, pll2, 1,  4, NOMINAL),
+	F_END
+};
+
+static struct bank_masks bmnd_info_vcap = {
+	.bank_sel_mask =                BIT(11),
+	.bank0_mask = {
+		.md_reg =               VCAP_MD0_REG,
+		.ns_mask =              BM(21, 18) | BM(5, 3),
+		.rst_mask =             BIT(23),
+		.mnd_en_mask =          BIT(8),
+		.mode_mask =            BM(10, 9),
+	},
+	.bank1_mask = {
+		.md_reg =               VCAP_MD1_REG,
+		.ns_mask =              BM(17, 14) | BM(2, 0),
+		.rst_mask =             BIT(22),
+		.mnd_en_mask =          BIT(5),
+		.mode_mask =            BM(7, 6),
+	},
+};
+
+static struct rcg_clk vcap_clk = {
+	.b = {
+		.ctl_reg = VCAP_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 15,
+	},
+	.ns_reg = VCAP_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_vcap,
+	.bank_info = &bmnd_info_vcap,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vcap_clk",
+		.ops = &clk_ops_rcg_8960,
+		.depends = &vcap_axi_clk.c,
+		CLK_INIT(vcap_clk.c),
+	},
+};
+
+static struct branch_clk vcap_npl_clk = {
+	.b = {
+		.ctl_reg = VCAP_CC_REG,
+		.en_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 25,
+	},
+	.parent = &vcap_clk.c,
+	.c = {
+		.dbg_name = "vcap_npl_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcap_npl_clk.c),
+	},
+};
+
 #define F_IJPEG(f, s, d, m, n, v) \
 	{ \
 		.freq_hz = f, \
@@ -3487,7 +3587,7 @@
 	F_IJPEG(128000000, pll8, 3, 0,  0, LOW),
 	F_IJPEG(153600000, pll8, 1, 2,  5, NOMINAL),
 	F_IJPEG(200000000, pll2, 4, 0,  0, NOMINAL),
-	F_IJPEG(228000000, pll2, 1, 2,  7, NOMINAL),
+	F_IJPEG(228571000, pll2, 1, 2,  7, NOMINAL),
 	F_IJPEG(320000000, pll2, 1, 2,  5, HIGH),
 	F_END
 };
@@ -3567,7 +3667,7 @@
 		.mnd_en_mask = (BIT(8) | BIT(5)) * !!(n), \
 		.sys_vdd = v, \
 	}
-static struct clk_freq_tbl clk_tbl_mdp[] = {
+static struct clk_freq_tbl clk_tbl_mdp_8960[] = {
 	F_MDP(        0, gnd,  0,  0, NONE),
 	F_MDP(  9600000, pll8, 1, 40, LOW),
 	F_MDP( 13710000, pll8, 1, 28, LOW),
@@ -3586,6 +3686,25 @@
 	F_END
 };
 
+static struct clk_freq_tbl clk_tbl_mdp_8064[] = {
+	F_MDP(        0, gnd,  0,  0, NONE),
+	F_MDP(  9600000, pll8, 1, 40, LOW),
+	F_MDP( 13710000, pll8, 1, 28, LOW),
+	F_MDP( 29540000, pll8, 1, 13, LOW),
+	F_MDP( 34910000, pll8, 1, 11, LOW),
+	F_MDP( 38400000, pll8, 1, 10, LOW),
+	F_MDP( 59080000, pll8, 2, 13, LOW),
+	F_MDP( 76800000, pll8, 1,  5, LOW),
+	F_MDP( 85330000, pll8, 2,  9, LOW),
+	F_MDP( 96000000, pll8, 1,  4, LOW),
+	F_MDP(128000000, pll8, 1,  3, LOW),
+	F_MDP(160000000, pll2, 1,  5, NOMINAL),
+	F_MDP(177780000, pll2, 2,  9, NOMINAL),
+	F_MDP(200000000, pll2, 1,  4, NOMINAL),
+	F_MDP(266000000, pll2, 1,  3, NOMINAL),
+	F_END
+};
+
 static struct bank_masks bmnd_info_mdp = {
 	.bank_sel_mask =		BIT(11),
 	.bank0_mask = {
@@ -3616,7 +3735,7 @@
 	.ns_reg = MDP_NS_REG,
 	.root_en_mask = BIT(2),
 	.set_rate = set_rate_mnd_banked,
-	.freq_tbl = clk_tbl_mdp,
+	.freq_tbl = clk_tbl_mdp_8960,
 	.bank_info = &bmnd_info_mdp,
 	.current_freq = &rcg_dummy_freq,
 	.c = {
@@ -4621,7 +4740,10 @@
 	{ TEST_MM_HS(0x30), &csi_pix1_clk.c },
 	{ TEST_MM_HS(0x31), &csi_rdi1_clk.c },
 	{ TEST_MM_HS(0x32), &csi_rdi2_clk.c },
+	{ TEST_MM_HS(0x33), &vcap_clk.c },
+	{ TEST_MM_HS(0x34), &vcap_npl_clk.c },
 	{ TEST_MM_HS(0x36), &vcap_axi_clk.c },
+	{ TEST_MM_HS(0x39), &gfx3d_axi_clk.c },
 
 	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
 	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
@@ -4815,7 +4937,7 @@
 
 static struct clk_lookup msm_clocks_8064[] __initdata = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,		NULL),
-	CLK_DUMMY("pll2",		PLL2,		NULL, 0),
+	CLK_LOOKUP("pll2",		pll2_clk.c,		NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,		NULL),
 	CLK_DUMMY("pll4",		PLL4,		NULL, 0),
 	CLK_LOOKUP("measure",		measure_clk.c,		"debug"),
@@ -4898,66 +5020,84 @@
 	CLK_LOOKUP("pmic_ssbi2",	pmic_ssbi2_clk.c,	NULL),
 	CLK_LOOKUP("rpm_msg_ram_pclk",	rpm_msg_ram_p_clk.c,	NULL),
 	CLK_LOOKUP("amp_clk",		amp_clk.c,		NULL),
-	CLK_DUMMY("cam_clk",		CAM0_CLK,		NULL, OFF),
-	CLK_DUMMY("cam_clk",		CAM1_CLK,		NULL, OFF),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,		NULL),
 	CLK_DUMMY("csi_src_clk",	CSI0_SRC_CLK,		NULL, OFF),
-	CLK_DUMMY("csi_src_clk",	CSI1_SRC_CLK,		NULL, OFF),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
 	CLK_DUMMY("csi_clk",		CSI0_CLK,		NULL, OFF),
-	CLK_DUMMY("csi_clk",		CSI1_CLK,		NULL, OFF),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
+	CLK_DUMMY("csi_phy_clk",	CSI0_PHY_CLK,		NULL, OFF),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
 	CLK_DUMMY("csi_pix_clk",	CSI_PIX_CLK,		NULL, OFF),
 	CLK_DUMMY("csi_rdi_clk",	CSI_RDI_CLK,		NULL, OFF),
-	CLK_DUMMY("csiphy_timer_src_clk", CSIPHY_TIMER_SRC_CLK,	NULL, OFF),
-	CLK_DUMMY("csi0phy_timer_clk",	CSIPHY0_TIMER_CLK,	NULL, OFF),
-	CLK_DUMMY("csi1phy_timer_clk",	CSIPHY1_TIMER_CLK,	NULL, OFF),
-	CLK_DUMMY("dsi_byte_div_clk",	DSI1_BYTE_CLK,	"mipi_dsi.1", OFF),
-	CLK_DUMMY("dsi_byte_div_clk",	DSI2_BYTE_CLK,	"mipi_dsi.2", OFF),
-	CLK_DUMMY("dsi_esc_clk",	DSI1_ESC_CLK,	"mipi_dsi.1", OFF),
-	CLK_DUMMY("dsi_esc_clk",	DSI2_ESC_CLK,	"mipi_dsi.2", OFF),
-	CLK_DUMMY("gfx3d_clk",		GFX3D_CLK,		NULL, OFF),
-	CLK_DUMMY("ijpeg_clk",		IJPEG_CLK,		NULL, OFF),
-	CLK_DUMMY("imem_axi_clk",	IMEM_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("jpegd_clk",		JPEGD_CLK,		NULL, OFF),
-	CLK_DUMMY("mdp_clk",		MDP_CLK,		NULL, OFF),
-	CLK_DUMMY("mdp_vsync_clk",	MDP_VSYNC_CLK,		NULL, OFF),
-	CLK_DUMMY("lut_mdp",		LUT_MDP_CLK,		NULL, OFF),
-	CLK_DUMMY("rot_clk",		ROT_CLK,		NULL, OFF),
+	CLK_DUMMY("csi_pix_clk",	CSI_PIX1_CLK,		NULL, OFF),
+	CLK_DUMMY("csi_rdi_clk",	CSI_RDI1_CLK,		NULL, OFF),
+	CLK_DUMMY("csi_rdi_clk",	CSI_RDI2_CLK,		NULL, OFF),
+	CLK_LOOKUP("csiphy_timer_src_clk", csiphy_timer_src_clk.c, NULL),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_clk",	csi2phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("dsi_byte_div_clk",	dsi1_byte_clk.c,	NULL),
+	CLK_LOOKUP("dsi_byte_div_clk",	dsi2_byte_clk.c,	NULL),
+	CLK_LOOKUP("dsi_esc_clk",	dsi1_esc_clk.c,		NULL),
+	CLK_LOOKUP("dsi_esc_clk",	dsi2_esc_clk.c,		NULL),
+	CLK_DUMMY("rgb_tv_clk",		RGB_TV_CLK,		NULL, OFF),
+	CLK_DUMMY("npl_tv_clk",		NPL_TV_CLK,		NULL, OFF),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,           NULL),
+	CLK_LOOKUP("bus_clk",		vcap_axi_clk.c,         NULL),
+	CLK_LOOKUP("core_clk",          vcap_clk.c,             NULL),
+	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         NULL),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,            NULL),
+	CLK_LOOKUP("jpegd_clk",		jpegd_clk.c,		NULL),
+	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
+	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("rot_clk",		rot_clk.c,		NULL),
 	CLK_DUMMY("tv_src_clk",		TV_SRC_CLK,		NULL, OFF),
-	CLK_DUMMY("tv_enc_clk",		TV_ENC_CLK,		NULL, OFF),
-	CLK_DUMMY("tv_dac_clk",		TV_DAC_CLK,		NULL, OFF),
-	CLK_DUMMY("vcodec_clk",		VCODEC_CLK,		NULL, OFF),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,		NULL),
 	CLK_DUMMY("mdp_tv_clk",		MDP_TV_CLK,		NULL, OFF),
 	CLK_DUMMY("hdmi_clk",		HDMI_TV_CLK,		NULL, OFF),
-	CLK_DUMMY("core_clk",		HDMI_APP_CLK,		NULL, OFF),
-	CLK_DUMMY("vpe_clk",		VPE_CLK,		NULL, OFF),
-	CLK_DUMMY("vfe_clk",		VFE_CLK,		NULL, OFF),
-	CLK_DUMMY("csi_vfe_clk",	CSI0_VFE_CLK,		NULL, OFF),
-	CLK_DUMMY("vfe_axi_clk",	VFE_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("ijpeg_axi_clk",	IJPEG_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("mdp_axi_clk",	MDP_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("rot_axi_clk",	ROT_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("vcodec_axi_clk",	VCODEC_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("vcodec_axi_a_clk",	VCODEC_AXI_A_CLK,	NULL, OFF),
-	CLK_DUMMY("vcodec_axi_b_clk",	VCODEC_AXI_B_CLK,	NULL, OFF),
-	CLK_DUMMY("vpe_axi_clk",	VPE_AXI_CLK,		NULL, OFF),
-	CLK_DUMMY("amp_pclk",		AMP_P_CLK,		NULL, OFF),
-	CLK_DUMMY("csi_pclk",		CSI0_P_CLK,		NULL, OFF),
-	CLK_DUMMY("dsi_m_pclk",		DSI1_M_P_CLK,	"mipi_dsi.1", OFF),
-	CLK_DUMMY("dsi_s_pclk",		DSI1_S_P_CLK,	"mipi_dsi.1", OFF),
-	CLK_DUMMY("dsi_m_pclk",		DSI2_M_P_CLK,	"mipi_dsi.2", OFF),
-	CLK_DUMMY("dsi_s_pclk",		DSI2_S_P_CLK,	"mipi_dsi.2", OFF),
-	CLK_DUMMY("gfx3d_pclk",		GFX3D_P_CLK,		NULL, OFF),
-	CLK_DUMMY("master_iface_clk",	HDMI_M_P_CLK,		NULL, OFF),
-	CLK_DUMMY("slave_iface_clk",	HDMI_S_P_CLK,		NULL, OFF),
-	CLK_DUMMY("ijpeg_pclk",		IJPEG_P_CLK,		NULL, OFF),
-	CLK_DUMMY("jpegd_pclk",		JPEGD_P_CLK,		NULL, OFF),
-	CLK_DUMMY("imem_pclk",		IMEM_P_CLK,		NULL, OFF),
-	CLK_DUMMY("mdp_pclk",		MDP_P_CLK,		NULL, OFF),
-	CLK_DUMMY("smmu_pclk",		SMMU_P_CLK,		NULL, OFF),
-	CLK_DUMMY("rotator_pclk",	ROT_P_CLK,		NULL, OFF),
-	CLK_DUMMY("tv_enc_pclk",	TV_ENC_P_CLK,		NULL, OFF),
-	CLK_DUMMY("vcodec_pclk",	VCODEC_P_CLK,		NULL, OFF),
-	CLK_DUMMY("vfe_pclk",		VFE_P_CLK,		NULL, OFF),
-	CLK_DUMMY("vpe_pclk",		VPE_P_CLK,		NULL, OFF),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		NULL),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		NULL),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		NULL),
+	CLK_LOOKUP("vfe_axi_clk",	vfe_axi_clk.c,		NULL),
+	CLK_LOOKUP("mdp_axi_clk",	mdp_axi_clk.c,		NULL),
+	CLK_LOOKUP("rot_axi_clk",	rot_axi_clk.c,		NULL),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c,	NULL),
+	CLK_LOOKUP("bus_a_clk",		vcodec_axi_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_b_clk",		vcodec_axi_b_clk.c,	NULL),
+	CLK_LOOKUP("vpe_axi_clk",	vpe_axi_clk.c,		NULL),
+	CLK_LOOKUP("amp_pclk",		amp_p_clk.c,		NULL),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		NULL),
+	CLK_LOOKUP("dsi_m_pclk",	dsi1_m_p_clk.c,		NULL),
+	CLK_LOOKUP("dsi_s_pclk",	dsi1_s_p_clk.c,		NULL),
+	CLK_LOOKUP("dsi_m_pclk",	dsi2_m_p_clk.c,		NULL),
+	CLK_LOOKUP("dsi_s_pclk",	dsi2_s_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,		NULL),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		NULL),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		NULL),
+	CLK_LOOKUP("jpegd_pclk",	jpegd_p_clk.c,		NULL),
+	CLK_LOOKUP("imem_pclk",		imem_p_clk.c,		NULL),
+	CLK_LOOKUP("mdp_pclk",		mdp_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		NULL),
+	CLK_LOOKUP("rotator_pclk",	rot_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,		NULL),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		NULL),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		NULL),
 	CLK_DUMMY("mi2s_osr_clk",	MI2S_OSR_CLK,		NULL, OFF),
 	CLK_DUMMY("mi2s_bit_clk",	MI2S_BIT_CLK,		NULL, OFF),
 	CLK_DUMMY("i2s_mic_osr_clk",	CODEC_I2S_MIC_OSR_CLK,	NULL, OFF),
@@ -4970,10 +5110,16 @@
 	CLK_DUMMY("i2s_spkr_bit_clk",	SPARE_I2S_SPKR_BIT_CLK,	NULL, OFF),
 	CLK_DUMMY("pcm_clk",		PCM_CLK,		NULL, OFF),
 	CLK_DUMMY("audio_slimbus_clk",	AUDIO_SLIMBUS_CLK,	NULL, OFF),
-	CLK_DUMMY("iommu_clk",		JPEGD_AXI_CLK,		NULL, 0),
-	CLK_DUMMY("iommu_clk",		VFE_AXI_CLK,		NULL, 0),
-	CLK_DUMMY("iommu_clk",		VCODEC_AXI_CLK,	NULL, 0),
-	CLK_DUMMY("iommu_clk",		GFX3D_CLK,	NULL, 0),
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcap_axi_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	NULL),
+	CLK_DUMMY("core_clk",		GFX3D_AXI_CLK,		NULL, 0),
 	CLK_DUMMY("dfab_dsps_clk",	DFAB_DSPS_CLK,		NULL, 0),
 	CLK_DUMMY("dfab_usb_hs_clk",	DFAB_USB_HS_CLK,	NULL, 0),
 	CLK_DUMMY("bus_clk",		DFAB_SDC1_CLK,		NULL, 0),
@@ -5014,6 +5160,7 @@
 	CLK_LOOKUP("mmfab_a_clk",	mmfab_a_clk.c,	NULL),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,	NULL),
 	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	"clock-8960"),
 	CLK_LOOKUP("sfab_clk",		sfab_clk.c,	NULL),
 	CLK_LOOKUP("sfab_a_clk",	sfab_a_clk.c,	NULL),
 	CLK_LOOKUP("sfpb_clk",		sfpb_clk.c,	NULL),
@@ -5150,7 +5297,7 @@
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
 	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
-	CLK_LOOKUP("vcodec_clk",	vcodec_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
@@ -5191,7 +5338,7 @@
 	CLK_LOOKUP("rotator_pclk",	rot_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_pclk",	tv_enc_p_clk.c,		NULL),
-	CLK_LOOKUP("vcodec_pclk",	vcodec_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
@@ -5344,6 +5491,8 @@
 	rmwreg(0x80FF0000, VFE_CC_REG,        0xE0FF4010);
 	rmwreg(0x800000FF, VFE_CC2_REG,       0xE00000FF);
 	rmwreg(0x80FF0000, VPE_CC_REG,        0xE0FF0010);
+	if (cpu_is_apq8064())
+		rmwreg(0x80FF0000, VCAP_CC_REG,       0xE0FF1010);
 
 	/*
 	 * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
@@ -5475,6 +5624,53 @@
 
 			set_fsm_mode(BB_PLL14_MODE_REG);
 		}
+		/* Program PLL2 to 800MHz with ref clk = 27MHz */
+		writel_relaxed(0x1D, MM_PLL1_L_VAL_REG);
+		writel_relaxed(0x11, MM_PLL1_M_VAL_REG);
+		writel_relaxed(0x1B, MM_PLL1_N_VAL_REG);
+
+		regval = readl_relaxed(MM_PLL1_CONFIG_REG);
+
+		/* Enable the main output and the MN accumulator */
+		regval |= BIT(23) | BIT(22);
+
+		/* Set pre-divider and post-divider values to 1 and 1 */
+		regval &= ~BIT(19);
+		regval &= ~BM(21, 20);
+
+		writel_relaxed(regval, MM_PLL1_CONFIG_REG);
+
+		/* Set VCO frequency */
+		rmwreg(0x20000, MM_PLL1_CONFIG_REG, 0x30000);
+
+		/* Enable AUX output */
+		regval = readl_relaxed(MM_PLL1_TEST_CTL_REG);
+		regval |= BIT(12);
+		writel_relaxed(regval, MM_PLL1_TEST_CTL_REG);
+
+		/* Program PLL15 to 975MHz with ref clk = 27MHz */
+		writel_relaxed(0x24, MM_PLL3_L_VAL_REG);
+		writel_relaxed(0x1,  MM_PLL3_M_VAL_REG);
+		writel_relaxed(0x9,  MM_PLL3_N_VAL_REG);
+
+		regval = readl_relaxed(MM_PLL3_CONFIG_REG);
+
+		/* Enable the main output and the MN accumulator */
+		regval |= BIT(23) | BIT(22);
+
+		/* Set pre-divider and post-divider values to 1 and 1 */
+		regval &= ~BIT(19);
+		regval &= ~BM(21, 20);
+
+		writel_relaxed(regval, MM_PLL3_CONFIG_REG);
+
+		/* Set VCO frequency */
+		rmwreg(0x20000, MM_PLL3_CONFIG_REG, 0x30000);
+
+		/* Enable AUX output */
+		regval = readl_relaxed(MM_PLL3_TEST_CTL_REG);
+		regval |= BIT(12);
+		writel_relaxed(regval, MM_PLL3_TEST_CTL_REG);
 	}
 }
 
@@ -5510,12 +5706,15 @@
 
 	/*
 	 * Change the freq tables for gfx3d_clk, ijpeg_clk, mdp_clk,
-	 * tv_src_clk and vfe_clk at runtime.
+	 * tv_src_clk and vfe_clk at runtime and chain gmem_axi_clk
+	 * with gfx3d_axi_clk for 8064.
 	 */
 	if (cpu_is_apq8064()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
 		ijpeg_clk.freq_tbl = clk_tbl_ijpeg_8064;
+		mdp_clk.freq_tbl = clk_tbl_mdp_8064;
 		vfe_clk.freq_tbl = clk_tbl_vfe_8064;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
 	}
 
 	soc_update_sys_vdd = msm8960_update_sys_vdd;
@@ -5565,6 +5764,20 @@
 
 static int __init msm8960_clock_late_init(void)
 {
+	int rc;
+	struct clk *mmfpb_a_clk = clk_get_sys("clock-8960", "mmfpb_a_clk");
+
+	/* Vote for MMFPB to be at least 76.8MHz when an Apps CPU is active. */
+	if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
+			PTR_ERR(mmfpb_a_clk)))
+		return PTR_ERR(mmfpb_a_clk);
+	rc = clk_set_min_rate(mmfpb_a_clk, 76800000);
+	if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
+		return rc;
+	rc = clk_enable(mmfpb_a_clk);
+	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
+		return rc;
+
 	return local_unvote_sys_vdd(HIGH);
 }
 
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 4ca366f..1273198 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3653,7 +3653,7 @@
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
 	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
-	CLK_LOOKUP("vcodec_clk",	vcodec_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
@@ -3699,7 +3699,7 @@
 	CLK_LOOKUP("rotator_pclk",	rot_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_pclk",	tv_enc_p_clk.c,		NULL),
-	CLK_LOOKUP("vcodec_pclk",	vcodec_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c, "footswitch-8x60.7"),
 	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index d58de8f..a5db9b2 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -26,9 +26,11 @@
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
 #include <mach/msm_xo.h>
+#include <mach/rpm-9615.h>
 
 #include "clock-local.h"
 #include "clock-voter.h"
+#include "clock-rpm.h"
 #include "devices.h"
 
 #define REG(off)	(MSM_CLK_CTL_BASE + (off))
@@ -1252,11 +1254,17 @@
 	},
 };
 
-static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dummy_clk);
-static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dummy_clk);
-static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dummy_clk);
-static DEFINE_CLK_VOTER(dfab_sps_clk, &dummy_clk);
-static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &dummy_clk);
+DEFINE_CLK_RPM(cfpb_clk, cfpb_a_clk, CFPB, NULL);
+DEFINE_CLK_RPM(dfab_clk, dfab_a_clk, DAYTONA_FABRIC, NULL);
+DEFINE_CLK_RPM(ebi1_clk, ebi1_a_clk, EBI1, NULL);
+DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
+DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
 
 /*
  * TODO: replace dummy_clk below with ebi1_clk.c once the
@@ -1277,8 +1285,11 @@
 	{ TEST_PER_LS(0x14), &sdc2_p_clk.c },
 	{ TEST_PER_LS(0x15), &sdc2_clk.c },
 	{ TEST_PER_LS(0x26), &pmem_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_a_clk.c },
 	{ TEST_PER_LS(0x32), &dma_bam_p_clk.c },
-	{ TEST_PER_LS(0x3D), &gsbi1_p_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_a_clk.c },
 	{ TEST_PER_LS(0x3E), &gsbi1_uart_clk.c },
 	{ TEST_PER_LS(0x3F), &gsbi1_qup_clk.c },
 	{ TEST_PER_LS(0x41), &gsbi2_p_clk.c },
@@ -1293,6 +1304,8 @@
 	{ TEST_PER_LS(0x4D), &gsbi5_p_clk.c },
 	{ TEST_PER_LS(0x4E), &gsbi5_uart_clk.c },
 	{ TEST_PER_LS(0x50), &gsbi5_qup_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_a_clk.c },
 	{ TEST_PER_LS(0x7A), &pmic_ssbi2_clk.c },
 	{ TEST_PER_LS(0x7B), &pmic_arb0_p_clk.c },
 	{ TEST_PER_LS(0x7C), &pmic_arb1_p_clk.c },
@@ -1307,8 +1320,12 @@
 	{ TEST_PER_LS(0x8B), &usb_hsic_hsio_cal_clk.c },
 	{ TEST_PER_LS(0x8D), &usb_hs1_sys_clk.c },
 	{ TEST_PER_LS(0x92), &ce1_p_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_a_clk.c },
 	{ TEST_PER_LS(0xA4), &ce1_core_clk.c },
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
 	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
 	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
 	{ TEST_LPA(0x11), &codec_i2s_spkr_bit_clk.c },
@@ -1482,17 +1499,16 @@
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
-	/* TODO: Make these real when the RPM driver's ready. */
-	CLK_DUMMY("cfpb_clk",		cfpb_clk.c,	NULL, OFF),
-	CLK_DUMMY("cfpb_a_clk",		cfpb_a_clk.c,	NULL, OFF),
-	CLK_DUMMY("dfab_clk",		dfab_clk.c,	NULL, OFF),
-	CLK_DUMMY("dfab_a_clk",		dfab_a_clk.c,	NULL, OFF),
-	CLK_DUMMY("ebi1_clk",		ebi1_clk.c,	NULL, OFF),
-	CLK_DUMMY("ebi1_a_clk",		ebi1_a_clk.c,	NULL, OFF),
-	CLK_DUMMY("sfab_clk",		sfab_clk.c,	NULL, OFF),
-	CLK_DUMMY("sfab_a_clk",		sfab_a_clk.c,	NULL, OFF),
-	CLK_DUMMY("sfpb_clk",		sfpb_clk.c,	NULL, OFF),
-	CLK_DUMMY("sfpb_a_clk",		sfpb_a_clk.c,	NULL, OFF),
+	CLK_LOOKUP("cfpb_clk",		cfpb_clk.c,	NULL),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
+	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_a_clk",	ebi1_a_clk.c,	NULL),
+	CLK_LOOKUP("sfab_clk",		sfab_clk.c,	NULL),
+	CLK_LOOKUP("sfab_a_clk",	sfab_a_clk.c,	NULL),
+	CLK_LOOKUP("sfpb_clk",		sfpb_clk.c,	NULL),
+	CLK_LOOKUP("sfpb_a_clk",	sfpb_a_clk.c,	NULL),
 
 	CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, NULL),
 	CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, NULL),
@@ -1557,9 +1573,8 @@
 	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c,	"msm_sdcc.2"),
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,		"msm_sps"),
 
-	/* TODO: Make this real when RPM's ready. */
-	CLK_DUMMY("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL, OFF),
-	CLK_DUMMY("mem_clk",		ebi1_adm_clk.c, "msm_dmov", OFF),
+	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
 };
 
@@ -1651,9 +1666,36 @@
 
 		set_fsm_mode(SC_PLL0_MODE_REG);
 
-	} else if (readl_relaxed(SC_PLL0_MODE_REG) & BIT(20))
+	} else if (!(readl_relaxed(SC_PLL0_MODE_REG) & BIT(20)))
 		WARN(1, "PLL9 enabled in non-FSM mode!\n");
 
+	/* Check if PLL14 is enabled in FSM mode */
+	is_pll_enabled  = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+
+	if (!is_pll_enabled) {
+		writel_relaxed(0x19, BB_PLL14_L_VAL_REG);
+		writel_relaxed(0x0, BB_PLL14_M_VAL_REG);
+		writel_relaxed(0x1, BB_PLL14_N_VAL_REG);
+
+		regval = readl_relaxed(BB_PLL14_CONFIG_REG);
+
+		/* Enable main output and the MN accumulator */
+		regval |= BIT(23) | BIT(22);
+
+		/* Set pre-divider and post-divider values to 1 and 1 */
+		regval &= ~BIT(19);
+		regval &= ~BM(21, 20);
+
+		/* Set VCO frequency */
+		regval &= ~BM(17, 16);
+
+		writel_relaxed(regval, BB_PLL14_CONFIG_REG);
+
+		set_fsm_mode(BB_PLL14_MODE_REG);
+
+	} else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
+		WARN(1, "PLL14 enabled in non-FSM mode!\n");
+
 	/* Enable PLL4 source on the LPASS Primary PLL Mux */
 	regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
 	writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 6c826dd..d542b96 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -531,7 +531,51 @@
 	.mpm_apps_ipc_reg = MSM_APCS_GCC_BASE + 0x008,
 	.mpm_apps_ipc_val =  BIT(1),
 	.mpm_ipc_irq = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+};
 
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x00, 0x03, 0x0B, 0x00,
+	0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+	0x30, 0x20, 0x10, 0x00,
+	0x50, 0x03, 0x50, 0x00,
+	0x10, 0x20, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+	0x30, 0x20, 0x10, 0x00,
+	0x50, 0x07, 0x50, 0x00,
+	0x10, 0x20, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
 };
 
 static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
@@ -558,6 +602,7 @@
 
 void __init msm9615_device_init(void)
 {
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_clock_init(&msm9615_clock_init_data);
 	acpuclk_init(&acpuclk_9615_soc_data);
 	BUG_ON(msm_rpm_init(&msm_rpm_data));
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 250cbad..3772884 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -33,7 +33,6 @@
 #include <asm/mach/mmc.h>
 #include <mach/msm_hsusb.h>
 #include <mach/usbdiag.h>
-#include <mach/usb_gadget_fserial.h>
 #include <mach/rpc_hsusb.h>
 
 static struct resource resources_uart1[] = {
@@ -299,35 +298,6 @@
 	return platform_device_register(pdev);
 }
 
-#ifdef CONFIG_USB_ANDROID_DIAG
-struct usb_diag_platform_data usb_diag_pdata = {
-	.ch_name = DIAG_LEGACY,
-	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
-};
-
-struct platform_device usb_diag_device = {
-	.name	= "usb_diag",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &usb_diag_pdata,
-	},
-};
-#endif
-
-#ifdef CONFIG_USB_F_SERIAL
-static struct usb_gadget_fserial_platform_data fserial_pdata = {
-	.no_ports	= 2,
-};
-
-struct platform_device usb_gadget_fserial_device = {
-	.name	= "usb_fserial",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &fserial_pdata,
-	},
-};
-#endif
-
 struct platform_device asoc_msm_pcm = {
 	.name   = "msm-dsp-audio",
 	.id     = 0,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index ef187a6..488db75 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -414,14 +414,14 @@
 	},
 	{
 		.name	= "sdcc_dma_chnl",
-		.start	= DMOV_SDC4_CHAN,
-		.end	= DMOV_SDC4_CHAN,
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
 		.name	= "sdcc_dma_crci",
-		.start	= DMOV_SDC4_CRCI,
-		.end	= DMOV_SDC4_CRCI,
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
@@ -439,14 +439,14 @@
 	},
 	{
 		.name	= "sdcc_dma_chnl",
-		.start	= DMOV_SDC3_CHAN,
-		.end	= DMOV_SDC3_CHAN,
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
 		.name	= "sdcc_dma_crci",
-		.start	= DMOV_SDC3_CRCI,
-		.end	= DMOV_SDC3_CRCI,
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index e1a3b4c..0da9de3 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -666,14 +666,14 @@
 	},
 	{
 		.name	= "sdcc_dma_chnl",
-		.start	= DMOV_SDC4_CHAN,
-		.end	= DMOV_SDC4_CHAN,
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
 		.name	= "sdcc_dma_crci",
-		.start	= DMOV_SDC4_CRCI,
-		.end	= DMOV_SDC4_CRCI,
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
@@ -691,14 +691,14 @@
 	},
 	{
 		.name	= "sdcc_dma_chnl",
-		.start	= DMOV_SDC3_CHAN,
-		.end	= DMOV_SDC3_CHAN,
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
 		.name	= "sdcc_dma_crci",
-		.start	= DMOV_SDC3_CRCI,
-		.end	= DMOV_SDC3_CRCI,
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index f4bc5f0..8280aa0 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1461,6 +1461,22 @@
 
 #define MHZ (1000*1000)
 
+#define TCSR_GSBI_IRQ_MUX_SEL	0x0044
+
+#define GSBI_IRQ_MUX_SEL_MASK	0xF
+#define GSBI_IRQ_MUX_SEL_DSPS	0xB
+
+static void dsps_init1(struct msm_dsps_platform_data *data)
+{
+	int val;
+
+	/* route GSBI12 interrutps to DSPS */
+	val = secure_readl(MSM_TCSR_BASE +  TCSR_GSBI_IRQ_MUX_SEL);
+	val &= ~GSBI_IRQ_MUX_SEL_MASK;
+	val |= GSBI_IRQ_MUX_SEL_DSPS;
+	secure_writel(val, MSM_TCSR_BASE + TCSR_GSBI_IRQ_MUX_SEL);
+}
+
 static struct dsps_clk_info dsps_clks[] = {
 	{
 		.name = "ppss_pclk",
@@ -1503,6 +1519,7 @@
 	.gpios_num = 0,
 	.regs = dsps_regs,
 	.regs_num = ARRAY_SIZE(dsps_regs),
+	.init = dsps_init1,
 	.signature = DSPS_SIGNATURE,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 2dbbc7d..df6a64c 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -24,9 +24,7 @@
 #include <linux/leds-pmic8058.h>
 #include <linux/clkdev.h>
 #include <linux/msm_ssbi.h>
-#ifdef CONFIG_MSM_BUS_SCALING
 #include <mach/msm_bus.h>
-#endif
 
 struct msm_camera_io_ext {
 	uint32_t mdcphy;
@@ -62,9 +60,7 @@
 	struct msm_camera_io_ext ioext;
 	struct msm_camera_io_clk ioclk;
 	uint8_t csid_core;
-#ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *cam_bus_scale_table;
-#endif
 };
 enum msm_camera_csi_data_format {
 	CSI_8BIT,
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index 824ef5f..cfb2024 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -86,6 +86,7 @@
 	struct dsps_regulator_info *regs;
 	int regs_num;
 	int dsps_pwr_ctl_en;
+	void (*init)(struct msm_dsps_platform_data *data);
 	u32 signature;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/rpm-8960.h b/arch/arm/mach-msm/include/mach/rpm-8960.h
index bee47a5..d5ebba0 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8960.h
@@ -440,8 +440,10 @@
 	MSM_RPM_STATUS_ID_HDMI_SWITCH				= 120,
 	MSM_RPM_STATUS_ID_DDR_DMM_0				= 121,
 	MSM_RPM_STATUS_ID_DDR_DMM_1				= 122,
+	MSM_RPM_STATUS_ID_EBI1_CH0_RANGE			= 123,
+	MSM_RPM_STATUS_ID_EBI1_CH1_RANGE			= 124,
 
-	MSM_RPM_STATUS_ID_LAST = MSM_RPM_STATUS_ID_DDR_DMM_1
+	MSM_RPM_STATUS_ID_LAST = MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_8960_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
index 3bcebd4..85dcd89 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
@@ -11,67 +11,61 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8660_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8660_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
 
-#define RPM_VREG_PIN_CTRL_NONE	0x00
-#define RPM_VREG_PIN_CTRL_A0	0x01
-#define RPM_VREG_PIN_CTRL_A1	0x02
-#define RPM_VREG_PIN_CTRL_D0	0x04
-#define RPM_VREG_PIN_CTRL_D1	0x08
+#define RPM_VREG_PIN_CTRL_PM8058_A0	0x01
+#define RPM_VREG_PIN_CTRL_PM8058_A1	0x02
+#define RPM_VREG_PIN_CTRL_PM8058_D0	0x04
+#define RPM_VREG_PIN_CTRL_PM8058_D1	0x08
 
-/*
- * Pin Function
- * ENABLE  - pin control switches between disable and enable
- * MODE    - pin control switches between LPM and HPM
- * SLEEP_B - regulator is forced into LPM by asserting sleep_b signal
- * NONE    - do not use pin control
+#define RPM_VREG_PIN_CTRL_PM8901_A0	0x01
+#define RPM_VREG_PIN_CTRL_PM8901_A1	0x02
+#define RPM_VREG_PIN_CTRL_PM8901_D0	0x04
+#define RPM_VREG_PIN_CTRL_PM8901_D1	0x08
+
+
+/**
+ * enum rpm_vreg_pin_fn_8660 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8660_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_8660_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8660_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8660_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
  *
  * The pin function specified in platform data corresponds to the active state
  * pin function value.  Pin function will be NONE until a consumer requests
- * pin control with regulator_set_mode(vreg, REGULATOR_MODE_IDLE).
+ * pin control to be enabled.
  */
-enum rpm_vreg_pin_fn {
-	RPM_VREG_PIN_FN_ENABLE = 0,
-	RPM_VREG_PIN_FN_MODE,
-	RPM_VREG_PIN_FN_SLEEP_B,
-	RPM_VREG_PIN_FN_NONE,
+enum rpm_vreg_pin_fn_8660 {
+	RPM_VREG_PIN_FN_8660_ENABLE = 0,
+	RPM_VREG_PIN_FN_8660_MODE,
+	RPM_VREG_PIN_FN_8660_SLEEP_B,
+	RPM_VREG_PIN_FN_8660_NONE,
 };
 
-enum rpm_vreg_mode {
-	RPM_VREG_MODE_PIN_CTRL = 0,
-	RPM_VREG_MODE_NONE = 0,
-	RPM_VREG_MODE_LPM,
-	RPM_VREG_MODE_HPM,
+/**
+ * enum rpm_vreg_force_mode_8660 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8660_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8660_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_8660_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_8660_HPM:	force into high power mode
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_8660 {
+	RPM_VREG_FORCE_MODE_8660_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_8660_NONE = 0,
+	RPM_VREG_FORCE_MODE_8660_LPM,
+	RPM_VREG_FORCE_MODE_8660_HPM,
 };
 
-enum rpm_vreg_state {
-	RPM_VREG_STATE_OFF = 0,
-	RPM_VREG_STATE_ON,
-};
-
-enum rpm_vreg_freq {
-	RPM_VREG_FREQ_NONE,
-	RPM_VREG_FREQ_19p20,
-	RPM_VREG_FREQ_9p60,
-	RPM_VREG_FREQ_6p40,
-	RPM_VREG_FREQ_4p80,
-	RPM_VREG_FREQ_3p84,
-	RPM_VREG_FREQ_3p20,
-	RPM_VREG_FREQ_2p74,
-	RPM_VREG_FREQ_2p40,
-	RPM_VREG_FREQ_2p13,
-	RPM_VREG_FREQ_1p92,
-	RPM_VREG_FREQ_1p75,
-	RPM_VREG_FREQ_1p60,
-	RPM_VREG_FREQ_1p48,
-	RPM_VREG_FREQ_1p37,
-	RPM_VREG_FREQ_1p28,
-	RPM_VREG_FREQ_1p20,
-};
-
-enum rpm_vreg_id {
-	RPM_VREG_ID_PM8058_L0 = 0,
+enum rpm_vreg_id_8660 {
+	RPM_VREG_ID_PM8058_L0,
 	RPM_VREG_ID_PM8058_L1,
 	RPM_VREG_ID_PM8058_L2,
 	RPM_VREG_ID_PM8058_L3,
@@ -122,55 +116,68 @@
 	RPM_VREG_ID_PM8901_LVS2,
 	RPM_VREG_ID_PM8901_LVS3,
 	RPM_VREG_ID_PM8901_MVS0,
-	RPM_VREG_ID_MAX,
+	RPM_VREG_ID_8660_MAX_REAL = RPM_VREG_ID_PM8901_MVS0,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8058_L0_PC,
+	RPM_VREG_ID_PM8058_L1_PC,
+	RPM_VREG_ID_PM8058_L2_PC,
+	RPM_VREG_ID_PM8058_L3_PC,
+	RPM_VREG_ID_PM8058_L4_PC,
+	RPM_VREG_ID_PM8058_L5_PC,
+	RPM_VREG_ID_PM8058_L6_PC,
+	RPM_VREG_ID_PM8058_L7_PC,
+	RPM_VREG_ID_PM8058_L8_PC,
+	RPM_VREG_ID_PM8058_L9_PC,
+	RPM_VREG_ID_PM8058_L10_PC,
+	RPM_VREG_ID_PM8058_L11_PC,
+	RPM_VREG_ID_PM8058_L12_PC,
+	RPM_VREG_ID_PM8058_L13_PC,
+	RPM_VREG_ID_PM8058_L14_PC,
+	RPM_VREG_ID_PM8058_L15_PC,
+	RPM_VREG_ID_PM8058_L16_PC,
+	RPM_VREG_ID_PM8058_L17_PC,
+	RPM_VREG_ID_PM8058_L18_PC,
+	RPM_VREG_ID_PM8058_L19_PC,
+	RPM_VREG_ID_PM8058_L20_PC,
+	RPM_VREG_ID_PM8058_L21_PC,
+	RPM_VREG_ID_PM8058_L22_PC,
+	RPM_VREG_ID_PM8058_L23_PC,
+	RPM_VREG_ID_PM8058_L24_PC,
+	RPM_VREG_ID_PM8058_L25_PC,
+	RPM_VREG_ID_PM8058_S0_PC,
+	RPM_VREG_ID_PM8058_S1_PC,
+	RPM_VREG_ID_PM8058_S2_PC,
+	RPM_VREG_ID_PM8058_S3_PC,
+	RPM_VREG_ID_PM8058_S4_PC,
+	RPM_VREG_ID_PM8058_LVS0_PC,
+	RPM_VREG_ID_PM8058_LVS1_PC,
+
+	RPM_VREG_ID_PM8901_L0_PC,
+	RPM_VREG_ID_PM8901_L1_PC,
+	RPM_VREG_ID_PM8901_L2_PC,
+	RPM_VREG_ID_PM8901_L3_PC,
+	RPM_VREG_ID_PM8901_L4_PC,
+	RPM_VREG_ID_PM8901_L5_PC,
+	RPM_VREG_ID_PM8901_L6_PC,
+	RPM_VREG_ID_PM8901_S0_PC,
+	RPM_VREG_ID_PM8901_S1_PC,
+	RPM_VREG_ID_PM8901_S2_PC,
+	RPM_VREG_ID_PM8901_S3_PC,
+	RPM_VREG_ID_PM8901_S4_PC,
+	RPM_VREG_ID_PM8901_LVS0_PC,
+	RPM_VREG_ID_PM8901_LVS1_PC,
+	RPM_VREG_ID_PM8901_LVS2_PC,
+	RPM_VREG_ID_PM8901_LVS3_PC,
+	RPM_VREG_ID_PM8901_MVS0_PC,
+	RPM_VREG_ID_8660_MAX = RPM_VREG_ID_PM8901_MVS0_PC,
 };
 
 /* Minimum high power mode loads in uA. */
-#define RPM_VREG_LDO_50_HPM_MIN_LOAD	5000
-#define RPM_VREG_LDO_150_HPM_MIN_LOAD	10000
-#define RPM_VREG_LDO_300_HPM_MIN_LOAD	10000
-#define RPM_VREG_SMPS_HPM_MIN_LOAD	50000
-#define RPM_VREG_FTSMPS_HPM_MIN_LOAD	100000
-
-/*
- * default_uV = initial voltage to set the regulator to if enable is called
- *		before set_voltage (e.g. when boot_on or always_on is set).
- * peak_uA    = initial load requirement sent in RPM request; used to determine
- *		initial mode.
- * avg_uA     = initial avg load requirement sent in RPM request; overwritten
- *		along with peak_uA when regulator_set_mode or
- *		regulator_set_optimum_mode is called.
- * pin_fn     = RPM_VREG_PIN_FN_ENABLE  - pin control ON/OFF
- *	      = RPM_VREG_PIN_FN_MODE    - pin control LPM/HPM
- *	      = RPM_VREG_PIN_FN_SLEEP_B - regulator is forced into LPM by
- *					  asserting sleep_b signal
- *	      = RPM_VREG_PIN_FN_NONE    - do not use pin control
- * mode	      = used to specify a force mode which overrides the votes of other
- *		RPM masters.
- * state      = initial state sent in RPM request.
- * sleep_selectable = flag which indicates that regulator should be accessable
- *		by external private API and that spinlocks should be used.
- */
-struct rpm_vreg_pdata {
-	struct regulator_init_data	init_data;
-	int				default_uV;
-	unsigned			peak_uA;
-	unsigned			avg_uA;
-	unsigned			pull_down_enable;
-	unsigned			pin_ctrl;
-	enum rpm_vreg_freq		freq;
-	enum rpm_vreg_pin_fn		pin_fn;
-	enum rpm_vreg_mode		mode;
-	enum rpm_vreg_state		state;
-	int				sleep_selectable;
-};
-
-enum rpm_vreg_voter {
-	RPM_VREG_VOTER_REG_FRAMEWORK = 0, /* for internal use only */
-	RPM_VREG_VOTER1,		  /* for use by the acpu-clock driver */
-	RPM_VREG_VOTER2,		  /* for use by the acpu-clock driver */
-	RPM_VREG_VOTER3,		  /* for use by other drivers */
-	RPM_VREG_VOTER_COUNT,
-};
+#define RPM_VREG_8660_LDO_50_HPM_MIN_LOAD	5000
+#define RPM_VREG_8660_LDO_150_HPM_MIN_LOAD	10000
+#define RPM_VREG_8660_LDO_300_HPM_MIN_LOAD	10000
+#define RPM_VREG_8660_SMPS_HPM_MIN_LOAD		50000
+#define RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD	100000
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
index de7571b..6de47bd 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
@@ -11,118 +11,83 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8960_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8960_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
 
 /* Pin control input signals. */
-#define RPM_VREG_PIN_CTRL_NONE		0x00
-#define RPM_VREG_PIN_CTRL_EN0		0x01
-#define RPM_VREG_PIN_CTRL_EN1		0x02
-#define RPM_VREG_PIN_CTRL_EN2		0x04
-#define RPM_VREG_PIN_CTRL_EN3		0x08
-#define RPM_VREG_PIN_CTRL_ALL		0x0F
-
-#define RPM_VREG_PIN_CTRL_PM8921_D1	RPM_VREG_PIN_CTRL_EN0
-#define RPM_VREG_PIN_CTRL_PM8921_A0	RPM_VREG_PIN_CTRL_EN1
-#define RPM_VREG_PIN_CTRL_PM8921_A1	RPM_VREG_PIN_CTRL_EN2
-#define RPM_VREG_PIN_CTRL_PM8921_A2	RPM_VREG_PIN_CTRL_EN3
+#define RPM_VREG_PIN_CTRL_PM8921_D1	0x01
+#define RPM_VREG_PIN_CTRL_PM8921_A0	0x02
+#define RPM_VREG_PIN_CTRL_PM8921_A1	0x04
+#define RPM_VREG_PIN_CTRL_PM8921_A2	0x08
 
 /**
- * enum rpm_vreg_pin_fn - RPM regulator pin function choices
- * %RPM_VREG_PIN_FN_DONT_CARE:	do not care about pin control state of the
- *				regulator; allow another master processor to
- *				specify pin control
- * %RPM_VREG_PIN_FN_ENABLE:	pin control switches between disable and enable
- * %RPM_VREG_PIN_FN_MODE:	pin control switches between LPM and HPM
- * %RPM_VREG_PIN_FN_SLEEP_B:	regulator is forced into LPM when sleep_b signal
- *				is asserted
- * %RPM_VREG_PIN_FN_NONE:	do not use pin control for the regulator and do
- *				not allow another master to request pin control
+ * enum rpm_vreg_pin_fn_8960 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8960_DONT_CARE:	do not care about pin control state of
+ *					the regulator; allow another master
+ *					processor to specify pin control
+ * %RPM_VREG_PIN_FN_8960_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_8960_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8960_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8960_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
  *
  * The pin function specified in platform data corresponds to the active state
  * pin function value.  Pin function will be NONE until a consumer requests
  * pin control to be enabled.
  */
-enum rpm_vreg_pin_fn {
-	RPM_VREG_PIN_FN_DONT_CARE,
-	RPM_VREG_PIN_FN_ENABLE,
-	RPM_VREG_PIN_FN_MODE,
-	RPM_VREG_PIN_FN_SLEEP_B,
-	RPM_VREG_PIN_FN_NONE,
+enum rpm_vreg_pin_fn_8960 {
+	RPM_VREG_PIN_FN_8960_DONT_CARE,
+	RPM_VREG_PIN_FN_8960_ENABLE,
+	RPM_VREG_PIN_FN_8960_MODE,
+	RPM_VREG_PIN_FN_8960_SLEEP_B,
+	RPM_VREG_PIN_FN_8960_NONE,
 };
 
 /**
- * enum rpm_vreg_force_mode - RPM regulator force mode choices
- * %RPM_VREG_FORCE_MODE_PIN_CTRL: allow pin control usage
- * %RPM_VREG_FORCE_MODE_NONE:	  do not force any mode
- * %RPM_VREG_FORCE_MODE_LPM:	  force into low power mode
- * %RPM_VREG_FORCE_MODE_AUTO:	  allow regulator to automatically select its
- *				  own mode based on realtime current draw
- *				  (only available for SMPS regulators)
- * %RPM_VREG_FORCE_MODE_HPM:	  force into high power mode
- * %RPM_VREG_FORCE_MODE_BYPASS:   set regulator to use bypass mode, i.e. to act
- *				  as a switch and not regulate (only available
- *				  for LDO regulators)
+ * enum rpm_vreg_force_mode_8960 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8960_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8960_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_8960_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_8960_AUTO:	allow regulator to automatically select
+ *					its own mode based on realtime current
+ *					draw (only available for SMPS
+ *					regulators)
+ * %RPM_VREG_FORCE_MODE_8960_HPM:	force into high power mode
+ * %RPM_VREG_FORCE_MODE_8960_BYPASS:	set regulator to use bypass mode, i.e.
+ *					to act as a switch and not regulate
+ *					(only available for LDO regulators)
  *
  * Force mode is used to override aggregation with other masters and to set
  * special operating modes.
  */
-enum rpm_vreg_force_mode {
-	RPM_VREG_FORCE_MODE_PIN_CTRL = 0,
-	RPM_VREG_FORCE_MODE_NONE = 0,
-	RPM_VREG_FORCE_MODE_LPM,
-	RPM_VREG_FORCE_MODE_AUTO,		/* SMPS only */
-	RPM_VREG_FORCE_MODE_HPM,
-	RPM_VREG_FORCE_MODE_BYPASS,		/* LDO only */
+enum rpm_vreg_force_mode_8960 {
+	RPM_VREG_FORCE_MODE_8960_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_8960_NONE = 0,
+	RPM_VREG_FORCE_MODE_8960_LPM,
+	RPM_VREG_FORCE_MODE_8960_AUTO,		/* SMPS only */
+	RPM_VREG_FORCE_MODE_8960_HPM,
+	RPM_VREG_FORCE_MODE_8960_BYPASS,	/* LDO only */
 };
 
 /**
- * enum rpm_vreg_power_mode - power mode for SMPS regulators
- * %RPM_VREG_POWER_MODE_HYSTERETIC:	Use hysteretic mode for HPM and when
- *					usage goes high in AUTO
- * %RPM_VREG_POWER_MODE_PWM:		Use PWM mode for HPM and when usage goes
- *					high in AUTO
+ * enum rpm_vreg_power_mode_8960 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_8960_HYSTERETIC: Use hysteretic mode for HPM and when
+ *					 usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_8960_PWM:	 Use PWM mode for HPM and when usage
+ *					 goes high in AUTO
  */
-enum rpm_vreg_power_mode {
-	RPM_VREG_POWER_MODE_HYSTERETIC,
-	RPM_VREG_POWER_MODE_PWM,
-};
-
-/**
- * enum rpm_vreg_state - enable state for switch or NCP
- */
-enum rpm_vreg_state {
-	RPM_VREG_STATE_OFF,
-	RPM_VREG_STATE_ON,
-};
-
-/**
- * enum rpm_vreg_freq - switching frequency for SMPS or NCP
- */
-enum rpm_vreg_freq {
-	RPM_VREG_FREQ_NONE,
-	RPM_VREG_FREQ_19p20,
-	RPM_VREG_FREQ_9p60,
-	RPM_VREG_FREQ_6p40,
-	RPM_VREG_FREQ_4p80,
-	RPM_VREG_FREQ_3p84,
-	RPM_VREG_FREQ_3p20,
-	RPM_VREG_FREQ_2p74,
-	RPM_VREG_FREQ_2p40,
-	RPM_VREG_FREQ_2p13,
-	RPM_VREG_FREQ_1p92,
-	RPM_VREG_FREQ_1p75,
-	RPM_VREG_FREQ_1p60,
-	RPM_VREG_FREQ_1p48,
-	RPM_VREG_FREQ_1p37,
-	RPM_VREG_FREQ_1p28,
-	RPM_VREG_FREQ_1p20,
+enum rpm_vreg_power_mode_8960 {
+	RPM_VREG_POWER_MODE_8960_HYSTERETIC,
+	RPM_VREG_POWER_MODE_8960_PWM,
 };
 
 /**
  * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
  */
-enum rpm_vreg_id {
+enum rpm_vreg_id_8960 {
 	RPM_VREG_ID_PM8921_L1,
 	RPM_VREG_ID_PM8921_L2,
 	RPM_VREG_ID_PM8921_L3,
@@ -211,76 +176,12 @@
 };
 
 /* Minimum high power mode loads in uA. */
-#define RPM_VREG_LDO_50_HPM_MIN_LOAD		5000
-#define RPM_VREG_LDO_150_HPM_MIN_LOAD		10000
-#define RPM_VREG_LDO_300_HPM_MIN_LOAD		10000
-#define RPM_VREG_LDO_600_HPM_MIN_LOAD		10000
-#define RPM_VREG_LDO_1200_HPM_MIN_LOAD		10000
-#define RPM_VREG_SMPS_1500_HPM_MIN_LOAD		100000
-#define RPM_VREG_SMPS_2000_HPM_MIN_LOAD		100000
-
-/**
- * struct rpm_regulator_init_data - RPM regulator initialization data
- * @init_data:		regulator constraints
- * @id:			regulator id; from enum rpm_vreg_id
- * @sleep_selectable:	flag which indicates that regulator should be accessable
- *			by external private API and that spinlocks should be
- *			used instead of mutex locks
- * @system_uA:		current drawn from regulator not accounted for by any
- *			regulator framework consumer
- * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
- * @freq:		enum value representing the switching frequency of an
- *			SMPS or NCP
- * @pin_ctrl:		pin control inputs to use for the regulator; should be
- *			a combination of RPM_VREG_PIN_CTRL_* values
- * @pin_fn:		action to perform when pin control pin(s) is/are active
- * @force_mode:		used to specify a force mode which overrides the votes
- *			of other RPM masters.
- * @default_uV:		initial voltage to set the regulator to if enable is
- *			called before set_voltage (e.g. when boot_on or
- *			always_on is set).
- * @peak_uA:		initial peak load requirement sent in RPM request; used
- *			to determine initial mode.
- * @avg_uA:		average load requirement sent in RPM request
- * @state:		initial enable state sent in RPM request for switch or
- *			NCP
- */
-struct rpm_regulator_init_data {
-	struct regulator_init_data	init_data;
-	enum rpm_vreg_id		id;
-	int				sleep_selectable;
-	int				system_uA;
-	unsigned			pull_down_enable;
-	enum rpm_vreg_freq		freq;
-	unsigned			pin_ctrl;
-	enum rpm_vreg_pin_fn		pin_fn;
-	enum rpm_vreg_force_mode	force_mode;
-	enum rpm_vreg_power_mode	power_mode;
-	int				default_uV;
-	unsigned			peak_uA;
-	unsigned			avg_uA;
-	enum rpm_vreg_state		state;
-};
-
-/**
- * struct rpm_regulator_platform_data - RPM regulator platform data
- */
-struct rpm_regulator_platform_data {
-	struct rpm_regulator_init_data	*init_data;
-	int				num_regulators;
-};
-
-/**
- * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
- */
-enum rpm_vreg_voter {
-	RPM_VREG_VOTER_REG_FRAMEWORK,	/* for internal use only */
-	RPM_VREG_VOTER1,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER2,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER3,		/* for use by other drivers */
-	RPM_VREG_VOTER4,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER5,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER_COUNT,
-};
+#define RPM_VREG_8960_LDO_50_HPM_MIN_LOAD		5000
+#define RPM_VREG_8960_LDO_150_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_300_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_600_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_1200_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_SMPS_1500_HPM_MIN_LOAD		100000
+#define RPM_VREG_8960_SMPS_2000_HPM_MIN_LOAD		100000
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
new file mode 100644
index 0000000..f5fa8ca
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_9615_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_9615_H
+
+/* Pin control input signals. */
+#define RPM_VREG_PIN_CTRL_PM8018_D1	0x01
+#define RPM_VREG_PIN_CTRL_PM8018_A0	0x02
+#define RPM_VREG_PIN_CTRL_PM8018_A1	0x04
+#define RPM_VREG_PIN_CTRL_PM8018_A2	0x08
+
+/**
+ * enum rpm_vreg_pin_fn_9615 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_9615_DONT_CARE:	do not care about pin control state of
+ *					the regulator; allow another master
+ *					processor to specify pin control
+ * %RPM_VREG_PIN_FN_9615_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_9615_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_9615_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_9615_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
+ *
+ * The pin function specified in platform data corresponds to the active state
+ * pin function value.  Pin function will be NONE until a consumer requests
+ * pin control to be enabled.
+ */
+enum rpm_vreg_pin_fn_9615 {
+	RPM_VREG_PIN_FN_9615_DONT_CARE,
+	RPM_VREG_PIN_FN_9615_ENABLE,
+	RPM_VREG_PIN_FN_9615_MODE,
+	RPM_VREG_PIN_FN_9615_SLEEP_B,
+	RPM_VREG_PIN_FN_9615_NONE,
+};
+
+/**
+ * enum rpm_vreg_force_mode_9615 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_9615_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_9615_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_9615_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_9615_AUTO:	allow regulator to automatically select
+ *					its own mode based on realtime current
+ *					draw (only available for SMPS
+ *					regulators)
+ * %RPM_VREG_FORCE_MODE_9615_HPM:	force into high power mode
+ * %RPM_VREG_FORCE_MODE_9615_BYPASS:	set regulator to use bypass mode, i.e.
+ *					to act as a switch and not regulate
+ *					(only available for LDO regulators)
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_9615 {
+	RPM_VREG_FORCE_MODE_9615_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_9615_NONE = 0,
+	RPM_VREG_FORCE_MODE_9615_LPM,
+	RPM_VREG_FORCE_MODE_9615_AUTO,		/* SMPS only */
+	RPM_VREG_FORCE_MODE_9615_HPM,
+	RPM_VREG_FORCE_MODE_9615_BYPASS,	/* LDO only */
+};
+
+/**
+ * enum rpm_vreg_power_mode_9615 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_9615_HYSTERETIC: Use hysteretic mode for HPM and when
+ *					 usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_9615_PWM:	 Use PWM mode for HPM and when usage
+ *					 goes high in AUTO
+ */
+enum rpm_vreg_power_mode_9615 {
+	RPM_VREG_POWER_MODE_9615_HYSTERETIC,
+	RPM_VREG_POWER_MODE_9615_PWM,
+};
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_9615 {
+	RPM_VREG_ID_PM8018_L2,
+	RPM_VREG_ID_PM8018_L3,
+	RPM_VREG_ID_PM8018_L4,
+	RPM_VREG_ID_PM8018_L5,
+	RPM_VREG_ID_PM8018_L6,
+	RPM_VREG_ID_PM8018_L7,
+	RPM_VREG_ID_PM8018_L8,
+	RPM_VREG_ID_PM8018_L9,
+	RPM_VREG_ID_PM8018_L10,
+	RPM_VREG_ID_PM8018_L11,
+	RPM_VREG_ID_PM8018_L12,
+	RPM_VREG_ID_PM8018_L13,
+	RPM_VREG_ID_PM8018_L14,
+	RPM_VREG_ID_PM8018_S1,
+	RPM_VREG_ID_PM8018_S2,
+	RPM_VREG_ID_PM8018_S3,
+	RPM_VREG_ID_PM8018_S4,
+	RPM_VREG_ID_PM8018_S5,
+	RPM_VREG_ID_PM8018_LVS1,
+	RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_LVS1,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8018_L2_PC,
+	RPM_VREG_ID_PM8018_L3_PC,
+	RPM_VREG_ID_PM8018_L4_PC,
+	RPM_VREG_ID_PM8018_L5_PC,
+	RPM_VREG_ID_PM8018_L6_PC,
+	RPM_VREG_ID_PM8018_L7_PC,
+	RPM_VREG_ID_PM8018_L8_PC,
+	RPM_VREG_ID_PM8018_L13_PC,
+	RPM_VREG_ID_PM8018_L14_PC,
+	RPM_VREG_ID_PM8018_S1_PC,
+	RPM_VREG_ID_PM8018_S2_PC,
+	RPM_VREG_ID_PM8018_S3_PC,
+	RPM_VREG_ID_PM8018_S4_PC,
+	RPM_VREG_ID_PM8018_S5_PC,
+	RPM_VREG_ID_PM8018_LVS1_PC,
+	RPM_VREG_ID_PM8018_MAX = RPM_VREG_ID_PM8018_LVS1_PC,
+};
+
+/* Minimum high power mode loads in uA. */
+#define RPM_VREG_9615_LDO_50_HPM_MIN_LOAD	5000
+#define RPM_VREG_9615_LDO_150_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_LDO_300_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_LDO_1200_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_SMPS_1500_HPM_MIN_LOAD	100000
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 1187efc..8b5a1e7 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -10,18 +10,130 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
 
 #include <linux/regulator/machine.h>
 
 #define RPM_REGULATOR_DEV_NAME "rpm-regulator"
 
-#if defined(CONFIG_ARCH_MSM8X60)
 #include <mach/rpm-regulator-8660.h>
-#elif defined(CONFIG_ARCH_MSM8960)
 #include <mach/rpm-regulator-8960.h>
-#endif
+#include <mach/rpm-regulator-9615.h>
+
+/**
+ * enum rpm_vreg_version - supported RPM regulator versions
+ */
+enum rpm_vreg_version {
+	RPM_VREG_VERSION_8660,
+	RPM_VREG_VERSION_8960,
+	RPM_VREG_VERSION_9615,
+	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_9615,
+};
+
+#define RPM_VREG_PIN_CTRL_NONE		0x00
+
+/**
+ * enum rpm_vreg_state - enable state for switch or NCP
+ */
+enum rpm_vreg_state {
+	RPM_VREG_STATE_OFF,
+	RPM_VREG_STATE_ON,
+};
+
+/**
+ * enum rpm_vreg_freq - switching frequency for SMPS or NCP
+ */
+enum rpm_vreg_freq {
+	RPM_VREG_FREQ_NONE,
+	RPM_VREG_FREQ_19p20,
+	RPM_VREG_FREQ_9p60,
+	RPM_VREG_FREQ_6p40,
+	RPM_VREG_FREQ_4p80,
+	RPM_VREG_FREQ_3p84,
+	RPM_VREG_FREQ_3p20,
+	RPM_VREG_FREQ_2p74,
+	RPM_VREG_FREQ_2p40,
+	RPM_VREG_FREQ_2p13,
+	RPM_VREG_FREQ_1p92,
+	RPM_VREG_FREQ_1p75,
+	RPM_VREG_FREQ_1p60,
+	RPM_VREG_FREQ_1p48,
+	RPM_VREG_FREQ_1p37,
+	RPM_VREG_FREQ_1p28,
+	RPM_VREG_FREQ_1p20,
+};
+
+/**
+ * struct rpm_regulator_init_data - RPM regulator initialization data
+ * @init_data:		regulator constraints
+ * @id:			regulator id; from enum rpm_vreg_id
+ * @sleep_selectable:	flag which indicates that regulator should be accessable
+ *			by external private API and that spinlocks should be
+ *			used instead of mutex locks
+ * @system_uA:		current drawn from regulator not accounted for by any
+ *			regulator framework consumer
+ * @enable_time:	time in us taken to enable a regulator to the maximum
+ *			allowed voltage for the system.  This is dependent upon
+ *			the load and capacitance for a regulator on the board.
+ * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
+ * @freq:		enum value representing the switching frequency of an
+ *			SMPS or NCP
+ * @pin_ctrl:		pin control inputs to use for the regulator; should be
+ *			a combination of RPM_VREG_PIN_CTRL_* values
+ * @pin_fn:		action to perform when pin control pin(s) is/are active
+ * @force_mode:		used to specify a force mode which overrides the votes
+ *			of other RPM masters.
+ * @default_uV:		initial voltage to set the regulator to if enable is
+ *			called before set_voltage (e.g. when boot_on or
+ *			always_on is set).
+ * @peak_uA:		initial peak load requirement sent in RPM request; used
+ *			to determine initial mode.
+ * @avg_uA:		average load requirement sent in RPM request
+ * @state:		initial enable state sent in RPM request for switch or
+ *			NCP
+ */
+struct rpm_regulator_init_data {
+	struct regulator_init_data	init_data;
+	int				id;
+	int				sleep_selectable;
+	int				system_uA;
+	int				enable_time;
+	unsigned			pull_down_enable;
+	enum rpm_vreg_freq		freq;
+	unsigned			pin_ctrl;
+	int				pin_fn;
+	int				force_mode;
+	int				power_mode;
+	int				default_uV;
+	unsigned			peak_uA;
+	unsigned			avg_uA;
+	enum rpm_vreg_state		state;
+};
+
+/**
+ * struct rpm_regulator_platform_data - RPM regulator platform data
+ */
+struct rpm_regulator_platform_data {
+	struct rpm_regulator_init_data	*init_data;
+	int				num_regulators;
+	enum rpm_vreg_version		version;
+	int				vreg_id_vdd_mem;
+	int				vreg_id_vdd_dig;
+};
+
+/**
+ * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
+ */
+enum rpm_vreg_voter {
+	RPM_VREG_VOTER_REG_FRAMEWORK,	/* for internal use only */
+	RPM_VREG_VOTER1,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER2,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER3,		/* for use by other drivers */
+	RPM_VREG_VOTER4,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER5,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER_COUNT,
+};
 
 /**
  * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
@@ -44,8 +156,8 @@
  * This function may only be called for regulators which have the sleep flag
  * specified in their private data.
  */
-int rpm_vreg_set_voltage(enum rpm_vreg_id vreg_id, enum rpm_vreg_voter voter,
-			 int min_uV, int max_uV, int sleep_also);
+int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
+			 int max_uV, int sleep_also);
 
 /**
  * rpm_vreg_set_frequency - sets the frequency of a switching regulator
@@ -54,6 +166,6 @@
  *
  * Returns 0 on success or errno.
  */
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq);
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq);
 
 #endif
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ea9d246..3d34a30 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -176,6 +176,8 @@
 static DEFINE_MUTEX(xprt_info_list_lock);
 
 DECLARE_COMPLETION(msm_ipc_remote_router_up);
+static DECLARE_COMPLETION(msm_ipc_local_router_up);
+#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
 
 static uint32_t next_port_id;
 static DEFINE_MUTEX(next_port_id_lock);
@@ -2399,8 +2401,16 @@
 	struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
 	struct msm_ipc_router_xprt_work *xprt_work;
 	struct rr_packet *pkt;
+	unsigned long ret;
 
-	BUG_ON(!msm_ipc_router_workqueue);
+	if (!msm_ipc_router_workqueue) {
+		ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
+						  IPC_ROUTER_INIT_TIMEOUT);
+		if (!ret || !msm_ipc_router_workqueue) {
+			pr_err("%s: IPC Router not initialized\n", __func__);
+			return;
+		}
+	}
 
 	switch (event) {
 	case IPC_ROUTER_XPRT_EVENT_OPEN:
@@ -2515,6 +2525,7 @@
 	if (ret < 0)
 		pr_err("%s: Init sockets failed\n", __func__);
 
+	complete_all(&msm_ipc_local_router_up);
 	return ret;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 5987752..997d4b5 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -46,7 +46,14 @@
 
 static struct msm_ipc_router_smd_xprt smd_remote_xprt;
 
+struct msm_ipc_router_smd_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
 static void smd_xprt_read_data(struct work_struct *work);
+static void smd_xprt_open_event(struct work_struct *work);
+static void smd_xprt_close_event(struct work_struct *work);
 static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
 static struct workqueue_struct *smd_xprt_workqueue;
 
@@ -201,8 +208,10 @@
 			D("%s: Allocated rr_packet\n", __func__);
 		}
 
-		if ((pkt_size >= MIN_FRAG_SZ) &&
-		    (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ))
+		if (((pkt_size >= MIN_FRAG_SZ) &&
+		     (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ)) ||
+		    ((pkt_size < MIN_FRAG_SZ) &&
+		     (smd_read_avail(smd_remote_xprt.channel) < pkt_size)))
 			return;
 
 		sz = smd_read_avail(smd_remote_xprt.channel);
@@ -249,9 +258,32 @@
 	}
 }
 
+static void smd_xprt_open_event(struct work_struct *work)
+{
+	struct msm_ipc_router_smd_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_smd_xprt_work, work);
+
+	msm_ipc_router_xprt_notify(xprt_work->xprt,
+				IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of OPEN Event\n", __func__);
+	kfree(xprt_work);
+}
+
+static void smd_xprt_close_event(struct work_struct *work)
+{
+	struct msm_ipc_router_smd_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_smd_xprt_work, work);
+
+	msm_ipc_router_xprt_notify(xprt_work->xprt,
+				IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+	kfree(xprt_work);
+}
+
 static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
 {
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt_work *xprt_work;
 
 	switch (event) {
 	case SMD_EVENT_DATA:
@@ -266,9 +298,16 @@
 		spin_lock_irqsave(&modem_reset_lock, flags);
 		modem_reset = 0;
 		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
-					IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
-		D("%s: Notified IPC Router of OPEN Event\n", __func__);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
+				    GFP_ATOMIC);
+		if (!xprt_work) {
+			pr_err("%s: Couldn't notify %d event to IPC Router\n",
+				__func__, event);
+			return;
+		}
+		xprt_work->xprt = &smd_remote_xprt.xprt;
+		INIT_WORK(&xprt_work->work, smd_xprt_open_event);
+		queue_work(smd_xprt_workqueue, &xprt_work->work);
 		break;
 
 	case SMD_EVENT_CLOSE:
@@ -276,9 +315,16 @@
 		modem_reset = 1;
 		spin_unlock_irqrestore(&modem_reset_lock, flags);
 		wake_up(&write_avail_wait_q);
-		msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
-					IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
-		D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
+				    GFP_ATOMIC);
+		if (!xprt_work) {
+			pr_err("%s: Couldn't notify %d event to IPC Router\n",
+				__func__, event);
+			return;
+		}
+		xprt_work->xprt = &smd_remote_xprt.xprt;
+		INIT_WORK(&xprt_work->work, smd_xprt_close_event);
+		queue_work(smd_xprt_workqueue, &xprt_work->work);
 		break;
 	}
 }
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 014ea99..d8323e3 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -620,7 +620,7 @@
 	struct msm_bus_fabric_registration *pdata;
 
 	fabric = kzalloc(sizeof(struct msm_bus_fabric), GFP_KERNEL);
-	if (ZERO_OR_NULL_PTR(fabric)) {
+	if (!fabric) {
 		MSM_BUS_ERR("Fabric alloc failed\n");
 		return -ENOMEM;
 	}
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index b622e74..bcb777f 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -505,6 +505,10 @@
 	} else {
 		pr_debug("%s: ppss_wdog not supported.\n", __func__);
 	}
+
+	if (drv->pdata->init)
+		drv->pdata->init(drv->pdata);
+
 	return 0;
 
 request_irq_err:
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index c517178..8a9ac36 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -39,7 +39,7 @@
 static void __iomem *msm_tmr0_base;
 
 /* Watchdog pet interval in ms */
-#define PET_DELAY 3000
+#define PET_DELAY 10000
 static unsigned long delay_time;
 static unsigned long long last_pet;
 
@@ -317,11 +317,11 @@
 
 	/* 32768 ticks = 1 second */
 	if (machine_is_msm8960_sim()) {
-		__raw_writel(32768*8, msm_tmr0_base + WDT0_BARK_TIME);
-		__raw_writel(32768*10, msm_tmr0_base + WDT0_BITE_TIME);
+		__raw_writel(32768*15, msm_tmr0_base + WDT0_BARK_TIME);
+		__raw_writel(32768*17, msm_tmr0_base + WDT0_BITE_TIME);
 	} else {
-		__raw_writel(32768*4, msm_tmr0_base + WDT0_BARK_TIME);
-		__raw_writel(32768*5, msm_tmr0_base + WDT0_BITE_TIME);
+		__raw_writel(32768*11, msm_tmr0_base + WDT0_BARK_TIME);
+		__raw_writel(32768*12, msm_tmr0_base + WDT0_BITE_TIME);
 	}
 
 	ret = register_pm_notifier(&msm_watchdog_power_notifier);
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index 7357432..097d9d7 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -9,8 +9,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#ifndef __MACH_PERIPHERAL_LOADER_H
-#define __MACH_PERIPHERAL_LOADER_H
+#ifndef __MSM_PERIPHERAL_LOADER_H
+#define __MSM_PERIPHERAL_LOADER_H
 
 #include <linux/list.h>
 #include <linux/mutex.h>
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 84e798a..3f40a12 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -27,8 +27,6 @@
 #include "pm.h"
 #include "scm-boot.h"
 
-#define SECONDARY_CPU_WAIT_MS 10
-
 int pen_release = -1;
 
 /* Initialize the present map (cpu_set(i, cpu_present_map)). */
@@ -138,8 +136,8 @@
 	while (pen_release != 0xFFFFFFFF) {
 		dmac_inv_range((void *)&pen_release,
 			       (void *)(&pen_release+sizeof(pen_release)));
-		msleep_interruptible(1);
-		if (cnt++ >= SECONDARY_CPU_WAIT_MS)
+		usleep(500);
+		if (cnt++ >= 10)
 			break;
 	}
 
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index c86fe87..a929659 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1173,7 +1173,7 @@
 		init_completion(&dev->cpu_killed);
 #endif
 	}
-
+#ifdef CONFIG_MSM_SCM
 	ret = scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry),
 			SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1);
 	if (ret) {
@@ -1181,6 +1181,7 @@
 			__func__, ret);
 		return ret;
 	}
+#endif
 
 #ifdef CONFIG_MSM_IDLE_STATS
 	for_each_possible_cpu(cpu) {
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
index d1a4fe0..401c759 100644
--- a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -54,6 +54,26 @@
 #define SNDDEV_GPIO_MIC1_ANCL_SEL 295
 #define SNDDEV_GPIO_HS_MIC4_SEL 296
 
+#define DSP_RAM_BASE_8x60 0x46700000
+#define DSP_RAM_SIZE_8x60 0x2000000
+static int dspcrashd_pdata_8x60 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8x60[] = {
+	{
+		.name   = "msm_dspcrashd",
+		.start  = DSP_RAM_BASE_8x60,
+		.end    = DSP_RAM_BASE_8x60 + DSP_RAM_SIZE_8x60,
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_dspcrashd_8x60 = {
+	.name           = "msm_dspcrashd",
+	.num_resources  = ARRAY_SIZE(resources_dspcrashd_8x60),
+	.resource       = resources_dspcrashd_8x60,
+	.dev = { .platform_data = &dspcrashd_pdata_8x60 },
+};
+
 static struct resource msm_cdcclk_ctl_resources[] = {
 	{
 		.name   = "msm_snddev_tx_mclk",
@@ -2571,6 +2591,7 @@
 	&msm_cdcclk_ctl_device,
 	&msm_mi2s_device,
 	&msm_uplink_rx_device,
+	&msm_device_dspcrashd_8x60,
 };
 
 #ifdef CONFIG_MSM8X60_FTM_AUDIO_DEVICES
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
index 4382c23..1d8195e 100644
--- a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
 #include <asm/atomic.h>
 
 #include "../proc_comm.h"
@@ -57,8 +58,6 @@
 	}
 	if (cb_ptr)
 		cb_ptr(DSP_STATE_CRASH_DUMP_DONE);
-
-	BUG();
 }
 
 static int dsp_open(struct inode *inode, struct file *file)
@@ -125,10 +124,9 @@
 	return count;
 }
 
-#define DSP_RAM_BASE 0x46700000
-#define DSP_RAM_SIZE 0x2000000
-
 static unsigned copy_ok_count;
+static uint32_t dsp_ram_size;
+static uint32_t dsp_ram_base;
 
 static ssize_t dsp_read(struct file *file, char __user *buf,
 			size_t count, loff_t *pos)
@@ -140,13 +138,20 @@
 	unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
 	struct msm_mapped_buffer *mem_buffer;
 
-	if (*pos >= DSP_RAM_SIZE)
+	if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
+		pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
+			   " size = 0x%x\n", __MM_FILE__,
+				__func__, dsp_ram_base, dsp_ram_size);
+		return -EINVAL;
+	}
+
+	if (*pos >= dsp_ram_size)
 		return 0;
 
 	if (*pos & (PAGE_SIZE - 1))
 		return -EINVAL;
 
-	addr = (*pos + DSP_RAM_BASE);
+	addr = (*pos + dsp_ram_base);
 
 	/* don't blow up if we're unaligned */
 	if (addr & (PAGE_SIZE - 1))
@@ -200,6 +205,28 @@
 	return 0;
 }
 
+static int dspcrashd_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+	int *pdata;
+
+	pdata = pdev->dev.platform_data;
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+						"msm_dspcrashd");
+	if (!res) {
+		pr_err("%s: failed to get resources for dspcrashd\n", __func__);
+		return -ENODEV;
+	}
+
+	dsp_ram_base = res->start;
+	dsp_ram_size = res->end - res->start;
+	pr_info("%s: Platform driver values: Base = 0x%x, Size = 0x%x,"
+		 "pdata = 0x%x\n", __func__,
+		dsp_ram_base, dsp_ram_size, *pdata);
+	return rc;
+}
+
 static const struct file_operations dsp_fops = {
 	.owner		= THIS_MODULE,
 	.open		= dsp_open,
@@ -214,11 +241,27 @@
 	.fops	= &dsp_fops,
 };
 
+static struct platform_driver dspcrashd_driver = {
+	.probe = dspcrashd_probe,
+	.driver = { .name = "msm_dspcrashd"}
+};
 
 static int __init dsp_init(void)
 {
+	int rc = 0;
 	init_waitqueue_head(&dsp_wait);
+	rc = platform_driver_register(&dspcrashd_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for dspcrashd failed\n",
+			__func__);
+	}
 	return misc_register(&dsp_misc);
 }
 
+static int __exit dsp_exit(void)
+{
+	platform_driver_unregister(&dspcrashd_driver);
+	return 0;
+}
+
 device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_out.c b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
index b8521f6..75975cc 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_out.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
@@ -52,7 +52,6 @@
 	atomic_t out_stopped;
 	atomic_t out_prefill;
 	struct wake_lock wakelock;
-	struct wake_lock idlelock;
 };
 
 void pcm_out_cb(uint32_t opcode, uint32_t token,
@@ -77,14 +76,12 @@
 {
 	pr_debug("%s:\n", __func__);
 	wake_lock(&audio->wakelock);
-	wake_lock(&audio->idlelock);
 }
 
 static void audio_allow_sleep(struct pcm *audio)
 {
 	pr_debug("%s:\n", __func__);
 	wake_unlock(&audio->wakelock);
-	wake_unlock(&audio->idlelock);
 }
 
 static int pcm_out_enable(struct pcm *pcm)
@@ -336,8 +333,6 @@
 	atomic_set(&pcm->out_opened, 1);
 	snprintf(name, sizeof name, "audio_pcm_%x", pcm->ac->session);
 	wake_lock_init(&pcm->wakelock, WAKE_LOCK_SUSPEND, name);
-	snprintf(name, sizeof name, "audio_pcm_idle_%x", pcm->ac->session);
-	wake_lock_init(&pcm->idlelock, WAKE_LOCK_IDLE, name);
 
 	rc = auddev_register_evt_listner(pcm->stream_event,
 					AUDDEV_CLNT_DEC,
@@ -441,7 +436,6 @@
 	q6asm_audio_client_free(pcm->ac);
 	audio_allow_sleep(pcm);
 	wake_lock_destroy(&pcm->wakelock);
-	wake_lock_destroy(&pcm->idlelock);
 	mutex_destroy(&pcm->lock);
 	mutex_destroy(&pcm->write_lock);
 	kfree(pcm);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index 0abc9ff..a1bdcfd 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -374,6 +374,9 @@
 
 	trc = afe_open(icodec->data->copp_id, &afe_config, icodec->sample_rate);
 
+	if (trc < 0)
+		pr_err("%s: afe open failed, trc = %d\n", __func__, trc);
+
 	/* Enable ADIE */
 	if (icodec->adie_path) {
 		adie_codec_proceed_stage(icodec->adie_path,
@@ -665,18 +668,24 @@
 		mutex_lock(&drv->rx_lock);
 		if (drv->rx_active) {
 			mutex_unlock(&drv->rx_lock);
+			pr_err("%s: rx_active is set, return EBUSY\n",
+				__func__);
 			rc = -EBUSY;
 			goto error;
 		}
 		rc = snddev_icodec_open_rx(icodec);
 
 		if (!IS_ERR_VALUE(rc)) {
-			drv->rx_active = 1;
 			if ((icodec->data->dev_vol_type & (
 				SNDDEV_DEV_VOL_DIGITAL |
 				SNDDEV_DEV_VOL_ANALOG)))
 				rc = snddev_icodec_set_device_volume_impl(
 						dev_info, dev_info->dev_volume);
+			if (!IS_ERR_VALUE(rc))
+				drv->rx_active = 1;
+			else
+				pr_err("%s: set_device_volume_impl"
+					" error(rx) = %d\n", __func__, rc);
 		}
 		mutex_unlock(&drv->rx_lock);
 	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
@@ -696,18 +705,24 @@
 		mutex_lock(&drv->tx_lock);
 		if (drv->tx_active) {
 			mutex_unlock(&drv->tx_lock);
+			pr_err("%s: tx_active is set, return EBUSY\n",
+				__func__);
 			rc = -EBUSY;
 			goto error;
 		}
 		rc = snddev_icodec_open_tx(icodec);
 
 		if (!IS_ERR_VALUE(rc)) {
-			drv->tx_active = 1;
 			if ((icodec->data->dev_vol_type & (
 				SNDDEV_DEV_VOL_DIGITAL |
 				SNDDEV_DEV_VOL_ANALOG)))
 				rc = snddev_icodec_set_device_volume_impl(
 						dev_info, dev_info->dev_volume);
+			if (!IS_ERR_VALUE(rc))
+				drv->tx_active = 1;
+			else
+				pr_err("%s: set_device_volume_impl"
+					" error(tx) = %d\n", __func__, rc);
 		}
 		mutex_unlock(&drv->tx_lock);
 	}
@@ -731,12 +746,15 @@
 		mutex_lock(&drv->rx_lock);
 		if (!drv->rx_active) {
 			mutex_unlock(&drv->rx_lock);
+			pr_err("%s: rx_active not set, return\n", __func__);
 			rc = -EPERM;
 			goto error;
 		}
 		rc = snddev_icodec_close_rx(icodec);
 		if (!IS_ERR_VALUE(rc))
 			drv->rx_active = 0;
+		else
+			pr_err("%s: close rx failed, rc = %d\n", __func__, rc);
 		mutex_unlock(&drv->rx_lock);
 	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
 		mutex_lock(&drv->lb_lock);
@@ -746,12 +764,15 @@
 		mutex_lock(&drv->tx_lock);
 		if (!drv->tx_active) {
 			mutex_unlock(&drv->tx_lock);
+			pr_err("%s: tx_active not set, return\n", __func__);
 			rc = -EPERM;
 			goto error;
 		}
 		rc = snddev_icodec_close_tx(icodec);
 		if (!IS_ERR_VALUE(rc))
 			drv->tx_active = 0;
+		else
+			pr_err("%s: close tx failed, rc = %d\n", __func__, rc);
 		mutex_unlock(&drv->tx_lock);
 	}
 
@@ -789,10 +810,12 @@
 
 	icodec = dev_info->private_data;
 	if (adie_codec_freq_supported(icodec->data->profile, rate) != 0) {
+		pr_err("%s: adie_codec_freq_supported() failed\n", __func__);
 		rc = -EINVAL;
 		goto error;
 	} else {
 		if (snddev_icodec_check_freq(rate) != 0) {
+			pr_err("%s: check_freq failed\n", __func__);
 			rc = -EINVAL;
 			goto error;
 		} else
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index d4f7940..16f8a5b 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -12,6 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/err.h>
@@ -20,6 +23,7 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include "qdss.h"
 
@@ -47,6 +51,7 @@
 
 #define BYTES_PER_WORD		4
 #define ETB_SIZE_WORDS		4096
+#define FRAME_SIZE_WORDS	4
 
 #define ETB_LOCK()							\
 do {									\
@@ -132,12 +137,24 @@
 	uint32_t read_data;
 	uint32_t read_ptr;
 	uint32_t write_ptr;
+	uint32_t frame_off;
+	uint32_t frame_endoff;
 
 	ETB_UNLOCK();
 
 	read_ptr = etb_readl(etb, ETB_RAM_READ_POINTER);
 	write_ptr = etb_readl(etb, ETB_RAM_WRITE_POINTER);
 
+	frame_off = write_ptr % FRAME_SIZE_WORDS;
+	frame_endoff = FRAME_SIZE_WORDS - frame_off;
+	if (frame_off) {
+		dev_err(etb.dev, "write_ptr: %lu not aligned to formatter "
+				"frame size\n", (unsigned long)write_ptr);
+		dev_err(etb.dev, "frameoff: %lu, frame_endoff: %lu\n",
+			(unsigned long)frame_off, (unsigned long)frame_endoff);
+		write_ptr += frame_endoff;
+	}
+
 	if ((etb_readl(etb, ETB_STATUS_REG) & BIT(0)) == 0)
 		etb_writel(etb, 0x0, ETB_RAM_READ_POINTER);
 	else
@@ -146,14 +163,20 @@
 	buf_ptr = etb.buf;
 	for (i = 0; i < ETB_SIZE_WORDS; i++) {
 		read_data = etb_readl(etb, ETB_RAM_READ_DATA_REG);
-		*buf_ptr = read_data >> 0;
-		buf_ptr++;
-		*buf_ptr = read_data >> 8;
-		buf_ptr++;
-		*buf_ptr = read_data >> 16;
-		buf_ptr++;
-		*buf_ptr = read_data >> 24;
-		buf_ptr++;
+		*buf_ptr++ = read_data >> 0;
+		*buf_ptr++ = read_data >> 8;
+		*buf_ptr++ = read_data >> 16;
+		*buf_ptr++ = read_data >> 24;
+	}
+
+	if (frame_off) {
+		buf_ptr -= (frame_endoff * BYTES_PER_WORD);
+		for (i = 0; i < frame_endoff; i++) {
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+		}
 	}
 
 	etb_writel(etb, read_ptr, ETB_RAM_READ_POINTER);
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index 9ad407b..290b418 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -12,6 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/err.h>
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-ptm.c
index 28dd171..4e8add7 100644
--- a/arch/arm/mach-msm/qdss-ptm.c
+++ b/arch/arm/mach-msm/qdss-ptm.c
@@ -12,6 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/err.h>
diff --git a/arch/arm/mach-msm/qdss-tpiu.c b/arch/arm/mach-msm/qdss-tpiu.c
index def7467..60a8dd2 100644
--- a/arch/arm/mach-msm/qdss-tpiu.c
+++ b/arch/arm/mach-msm/qdss-tpiu.c
@@ -12,6 +12,8 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/err.h>
@@ -56,7 +58,6 @@
 struct tpiu_ctx {
 	void __iomem	*base;
 	bool		enabled;
-	atomic_t	in_use;
 	struct device	*dev;
 };
 
diff --git a/arch/arm/mach-msm/qdss.h b/arch/arm/mach-msm/qdss.h
index e4e6b0c..a41d7e2 100644
--- a/arch/arm/mach-msm/qdss.h
+++ b/arch/arm/mach-msm/qdss.h
@@ -13,6 +13,8 @@
 #ifndef _ARCH_ARM_MACH_MSM_QDSS_H_
 #define _ARCH_ARM_MACH_MSM_QDSS_H_
 
+#include <linux/bitops.h>
+
 /* Coresight management registers (0xF00-0xFCC) */
 #define CS_ITCTRL		(0xF00)
 #define CS_CLAIMSET		(0xFA0)
diff --git a/arch/arm/mach-msm/rpm-regulator-8660.c b/arch/arm/mach-msm/rpm-regulator-8660.c
new file mode 100644
index 0000000..6c4a9ad
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-8660.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.ip		= REQUEST_MEMBER(0, 0x00FFF000, 12),
+	.fm		= REQUEST_MEMBER(0, 0x03000000, 24),
+	.pc		= REQUEST_MEMBER(0, 0x3C000000, 26),
+	.pf		= REQUEST_MEMBER(0, 0xC0000000, 30),
+	.pd		= REQUEST_MEMBER(1, 0x00000001,  0),
+	.ia		= REQUEST_MEMBER(1, 0x00001FFE,  1),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.ip		= REQUEST_MEMBER(0, 0x00FFF000, 12),
+	.fm		= REQUEST_MEMBER(0, 0x03000000, 24),
+	.pc		= REQUEST_MEMBER(0, 0x3C000000, 26),
+	.pf		= REQUEST_MEMBER(0, 0xC0000000, 30),
+	.pd		= REQUEST_MEMBER(1, 0x00000001,  0),
+	.ia		= REQUEST_MEMBER(1, 0x00001FFE,  1),
+	.freq		= REQUEST_MEMBER(1, 0x001FE000, 13),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x00600000, 21),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000000C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000300,  8),
+};
+
+static struct rpm_vreg_parts ncp_parts = {
+	.request_len	= 1,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.enable_state	= REQUEST_MEMBER(0, 0x00001000, 12),
+	.comp_mode	= REQUEST_MEMBER(0, 0x00002000, 13),
+	.freq		= REQUEST_MEMBER(0, 0x003FC000, 14),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_range ftsmps_ranges[] = {
+	VOLTAGE_RANGE( 350000,  650000, 50000),
+	VOLTAGE_RANGE( 700000, 1400000, 12500),
+	VOLTAGE_RANGE(1500000, 3300000, 50000),
+};
+
+static struct vreg_range ncp_ranges[] = {
+	VOLTAGE_RANGE(1500000, 3050000, 50000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&smps_set_points,
+	&ftsmps_set_points,
+	&ncp_set_points,
+};
+
+#define LDO(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_vreg_id, _rpm_id, _name, _name_pc) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define MVS(_vreg_id, _rpm_id, _name, _name_pc) \
+		LVS(_vreg_id, _rpm_id, _name, _name_pc)
+
+#define NCP(_vreg_id, _rpm_id, _name, _name_pc) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_NCP, \
+		.set_points	 = &ncp_set_points, \
+		.part		 = &ncp_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(PM8058_L0,   LDO0,   "8058_l0",   "8058_l0_pc",  nldo, LDO_150),
+	LDO(PM8058_L1,   LDO1,   "8058_l1",   "8058_l1_pc",  nldo, LDO_300),
+	LDO(PM8058_L2,   LDO2,   "8058_l2",   "8058_l2_pc",  pldo, LDO_300),
+	LDO(PM8058_L3,   LDO3,   "8058_l3",   "8058_l3_pc",  pldo, LDO_150),
+	LDO(PM8058_L4,   LDO4,   "8058_l4",   "8058_l4_pc",  pldo, LDO_50),
+	LDO(PM8058_L5,   LDO5,   "8058_l5",   "8058_l5_pc",  pldo, LDO_300),
+	LDO(PM8058_L6,   LDO6,   "8058_l6",   "8058_l6_pc",  pldo, LDO_50),
+	LDO(PM8058_L7,   LDO7,   "8058_l7",   "8058_l7_pc",  pldo, LDO_50),
+	LDO(PM8058_L8,   LDO8,   "8058_l8",   "8058_l8_pc",  pldo, LDO_300),
+	LDO(PM8058_L9,   LDO9,   "8058_l9",   "8058_l9_pc",  pldo, LDO_300),
+	LDO(PM8058_L10,  LDO10,  "8058_l10",  "8058_l10_pc", pldo, LDO_300),
+	LDO(PM8058_L11,  LDO11,  "8058_l11",  "8058_l11_pc", pldo, LDO_150),
+	LDO(PM8058_L12,  LDO12,  "8058_l12",  "8058_l12_pc", pldo, LDO_150),
+	LDO(PM8058_L13,  LDO13,  "8058_l13",  "8058_l13_pc", pldo, LDO_300),
+	LDO(PM8058_L14,  LDO14,  "8058_l14",  "8058_l14_pc", pldo, LDO_300),
+	LDO(PM8058_L15,  LDO15,  "8058_l15",  "8058_l15_pc", pldo, LDO_300),
+	LDO(PM8058_L16,  LDO16,  "8058_l16",  "8058_l16_pc", pldo, LDO_300),
+	LDO(PM8058_L17,  LDO17,  "8058_l17",  "8058_l17_pc", pldo, LDO_150),
+	LDO(PM8058_L18,  LDO18,  "8058_l18",  "8058_l18_pc", pldo, LDO_150),
+	LDO(PM8058_L19,  LDO19,  "8058_l19",  "8058_l19_pc", pldo, LDO_150),
+	LDO(PM8058_L20,  LDO20,  "8058_l20",  "8058_l20_pc", pldo, LDO_150),
+	LDO(PM8058_L21,  LDO21,  "8058_l21",  "8058_l21_pc", nldo, LDO_150),
+	LDO(PM8058_L22,  LDO22,  "8058_l22",  "8058_l22_pc", nldo, LDO_300),
+	LDO(PM8058_L23,  LDO23,  "8058_l23",  "8058_l23_pc", nldo, LDO_300),
+	LDO(PM8058_L24,  LDO24,  "8058_l24",  "8058_l24_pc", nldo, LDO_150),
+	LDO(PM8058_L25,  LDO25,  "8058_l25",  "8058_l25_pc", nldo, LDO_150),
+
+	SMPS(PM8058_S0,  SMPS0,  "8058_s0",   "8058_s0_pc",  smps, SMPS),
+	SMPS(PM8058_S1,  SMPS1,  "8058_s1",   "8058_s1_pc",  smps, SMPS),
+	SMPS(PM8058_S2,  SMPS2,  "8058_s2",   "8058_s2_pc",  smps, SMPS),
+	SMPS(PM8058_S3,  SMPS3,  "8058_s3",   "8058_s3_pc",  smps, SMPS),
+	SMPS(PM8058_S4,  SMPS4,  "8058_s4",   "8058_s4_pc",  smps, SMPS),
+
+	LVS(PM8058_LVS0, LVS0,   "8058_lvs0", "8058_lvs0_pc"),
+	LVS(PM8058_LVS1, LVS1,   "8058_lvs1", "8058_lvs1_pc"),
+
+	NCP(PM8058_NCP,  NCP,    "8058_ncp",  NULL),
+
+	LDO(PM8901_L0,   LDO0B,  "8901_l0",   "8901_l0_pc",  nldo, LDO_300),
+	LDO(PM8901_L1,   LDO1B,  "8901_l1",   "8901_l1_pc",  pldo, LDO_300),
+	LDO(PM8901_L2,   LDO2B,  "8901_l2",   "8901_l2_pc",  pldo, LDO_300),
+	LDO(PM8901_L3,   LDO3B,  "8901_l3",   "8901_l3_pc",  pldo, LDO_300),
+	LDO(PM8901_L4,   LDO4B,  "8901_l4",   "8901_l4_pc",  pldo, LDO_300),
+	LDO(PM8901_L5,   LDO5B,  "8901_l5",   "8901_l5_pc",  pldo, LDO_300),
+	LDO(PM8901_L6,   LDO6B,  "8901_l6",   "8901_l6_pc",  pldo, LDO_300),
+
+	SMPS(PM8901_S0,  SMPS0B, "8901_s0",   "8901_s0_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S1,  SMPS1B, "8901_s1",   "8901_s1_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S2,  SMPS2B, "8901_s2",   "8901_s2_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S3,  SMPS3B, "8901_s3",   "8901_s3_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S4,  SMPS4B, "8901_s4",   "8901_s4_pc", ftsmps, FTSMPS),
+
+	LVS(PM8901_LVS0, LVS0B,  "8901_lvs0", "8901_lvs0_pc"),
+	LVS(PM8901_LVS1, LVS1B,  "8901_lvs1", "8901_lvs1_pc"),
+	LVS(PM8901_LVS2, LVS2B,  "8901_lvs2", "8901_lvs2_pc"),
+	LVS(PM8901_LVS3, LVS3B,  "8901_lvs3", "8901_lvs3_pc"),
+
+	MVS(PM8901_MVS0, MVS,    "8901_mvs0", "8901_mvs0_pc"),
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_8660_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_8660_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_8660_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_8660_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_8660_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_8660_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_8660_HPM]		= "HPM",
+};
+
+static const char *pin_control_label[] = {
+	" A0",
+	" A1",
+	" D0",
+	" D1",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_8660_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id;
+
+	if (id >= RPM_VREG_ID_PM8058_L0_PC && id <= RPM_VREG_ID_PM8058_LVS1_PC)
+		real_id = id - RPM_VREG_ID_PM8058_L0_PC + RPM_VREG_ID_PM8058_L0;
+	else
+		real_id = id - RPM_VREG_ID_PM8901_L0_PC + RPM_VREG_ID_PM8901_L0;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs				= vregs,
+	.vregs_len			= ARRAY_SIZE(vregs),
+
+	.vreg_id_min			= RPM_VREG_ID_PM8058_L0,
+	.vreg_id_max			= RPM_VREG_ID_8660_MAX,
+
+	.pin_func_none			= RPM_VREG_PIN_FN_8660_NONE,
+	.pin_func_sleep_b		= RPM_VREG_PIN_FN_8660_SLEEP_B,
+
+	.mode_lpm			= REGULATOR_MODE_IDLE,
+	.mode_hpm			= REGULATOR_MODE_NORMAL,
+
+	.set_points			= all_set_points,
+	.set_points_len			= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl			= pin_control_label,
+	.label_pin_ctrl_len		= ARRAY_SIZE(pin_control_label),
+	.label_pin_func			= pin_func_label,
+	.label_pin_func_len		= ARRAY_SIZE(pin_func_label),
+	.label_force_mode		= force_mode_label,
+	.label_force_mode_len		= ARRAY_SIZE(force_mode_label),
+
+	.is_real_id			= is_real_id,
+	.pc_id_to_real_id		= pc_id_to_real_id,
+
+	.use_legacy_optimum_mode	= 1,
+	.ia_follows_ip			= 1,
+};
+
+struct vreg_config *get_config_8660(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 52cc77d..8726ed4 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -13,84 +13,10 @@
 
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <mach/rpm.h>
-#include <mach/rpm-regulator.h>
-#include <mach/socinfo.h>
+#include "rpm-regulator-private.h"
 
-#include "rpm_resources.h"
-
-/* Debug Definitions */
-
-enum {
-	MSM_RPM_VREG_DEBUG_REQUEST = BIT(0),
-	MSM_RPM_VREG_DEBUG_VOTE = BIT(1),
-	MSM_RPM_VREG_DEBUG_DUPLICATE = BIT(2),
-	MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG = BIT(3),
-};
-
-static int msm_rpm_vreg_debug_mask;
-module_param_named(
-	debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
-);
-
-#define REGULATOR_TYPE_LDO			0
-#define REGULATOR_TYPE_SMPS			1
-#define REGULATOR_TYPE_VS			2
-#define REGULATOR_TYPE_NCP			3
-
-#define MICRO_TO_MILLI(uV)			((uV) / 1000)
-#define MILLI_TO_MICRO(mV)			((mV) * 1000)
-
-#define SET_PART(_vreg, _part, _val) \
-	_vreg->req[_vreg->part->_part.word].value \
-		= (_vreg->req[_vreg->part->_part.word].value \
-			& ~vreg->part->_part.mask) \
-		| (((_val) << vreg->part->_part.shift) & vreg->part->_part.mask)
-
-#define GET_PART(_vreg, _part) \
-	((_vreg->req[_vreg->part->_part.word].value & vreg->part->_part.mask) \
-		>> vreg->part->_part.shift)
-
-struct request_member {
-	int			word;
-	unsigned int		mask;
-	int			shift;
-};
-
-struct rpm_vreg_parts {
-	struct request_member	mV;	/* voltage: used if voltage is in mV */
-	struct request_member	uV;	/* voltage: used if voltage is in uV */
-	struct request_member	ip;		/* peak current in mA */
-	struct request_member	pd;		/* pull down enable */
-	struct request_member	ia;		/* average current in mA */
-	struct request_member	fm;		/* force mode */
-	struct request_member	pm;		/* power mode */
-	struct request_member	pc;		/* pin control */
-	struct request_member	pf;		/* pin function */
-	struct request_member	enable_state;	/* NCP and switch */
-	struct request_member	comp_mode;	/* NCP */
-	struct request_member	freq;		/* frequency: NCP and SMPS */
-	struct request_member	freq_clk_src;	/* clock source: SMPS */
-	struct request_member	hpm;		/* switch: control OCP ans SS */
-	int			request_len;
-};
-
-#define REQUEST_MEMBER(_word, _mask, _shift) \
-	{ \
-		.word	= _word, \
-		.mask	= _mask, \
-		.shift	= _shift, \
-	}
-
-struct rpm_vreg_parts ldo_parts = {
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
 	.request_len	= 2,
 	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
 	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
@@ -101,7 +27,7 @@
 	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
 };
 
-struct rpm_vreg_parts smps_parts = {
+static struct rpm_vreg_parts smps_parts = {
 	.request_len	= 2,
 	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
 	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
@@ -115,7 +41,7 @@
 	.freq_clk_src	= REQUEST_MEMBER(1, 0x60000000, 29),
 };
 
-struct rpm_vreg_parts switch_parts = {
+static struct rpm_vreg_parts switch_parts = {
 	.request_len	= 1,
 	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
 	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
@@ -124,7 +50,7 @@
 	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
 };
 
-struct rpm_vreg_parts ncp_parts = {
+static struct rpm_vreg_parts ncp_parts = {
 	.request_len	= 1,
 	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
 	.enable_state	= REQUEST_MEMBER(0, 0x00800000, 23),
@@ -132,26 +58,7 @@
 	.freq		= REQUEST_MEMBER(0, 0x3E000000, 25),
 };
 
-struct vreg_range {
-	int			min_uV;
-	int			max_uV;
-	int			step_uV;
-	unsigned		n_voltages;
-};
-
-struct vreg_set_points {
-	struct vreg_range	*range;
-	int			count;
-	unsigned		n_voltages;
-};
-
-#define VOLTAGE_RANGE(_min_uV, _max_uV, _step_uV) \
-	{ \
-		.min_uV  = _min_uV, \
-		.max_uV  = _max_uV, \
-		.step_uV = _step_uV, \
-	}
-
+/* Physically available PMIC regulator voltage setpoint ranges */
 static struct vreg_range pldo_ranges[] = {
 	VOLTAGE_RANGE( 750000, 1487500, 12500),
 	VOLTAGE_RANGE(1500000, 3075000, 25000),
@@ -183,12 +90,6 @@
 	VOLTAGE_RANGE(1500000, 3050000, 50000),
 };
 
-#define SET_POINTS(_ranges) \
-{ \
-	.range	= _ranges, \
-	.count	= ARRAY_SIZE(_ranges), \
-};
-
 static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
 static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
 static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
@@ -196,1217 +97,164 @@
 static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
 static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
 
-/*
- * This is used when voting for LPM or HPM by subtracting or adding to the
- * hpm_min_load of a regulator.  It has units of uA.
- */
-#define LOAD_THRESHOLD_STEP			1000
-
-/* This is the maximum uA load that can be passed to the RPM. */
-#define MAX_POSSIBLE_LOAD			(MILLI_TO_MICRO(0xFFF))
-
-struct vreg {
-	struct msm_rpm_iv_pair		req[2];
-	struct msm_rpm_iv_pair		prev_active_req[2];
-	struct msm_rpm_iv_pair		prev_sleep_req[2];
-	struct rpm_regulator_init_data	pdata;
-	struct regulator_dev		*rdev;
-	struct regulator_dev		*rdev_pc;
-	const char			*name;
-	struct vreg_set_points		*set_points;
-	struct rpm_vreg_parts		*part;
-	int				type;
-	enum rpm_vreg_id		id;
-	struct mutex			pc_lock;
-	int				save_uV;
-	int				mode;
-	bool				is_enabled;
-	bool				is_enabled_pc;
-	const int			hpm_min_load;
-	int			       active_min_uV_vote[RPM_VREG_VOTER_COUNT];
-	int				sleep_min_uV_vote[RPM_VREG_VOTER_COUNT];
-
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&nldo1200_set_points,
+	&smps_set_points,
+	&ftsmps_set_points,
+	&ncp_set_points,
 };
 
-#define LDO(_id, _ranges, _hpm_min_load) \
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
 	[RPM_VREG_ID_PM8921_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
 			[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
 		}, \
-		.hpm_min_load	 = RPM_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-		.type		 = REGULATOR_TYPE_LDO, \
+		.hpm_min_load  = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &ldo_parts, \
 		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
 	}
 
-#define SMPS(_id, _ranges, _hpm_min_load) \
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
 	[RPM_VREG_ID_PM8921_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
 			[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
 		}, \
-		.hpm_min_load	 = RPM_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-		.type		 = REGULATOR_TYPE_SMPS, \
+		.hpm_min_load  = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &smps_parts, \
 		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
 	}
 
-#define LVS(_id) \
+#define LVS(_id, _name, _name_pc) \
 	[RPM_VREG_ID_PM8921_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8921_##_id, }, \
 			[1] = { .id = -1, }, \
 		}, \
-		.type		 = REGULATOR_TYPE_VS, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
 		.part		 = &switch_parts, \
 		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
 	}
 
-#define MVS(_vreg_id, _rpm_id) \
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
 	[RPM_VREG_ID_PM8921_##_vreg_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
 			[1] = { .id = -1, }, \
 		}, \
-		.type		 = REGULATOR_TYPE_VS, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
 		.part		 = &switch_parts, \
 		.id		 = RPM_VREG_ID_PM8921_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
 	}
 
-#define NCP(_id) \
+#define NCP(_id, _name, _name_pc) \
 	[RPM_VREG_ID_PM8921_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_##_id##_0, }, \
 			[1] = { .id = MSM_RPM_ID_##_id##_1, }, \
 		}, \
-		.type		 = REGULATOR_TYPE_NCP, \
+		.type		 = RPM_REGULATOR_TYPE_NCP, \
 		.set_points	 = &ncp_set_points, \
 		.part		 = &ncp_parts, \
 		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
 	}
 
 static struct vreg vregs[] = {
-	LDO(L1,  nldo,     LDO_150),
-	LDO(L2,  nldo,     LDO_150),
-	LDO(L3 , pldo,     LDO_150),
-	LDO(L4,  pldo,     LDO_50),
-	LDO(L5,  pldo,     LDO_300),
-	LDO(L6,  pldo,     LDO_600),
-	LDO(L7,  pldo,     LDO_150),
-	LDO(L8,  pldo,     LDO_300),
-	LDO(L9,  pldo,     LDO_300),
-	LDO(L10, pldo,     LDO_600),
-	LDO(L11, pldo,     LDO_150),
-	LDO(L12, nldo,     LDO_150),
-	LDO(L14, pldo,     LDO_50),
-	LDO(L15, pldo,     LDO_150),
-	LDO(L16, pldo,     LDO_300),
-	LDO(L17, pldo,     LDO_150),
-	LDO(L18, nldo,     LDO_150),
-	LDO(L21, pldo,     LDO_150),
-	LDO(L22, pldo,     LDO_150),
-	LDO(L23, pldo,     LDO_150),
-	LDO(L24, nldo1200, LDO_1200),
-	LDO(L25, nldo1200, LDO_1200),
-	LDO(L26, nldo1200, LDO_1200),
-	LDO(L27, nldo1200, LDO_1200),
-	LDO(L28, nldo1200, LDO_1200),
-	LDO(L29, pldo,     LDO_150),
+	LDO(L1,   "8921_l1",   "8921_l1_pc",  nldo,     LDO_150),
+	LDO(L2,   "8921_l2",   "8921_l2_pc",  nldo,     LDO_150),
+	LDO(L3,   "8921_l3",   "8921_l3_pc",  pldo,     LDO_150),
+	LDO(L4,   "8921_l4",   "8921_l4_pc",  pldo,     LDO_50),
+	LDO(L5,   "8921_l5",   "8921_l5_pc",  pldo,     LDO_300),
+	LDO(L6,   "8921_l6",   "8921_l6_pc",  pldo,     LDO_600),
+	LDO(L7,   "8921_l7",   "8921_l7_pc",  pldo,     LDO_150),
+	LDO(L8,   "8921_l8",   "8921_l8_pc",  pldo,     LDO_300),
+	LDO(L9,   "8921_l9",   "8921_l9_pc",  pldo,     LDO_300),
+	LDO(L10,  "8921_l10",  "8921_l10_pc", pldo,     LDO_600),
+	LDO(L11,  "8921_l11",  "8921_l11_pc", pldo,     LDO_150),
+	LDO(L12,  "8921_l12",  "8921_l12_pc", nldo,     LDO_150),
+	LDO(L14,  "8921_l14",  "8921_l14_pc", pldo,     LDO_50),
+	LDO(L15,  "8921_l15",  "8921_l15_pc", pldo,     LDO_150),
+	LDO(L16,  "8921_l16",  "8921_l16_pc", pldo,     LDO_300),
+	LDO(L17,  "8921_l17",  "8921_l17_pc", pldo,     LDO_150),
+	LDO(L18,  "8921_l18",  "8921_l18_pc", nldo,     LDO_150),
+	LDO(L21,  "8921_l21",  "8921_l21_pc", pldo,     LDO_150),
+	LDO(L22,  "8921_l22",  "8921_l22_pc", pldo,     LDO_150),
+	LDO(L23,  "8921_l23",  "8921_l23_pc", pldo,     LDO_150),
+	LDO(L24,  "8921_l24",  NULL,          nldo1200, LDO_1200),
+	LDO(L25,  "8921_l25",  NULL,          nldo1200, LDO_1200),
+	LDO(L26,  "8921_l26",  NULL,          nldo1200, LDO_1200),
+	LDO(L27,  "8921_l27",  NULL,          nldo1200, LDO_1200),
+	LDO(L28,  "8921_l28",  NULL,          nldo1200, LDO_1200),
+	LDO(L29,  "8921_l29",  "8921_l29_pc", pldo,     LDO_150),
 
-	SMPS(S1, smps,     SMPS_1500),
-	SMPS(S2, smps,     SMPS_1500),
-	SMPS(S3, smps,     SMPS_1500),
-	SMPS(S4, smps,     SMPS_1500),
-	SMPS(S5, ftsmps,   SMPS_2000),
-	SMPS(S6, ftsmps,   SMPS_2000),
-	SMPS(S7, smps,     SMPS_1500),
-	SMPS(S8, smps,     SMPS_1500),
+	SMPS(S1,  "8921_s1",   "8921_s1_pc",  smps,     SMPS_1500),
+	SMPS(S2,  "8921_s2",   "8921_s2_pc",  smps,     SMPS_1500),
+	SMPS(S3,  "8921_s3",   "8921_s3_pc",  smps,     SMPS_1500),
+	SMPS(S4,  "8921_s4",   "8921_s4_pc",  smps,     SMPS_1500),
+	SMPS(S5,  "8921_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(S6,  "8921_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(S7,  "8921_s7",   "8921_s7_pc",  smps,     SMPS_1500),
+	SMPS(S8,  "8921_s8",   "8921_s8_pc",  smps,     SMPS_1500),
 
-	LVS(LVS1),
-	LVS(LVS2),
-	LVS(LVS3),
-	LVS(LVS4),
-	LVS(LVS5),
-	LVS(LVS6),
-	LVS(LVS7),
-	MVS(USB_OTG, USB_OTG_SWITCH),
-	MVS(HDMI_MVS, HDMI_SWITCH),
+	LVS(LVS1, "8921_lvs1", "8921_lvs1_pc"),
+	LVS(LVS2, "8921_lvs2", NULL),
+	LVS(LVS3, "8921_lvs3", "8921_lvs3_pc"),
+	LVS(LVS4, "8921_lvs4", "8921_lvs4_pc"),
+	LVS(LVS5, "8921_lvs5", "8921_lvs5_pc"),
+	LVS(LVS6, "8921_lvs6", "8921_lvs6_pc"),
+	LVS(LVS7, "8921_lvs7", "8921_lvs7_pc"),
+	MVS(USB_OTG,  "8921_usb_otg",  NULL, USB_OTG_SWITCH),
+	MVS(HDMI_MVS, "8921_hdmi_mvs", NULL, HDMI_SWITCH),
 
-	NCP(NCP),
+	NCP(NCP,  "8921_ncp",  NULL),
 };
 
-#define vreg_err(vreg, fmt, ...) \
-	pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define VREG_ID_IS_VDD_MEM_OR_DIG(id) \
-	((id == RPM_VREG_ID_PM8921_L24) || (id == RPM_VREG_ID_PM8921_S3))
-
-const char *pin_func_label[] = {
-	[RPM_VREG_PIN_FN_DONT_CARE]		= "don't care",
-	[RPM_VREG_PIN_FN_ENABLE]		= "on/off",
-	[RPM_VREG_PIN_FN_MODE]			= "HPM/LPM",
-	[RPM_VREG_PIN_FN_SLEEP_B]		= "sleep_b",
-	[RPM_VREG_PIN_FN_NONE]			= "none",
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_8960_DONT_CARE]	= "don't care",
+	[RPM_VREG_PIN_FN_8960_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_8960_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_8960_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_8960_NONE]		= "none",
 };
 
-const char *force_mode_label[] = {
-	[RPM_VREG_FORCE_MODE_NONE]		= "none",
-	[RPM_VREG_FORCE_MODE_LPM]		= "LPM",
-	[RPM_VREG_FORCE_MODE_AUTO]		= "auto",
-	[RPM_VREG_FORCE_MODE_HPM]		= "HPM",
-	[RPM_VREG_FORCE_MODE_BYPASS]		= "BYP",
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_8960_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_8960_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_8960_AUTO]		= "auto",
+	[RPM_VREG_FORCE_MODE_8960_HPM]		= "HPM",
+	[RPM_VREG_FORCE_MODE_8960_BYPASS]	= "BYP",
 };
 
-const char *power_mode_label[] = {
-	[RPM_VREG_POWER_MODE_HYSTERETIC]	= "HYS",
-	[RPM_VREG_POWER_MODE_PWM]		= "PWM",
+static const char *power_mode_label[] = {
+	[RPM_VREG_POWER_MODE_8960_HYSTERETIC]	= "HYS",
+	[RPM_VREG_POWER_MODE_8960_PWM]		= "PWM",
 };
 
-static void rpm_regulator_req(struct vreg *vreg, int set)
-{
-	int uV, ip, fm, pm, pc, pf, pd, ia, freq, clk, state, hpm, comp_mode;
-	const char *pf_label = "", *fm_label = "", *pc_total = "";
-	const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
-	const char *pm_label = "";
-
-	/* Suppress VDD_MEM and VDD_DIG printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
-	    && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
-		return;
-
-	if (vreg->part->uV.mask)
-		uV = GET_PART(vreg, uV);
-	else
-		uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
-
-	ip = GET_PART(vreg, ip);
-	fm = GET_PART(vreg, fm);
-	pm = GET_PART(vreg, pm);
-	pc = GET_PART(vreg, pc);
-	pf = GET_PART(vreg, pf);
-	pd = GET_PART(vreg, pd);
-	ia = GET_PART(vreg, ia);
-	freq = GET_PART(vreg, freq);
-	clk = GET_PART(vreg, freq_clk_src);
-	state = GET_PART(vreg, enable_state);
-	hpm = GET_PART(vreg, hpm);
-	comp_mode = GET_PART(vreg, comp_mode);
-
-	if (pf >= 0 && pf < ARRAY_SIZE(pin_func_label))
-		pf_label = pin_func_label[pf];
-
-	if (fm >= 0 && fm < ARRAY_SIZE(force_mode_label))
-		fm_label = force_mode_label[fm];
-
-	if (pm >= 0 && pm < ARRAY_SIZE(power_mode_label))
-		pm_label = power_mode_label[pm];
-
-	if (pc & RPM_VREG_PIN_CTRL_EN0)
-		pc_en0 = " D1";
-	if (pc & RPM_VREG_PIN_CTRL_EN1)
-		pc_en1 = " A0";
-	if (pc & RPM_VREG_PIN_CTRL_EN2)
-		pc_en2 = " A1";
-	if (pc & RPM_VREG_PIN_CTRL_EN3)
-		pc_en3 = " A2";
-	if (pc == RPM_VREG_PIN_CTRL_NONE)
-		pc_total = " none";
-
-	switch (vreg->type) {
-	case REGULATOR_TYPE_LDO:
-		pr_info("%s %-9s: s=%c, v=%7d uV, ip=%4d mA, fm=%s (%d), "
-			"pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s (%d), "
-			"ia=%4d mA; req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg->name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), uV, ip,
-			fm_label, fm, pc_en0, pc_en1, pc_en2, pc_en3, pc_total,
-			pc, pf_label, pf, (pd == 1 ? "Y" : "N"), pd, ia,
-			vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-		break;
-	case REGULATOR_TYPE_SMPS:
-		pr_info("%s %-9s: s=%c, v=%7d uV, ip=%4d mA, fm=%s (%d), "
-			"pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s (%d), "
-			"ia=%4d mA, freq=%2d, pm=%s (%d), clk_src=%d; "
-			"req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg->name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), uV, ip,
-			fm_label, fm, pc_en0, pc_en1, pc_en2, pc_en3, pc_total,
-			pc, pf_label, pf, (pd == 1 ? "Y" : "N"), pd, ia, freq,
-			pm_label, pm, clk, vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-		break;
-	case REGULATOR_TYPE_VS:
-		pr_info("%s %-9s: s=%c, state=%s (%d), pd=%s (%d), "
-			"pc =%s%s%s%s%s (%d), pf=%s (%d), hpm=%d; "
-			"req[0]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg->name, (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
-			(state == 1 ? "on" : "off"), state,
-			(pd == 1 ? "Y" : "N"), pd, pc_en0, pc_en1, pc_en2,
-			pc_en3, pc_total, pc, pf_label, pf, hpm,
-			vreg->req[0].id, vreg->req[0].value);
-		break;
-	case REGULATOR_TYPE_NCP:
-		pr_info("%s %-9s: s=%c, v=-%7d uV, state=%s (%d), freq=%2d, "
-			"comp=%d; req[0]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg->name, (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
-			uV, (state == 1 ? "on" : "off"), state, freq, comp_mode,
-			vreg->req[0].id, vreg->req[0].value);
-		break;
-	}
-}
-
-static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
-			int set, int voter_uV, int aggregate_uV)
-{
-	/* Suppress VDD_MEM and VDD_DIG printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
-	    && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
-		return;
-
-	pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
-		"v_aggregate=%7d uV\n", vreg->name, voter,
-		(set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
-}
-
-static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
-{
-	/* Suppress VDD_MEM and VDD_DIG printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
-	    && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
-		return;
-
-	if (cnt == 2)
-		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
-			"req[1]={%d, 0x%08X}\n", vreg->name,
-			(set == 0 ? 'A' : 'S'),
-			vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-	else if (cnt == 1)
-		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
-			vreg->name, (set == 0 ? 'A' : 'S'),
-			vreg->req[0].id, vreg->req[0].value);
-}
-
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(pm8921_noirq_lock);
-
-static int voltage_from_req(struct vreg *vreg)
-{
-	int uV = 0;
-
-	if (vreg->part->uV.mask)
-		uV = GET_PART(vreg, uV);
-	else
-		uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
-
-	return uV;
-}
-
-static void voltage_to_req(int uV, struct vreg *vreg)
-{
-	if (vreg->part->uV.mask)
-		SET_PART(vreg, uV, uV);
-	else
-		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
-}
-
-static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
-			  int set, unsigned mask0, unsigned val0,
-			  unsigned mask1, unsigned val1, unsigned cnt,
-			  int update_voltage)
-{
-	struct msm_rpm_iv_pair *prev_req;
-	int rc = 0, max_uV_vote = 0;
-	unsigned prev0, prev1;
-	int *min_uV_vote;
-	int i;
-
-	if (set == MSM_RPM_CTX_SET_0) {
-		min_uV_vote = vreg->active_min_uV_vote;
-		prev_req = vreg->prev_active_req;
-	} else {
-		min_uV_vote = vreg->sleep_min_uV_vote;
-		prev_req = vreg->prev_sleep_req;
-	}
-
-	prev0 = vreg->req[0].value;
-	vreg->req[0].value &= ~mask0;
-	vreg->req[0].value |= val0 & mask0;
-
-	prev1 = vreg->req[1].value;
-	vreg->req[1].value &= ~mask1;
-	vreg->req[1].value |= val1 & mask1;
-
-	if (update_voltage)
-		min_uV_vote[voter] = voltage_from_req(vreg);
-
-	/* Find the highest voltage voted for and use it. */
-	for (i = 0; i < RPM_VREG_VOTER_COUNT; i++)
-		max_uV_vote = max(max_uV_vote, min_uV_vote[i]);
-	voltage_to_req(max_uV_vote, vreg);
-
-	if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
-		rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
-				max_uV_vote);
-
-	/* Ignore duplicate requests */
-	if (vreg->req[0].value != prev_req[0].value ||
-	    vreg->req[1].value != prev_req[1].value) {
-		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
-		if (rc) {
-			vreg->req[0].value = prev0;
-			vreg->req[1].value = prev1;
-
-			vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
-				"set=%s, id=%d, rc=%d\n",
-				(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
-				vreg->req[0].id, rc);
-		} else {
-			/* Only save if nonzero and active set. */
-			if (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
-				vreg->save_uV = max_uV_vote;
-			if (msm_rpm_vreg_debug_mask
-			    & MSM_RPM_VREG_DEBUG_REQUEST)
-				rpm_regulator_req(vreg, set);
-			prev_req[0].value = vreg->req[0].value;
-			prev_req[1].value = vreg->req[1].value;
-		}
-	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
-		rpm_regulator_duplicate(vreg, set, cnt);
-	}
-
-	return rc;
-}
-
-static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
-			  int sleep, unsigned mask0, unsigned val0,
-			  unsigned mask1, unsigned val1, unsigned cnt,
-			  int update_voltage)
-{
-	unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
-	unsigned long flags;
-	int rc;
-
-	if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
-		return -EINVAL;
-
-	spin_lock_irqsave(&pm8921_noirq_lock, flags);
-
-	/*
-	 * Send sleep set request first so that subsequent set_mode, etc calls
-	 * use the voltage from the active set.
-	 */
-	if (sleep)
-		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
-				mask0, val0, mask1, val1, cnt, update_voltage);
-	else {
-		/*
-		 * Vote for 0 V in the sleep set when active set-only is
-		 * specified.  This ensures that a disable vote will be issued
-		 * at some point for the sleep set of the regulator.
-		 */
-		if (vreg->part->uV.mask) {
-			s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
-			s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
-		} else {
-			s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
-			s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
-		}
-
-		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
-				       s_mask[0], s_val[0], s_mask[1], s_val[1],
-				       cnt, update_voltage);
-	}
-
-	rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
-					mask1, val1, cnt, update_voltage);
-
-	spin_unlock_irqrestore(&pm8921_noirq_lock, flags);
-
-	return rc;
-}
-
-/**
- * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
- * @vreg: ID for regulator
- * @voter: ID for the voter
- * @min_uV: minimum acceptable voltage (in uV) that is voted for
- * @max_uV: maximum acceptable voltage (in uV) that is voted for
- * @sleep_also: 0 for active set only, non-0 for active set and sleep set
- *
- * Returns 0 on success or errno.
- *
- * This function is used to vote for the voltage of a regulator without
- * using the regulator framework.  It is needed by consumers which hold spin
- * locks or have interrupts disabled because the regulator framework can sleep.
- * It is also needed by consumers which wish to only vote for active set
- * regulator voltage.
- *
- * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
- *
- * This function may only be called for regulators which have the sleep flag
- * specified in their private data.
- */
-int rpm_vreg_set_voltage(enum rpm_vreg_id vreg_id, enum rpm_vreg_voter voter,
-			 int min_uV, int max_uV, int sleep_also)
-{
-	unsigned int mask[2] = {0}, val[2] = {0};
-	struct vreg_range *range;
-	struct vreg *vreg;
-	int uV = min_uV;
-	int lim_min_uV, lim_max_uV, i, rc;
-
-	if (vreg_id < 0 || vreg_id > RPM_VREG_ID_PM8921_MAX_REAL) {
-		pr_err("invalid regulator id=%d\n", vreg_id);
-		return -EINVAL;
-	}
-
-	/*
-	 * TODO: make this function a no-op for 8064 so that it can be called by
-	 * consumers on 8064 before RPM capabilities are present. (needed for
-	 * acpuclock driver)
-	 */
-	if (cpu_is_apq8064())
-		return 0;
-
-	vreg = &vregs[vreg_id];
-	range = &vreg->set_points->range[0];
-
-	if (!vreg->pdata.sleep_selectable) {
-		vreg_err(vreg, "regulator is not marked sleep selectable\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * Check if request voltage is outside of allowed range. The regulator
-	 * core has already checked that constraint range is inside of the
-	 * physically allowed range.
-	 */
-	lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
-	lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
-
-	if (uV < lim_min_uV && max_uV >= lim_min_uV)
-		uV = lim_min_uV;
-
-	if (uV < lim_min_uV || uV > lim_max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside allowed v=[%d, %d]\n",
-			 min_uV, max_uV, lim_min_uV, lim_max_uV);
-		return -EINVAL;
-	}
-
-	/* Find the range which uV is inside of. */
-	for (i = vreg->set_points->count - 1; i > 0; i--) {
-		if (uV > vreg->set_points->range[i - 1].max_uV) {
-			range = &vreg->set_points->range[i];
-			break;
-		}
-	}
-
-	/*
-	 * Force uV to be an allowed set point and apply a ceiling function
-	 * to non-set point values.
-	 */
-	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
-	uV = uV * range->step_uV + range->min_uV;
-
-	if (vreg->part->uV.mask) {
-		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
-		mask[vreg->part->uV.word] = vreg->part->uV.mask;
-	} else {
-		val[vreg->part->mV.word]
-			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
-		mask[vreg->part->mV.word] = vreg->part->mV.mask;
-	}
-
-	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
-			    val[1], vreg->part->request_len, 1);
-	if (rc)
-		vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(rpm_vreg_set_voltage);
-
-/**
- * rpm_vreg_set_frequency - sets the frequency of a switching regulator
- * @vreg: ID for regulator
- * @freq: enum corresponding to desired frequency
- *
- * Returns 0 on success or errno.
- */
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq)
-{
-	unsigned int mask[2] = {0}, val[2] = {0};
-	struct vreg *vreg;
-	int rc;
-
-	if (vreg_id < 0 || vreg_id > RPM_VREG_ID_PM8921_MAX_REAL) {
-		pr_err("invalid regulator id=%d\n", vreg_id);
-		return -EINVAL;
-	}
-
-	/*
-	 * TODO: make this function a no-op for 8064 so that it can be called by
-	 * consumers on 8064 before RPM capabilities are present.
-	 */
-	if (cpu_is_apq8064())
-		return 0;
-
-	vreg = &vregs[vreg_id];
-
-	if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
-		vreg_err(vreg, "invalid frequency=%d\n", freq);
-		return -EINVAL;
-	}
-	if (!vreg->pdata.sleep_selectable) {
-		vreg_err(vreg, "regulator is not marked sleep selectable\n");
-		return -EINVAL;
-	}
-	if (!vreg->part->freq.mask) {
-		vreg_err(vreg, "frequency not supported\n");
-		return -EINVAL;
-	}
-
-	val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
-	mask[vreg->part->freq.word] = vreg->part->freq.mask;
-
-	rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
-			   val[0], mask[1], val[1], vreg->part->request_len, 0);
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
-
-static inline int vreg_hpm_min_uA(struct vreg *vreg)
-{
-	return vreg->hpm_min_load;
-}
-
-static inline int vreg_lpm_max_uA(struct vreg *vreg)
-{
-	return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
-}
-
-static inline unsigned saturate_peak_load(struct vreg *vreg, unsigned load_uA)
-{
-	unsigned load_max
-		= MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
-
-	return (load_uA > load_max ? load_max : load_uA);
-}
-
-static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
-{
-	unsigned load_max
-		= MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
-	return (load_uA > load_max ? load_max : load_uA);
-}
-
-/* Change vreg->req, but do not send it to the RPM. */
-static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
-		unsigned mask1, unsigned val1)
-{
-	unsigned long flags = 0;
-
-	if (vreg->pdata.sleep_selectable)
-		spin_lock_irqsave(&pm8921_noirq_lock, flags);
-
-	vreg->req[0].value &= ~mask0;
-	vreg->req[0].value |= val0 & mask0;
-
-	vreg->req[1].value &= ~mask1;
-	vreg->req[1].value |= val1 & mask1;
-
-	if (vreg->pdata.sleep_selectable)
-		spin_unlock_irqrestore(&pm8921_noirq_lock, flags);
-
-	return 0;
-}
-
-static int vreg_set(struct vreg *vreg, unsigned mask0, unsigned val0,
-		unsigned mask1, unsigned val1, unsigned cnt)
-{
-	unsigned prev0 = 0, prev1 = 0;
-	int rc;
-
-	/*
-	 * Bypass the normal route for regulators that can be called to change
-	 * just the active set values.
-	 */
-	if (vreg->pdata.sleep_selectable)
-		return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
-					mask0, val0, mask1, val1, cnt, 1);
-
-	prev0 = vreg->req[0].value;
-	vreg->req[0].value &= ~mask0;
-	vreg->req[0].value |= val0 & mask0;
-
-	prev1 = vreg->req[1].value;
-	vreg->req[1].value &= ~mask1;
-	vreg->req[1].value |= val1 & mask1;
-
-	/* Ignore duplicate requests */
-	if (vreg->req[0].value == vreg->prev_active_req[0].value &&
-	    vreg->req[1].value == vreg->prev_active_req[1].value) {
-		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE)
-			rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
-		return 0;
-	}
-
-	rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
-	if (rc) {
-		vreg->req[0].value = prev0;
-		vreg->req[1].value = prev1;
-
-		vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
-			vreg->req[0].id, rc);
-	} else {
-		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
-			rpm_regulator_req(vreg, MSM_RPM_CTX_SET_0);
-		vreg->prev_active_req[0].value = vreg->req[0].value;
-		vreg->prev_active_req[1].value = vreg->req[1].value;
-	}
-
-	return rc;
-}
-
-static int vreg_is_enabled(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	int enabled;
-
-	mutex_lock(&vreg->pc_lock);
-	enabled = vreg->is_enabled;
-	mutex_unlock(&vreg->pc_lock);
-
-	return enabled;
-}
-
-static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
-{
-	switch (vreg->type) {
-	case REGULATOR_TYPE_LDO:
-	case REGULATOR_TYPE_SMPS:
-		/* Enable by setting a voltage. */
-		if (vreg->part->uV.mask) {
-			val[vreg->part->uV.word]
-				|= vreg->save_uV << vreg->part->uV.shift;
-			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
-		} else {
-			val[vreg->part->mV.word]
-				|= MICRO_TO_MILLI(vreg->save_uV)
-					<< vreg->part->mV.shift;
-			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
-		}
-		break;
-	case REGULATOR_TYPE_VS:
-	case REGULATOR_TYPE_NCP:
-		/* Enable by setting enable_state. */
-		val[vreg->part->enable_state.word]
-			|= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
-		mask[vreg->part->enable_state.word]
-			|= vreg->part->enable_state.mask;
-	}
-}
-
-static int vreg_enable(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mask[2] = {0}, val[2] = {0};
-	int rc = 0;
-
-	set_enable(vreg, mask, val);
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-			vreg->part->request_len);
-	if (!rc)
-		vreg->is_enabled = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static void set_disable(struct vreg *vreg, unsigned int *mask,
-			unsigned int *val)
-{
-	switch (vreg->type) {
-	case REGULATOR_TYPE_LDO:
-	case REGULATOR_TYPE_SMPS:
-		/* Disable by setting a voltage of 0 uV. */
-		if (vreg->part->uV.mask) {
-			val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
-			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
-		} else {
-			val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
-			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
-		}
-		break;
-	case REGULATOR_TYPE_VS:
-	case REGULATOR_TYPE_NCP:
-		/* Disable by setting enable_state. */
-		val[vreg->part->enable_state.word]
-			|= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
-		mask[vreg->part->enable_state.word]
-			|= vreg->part->enable_state.mask;
-	}
-}
-
-static int vreg_disable(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mask[2] = {0}, val[2] = {0};
-	int rc = 0;
-
-	set_disable(vreg, mask, val);
-
-	mutex_lock(&vreg->pc_lock);
-
-	/* Only disable if pin control is not in use. */
-	if (!vreg->is_enabled_pc)
-		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-				vreg->part->request_len);
-
-	if (!rc)
-		vreg->is_enabled = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
-			    unsigned *selector)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	struct vreg_range *range = &vreg->set_points->range[0];
-	unsigned int mask[2] = {0}, val[2] = {0};
-	int rc = 0, uV = min_uV;
-	int lim_min_uV, lim_max_uV, i;
-
-	/* Check if request voltage is outside of physically settable range. */
-	lim_min_uV = vreg->set_points->range[0].min_uV;
-	lim_max_uV =
-		vreg->set_points->range[vreg->set_points->count - 1].max_uV;
-
-	if (uV < lim_min_uV && max_uV >= lim_min_uV)
-		uV = lim_min_uV;
-
-	if (uV < lim_min_uV || uV > lim_max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, lim_min_uV, lim_max_uV);
-		return -EINVAL;
-	}
-
-	/* Find the range which uV is inside of. */
-	for (i = vreg->set_points->count - 1; i > 0; i--) {
-		if (uV > vreg->set_points->range[i - 1].max_uV) {
-			range = &vreg->set_points->range[i];
-			break;
-		}
-	}
-
-	/*
-	 * Force uV to be an allowed set point and apply a ceiling function
-	 * to non-set point values.
-	 */
-	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
-	uV = uV * range->step_uV + range->min_uV;
-
-	if (vreg->part->uV.mask) {
-		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
-		mask[vreg->part->uV.word] = vreg->part->uV.mask;
-	} else {
-		val[vreg->part->mV.word]
-			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
-		mask[vreg->part->mV.word] = vreg->part->mV.mask;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Only send a request for a new voltage if the regulator is currently
-	 * enabled.  This will ensure that LDO and SMPS regulators are not
-	 * inadvertently turned on because voltage > 0 is equivalent to
-	 * enabling.  For NCP, this just removes unnecessary RPM requests.
-	 */
-	if (vreg->is_enabled) {
-		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-				vreg->part->request_len);
-		if (rc)
-			vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-	} else if (vreg->type == REGULATOR_TYPE_NCP) {
-		/* Regulator is disabled; store but don't send new request. */
-		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
-	}
-
-	if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
-		vreg->save_uV = uV;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	return rc;
-}
-
-static int vreg_get_voltage(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-
-	return vreg->save_uV;
-}
-
-static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	int uV = 0;
-	int i;
-
-	if (!vreg->set_points) {
-		vreg_err(vreg, "no voltages available\n");
-		return -EINVAL;
-	}
-
-	if (selector >= vreg->set_points->n_voltages)
-		return 0;
-
-	for (i = 0; i < vreg->set_points->count; i++) {
-		if (selector < vreg->set_points->range[i].n_voltages) {
-			uV = selector * vreg->set_points->range[i].step_uV
-				+ vreg->set_points->range[i].min_uV;
-			break;
-		} else {
-			selector -= vreg->set_points->range[i].n_voltages;
-		}
-	}
-
-	return uV;
-}
-
-static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mask[2] = {0}, val[2] = {0};
-	int rc = 0;
-	int peak_uA;
-
-	mutex_lock(&vreg->pc_lock);
-
-	peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
-				& vreg->part->ip.mask) >> vreg->part->ip.shift);
-
-	switch (mode) {
-	case REGULATOR_MODE_NORMAL:
-		/* Make sure that request currents are in HPM range. */
-		if (peak_uA < vreg_hpm_min_uA(vreg)) {
-			val[vreg->part->ip.word]
-				= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
-					<< vreg->part->ip.shift;
-			mask[vreg->part->ip.word] = vreg->part->ip.mask;
-		}
-		break;
-	case REGULATOR_MODE_IDLE:
-		/* Make sure that request currents are in LPM range. */
-		if (peak_uA > vreg_lpm_max_uA(vreg)) {
-			val[vreg->part->ip.word]
-				= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
-					<< vreg->part->ip.shift;
-			mask[vreg->part->ip.word] = vreg->part->ip.mask;
-		}
-		break;
-	default:
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		mutex_unlock(&vreg->pc_lock);
-		return -EINVAL;
-	}
-
-	if (vreg->is_enabled) {
-		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-					vreg->part->request_len);
-	} else {
-		/* Regulator is disabled; store but don't send new request. */
-		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
-	}
-
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-	else
-		vreg->mode = mode;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	return rc;
-}
-
-static unsigned int vreg_get_mode(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-
-	return vreg->mode;
-}
-
-static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
-			int input_uV, int output_uV, int load_uA)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode;
-
-	load_uA += vreg->pdata.system_uA;
-
-	mutex_lock(&vreg->pc_lock);
-	SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
-	mutex_unlock(&vreg->pc_lock);
-
-	if (load_uA >= vreg->hpm_min_load)
-		mode = REGULATOR_MODE_NORMAL;
-	else
-		mode = REGULATOR_MODE_IDLE;
-
-	return mode;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-
-	return vreg->is_enabled_pc;
-}
-
-static int vreg_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mask[2] = {0}, val[2] = {0};
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	val[vreg->part->pc.word]
-		|= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
-	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
-
-	val[vreg->part->pf.word]  |= vreg->pdata.pin_fn << vreg->part->pf.shift;
-	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
-
-	if (!vreg->is_enabled)
-		set_enable(vreg, mask, val);
-
-	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-			vreg->part->request_len);
-
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int vreg_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mask[2] = {0}, val[2] = {0};
-	enum rpm_vreg_pin_fn pin_fn;
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	val[vreg->part->pc.word]
-		|= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
-	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
-
-	pin_fn = RPM_VREG_PIN_FN_NONE;
-	if (vreg->pdata.pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
-		pin_fn = RPM_VREG_PIN_FN_SLEEP_B;
-	val[vreg->part->pf.word]  |= pin_fn << vreg->part->pf.shift;
-	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
-
-	if (!vreg->is_enabled)
-		set_disable(vreg, mask, val);
-
-	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
-			vreg->part->request_len);
-
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-/* Real regulator operations. */
-static struct regulator_ops ldo_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
-	.is_enabled		= vreg_is_enabled,
-	.set_voltage		= vreg_set_voltage,
-	.get_voltage		= vreg_get_voltage,
-	.list_voltage		= vreg_list_voltage,
-	.set_mode		= vreg_set_mode,
-	.get_mode		= vreg_get_mode,
-	.get_optimum_mode	= vreg_get_optimum_mode,
+static const char *pin_control_label[] = {
+	" D1",
+	" A0",
+	" A1",
+	" A2",
 };
 
-static struct regulator_ops smps_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
-	.is_enabled		= vreg_is_enabled,
-	.set_voltage		= vreg_set_voltage,
-	.get_voltage		= vreg_get_voltage,
-	.list_voltage		= vreg_list_voltage,
-	.set_mode		= vreg_set_mode,
-	.get_mode		= vreg_get_mode,
-	.get_optimum_mode	= vreg_get_optimum_mode,
-};
-
-static struct regulator_ops switch_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
-	.is_enabled		= vreg_is_enabled,
-};
-
-static struct regulator_ops ncp_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
-	.is_enabled		= vreg_is_enabled,
-	.set_voltage		= vreg_set_voltage,
-	.get_voltage		= vreg_get_voltage,
-	.list_voltage		= vreg_list_voltage,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pin_control_ops = {
-	.enable			= vreg_pin_control_enable,
-	.disable		= vreg_pin_control_disable,
-	.is_enabled		= vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops) \
-	[RPM_VREG_ID_PM8921_##_id] = { \
-		.id	= RPM_VREG_ID_PM8921_##_id, \
-		.name	= _name, \
-		.ops	= _ops, \
-		.type	= REGULATOR_VOLTAGE, \
-		.owner	= THIS_MODULE, \
-	}
-
-static struct regulator_desc vreg_description[] = {
-	VREG_DESC(L1,  "8921_l1",  &ldo_ops),
-	VREG_DESC(L2,  "8921_l2",  &ldo_ops),
-	VREG_DESC(L3,  "8921_l3",  &ldo_ops),
-	VREG_DESC(L4,  "8921_l4",  &ldo_ops),
-	VREG_DESC(L5,  "8921_l5",  &ldo_ops),
-	VREG_DESC(L6,  "8921_l6",  &ldo_ops),
-	VREG_DESC(L7,  "8921_l7",  &ldo_ops),
-	VREG_DESC(L8,  "8921_l8",  &ldo_ops),
-	VREG_DESC(L9,  "8921_l9",  &ldo_ops),
-	VREG_DESC(L10, "8921_l10", &ldo_ops),
-	VREG_DESC(L11, "8921_l11", &ldo_ops),
-	VREG_DESC(L12, "8921_l12", &ldo_ops),
-	VREG_DESC(L14, "8921_l14", &ldo_ops),
-	VREG_DESC(L15, "8921_l15", &ldo_ops),
-	VREG_DESC(L16, "8921_l16", &ldo_ops),
-	VREG_DESC(L17, "8921_l17", &ldo_ops),
-	VREG_DESC(L18, "8921_l18", &ldo_ops),
-	VREG_DESC(L21, "8921_l21", &ldo_ops),
-	VREG_DESC(L22, "8921_l22", &ldo_ops),
-	VREG_DESC(L23, "8921_l23", &ldo_ops),
-	VREG_DESC(L24, "8921_l24", &ldo_ops),
-	VREG_DESC(L25, "8921_l25", &ldo_ops),
-	VREG_DESC(L26, "8921_l26", &ldo_ops),
-	VREG_DESC(L27, "8921_l27", &ldo_ops),
-	VREG_DESC(L28, "8921_l28", &ldo_ops),
-	VREG_DESC(L29, "8921_l29", &ldo_ops),
-
-	VREG_DESC(S1, "8921_s1", &smps_ops),
-	VREG_DESC(S2, "8921_s2", &smps_ops),
-	VREG_DESC(S3, "8921_s3", &smps_ops),
-	VREG_DESC(S4, "8921_s4", &smps_ops),
-	VREG_DESC(S5, "8921_s5", &smps_ops),
-	VREG_DESC(S6, "8921_s6", &smps_ops),
-	VREG_DESC(S7, "8921_s7", &smps_ops),
-	VREG_DESC(S8, "8921_s8", &smps_ops),
-
-	VREG_DESC(LVS1, "8921_lvs1", &switch_ops),
-	VREG_DESC(LVS2, "8921_lvs2", &switch_ops),
-	VREG_DESC(LVS3, "8921_lvs3", &switch_ops),
-	VREG_DESC(LVS4, "8921_lvs4", &switch_ops),
-	VREG_DESC(LVS5, "8921_lvs5", &switch_ops),
-	VREG_DESC(LVS6, "8921_lvs6", &switch_ops),
-	VREG_DESC(LVS7, "8921_lvs7", &switch_ops),
-
-	VREG_DESC(USB_OTG, "8921_usb_otg", &switch_ops),
-	VREG_DESC(HDMI_MVS, "8921_hdmi_mvs", &switch_ops),
-	VREG_DESC(NCP, "8921_ncp", &ncp_ops),
-
-	VREG_DESC(L1_PC,  "8921_l1_pc",  &pin_control_ops),
-	VREG_DESC(L2_PC,  "8921_l2_pc",  &pin_control_ops),
-	VREG_DESC(L3_PC,  "8921_l3_pc",  &pin_control_ops),
-	VREG_DESC(L4_PC,  "8921_l4_pc",  &pin_control_ops),
-	VREG_DESC(L5_PC,  "8921_l5_pc",  &pin_control_ops),
-	VREG_DESC(L6_PC,  "8921_l6_pc",  &pin_control_ops),
-	VREG_DESC(L7_PC,  "8921_l7_pc",  &pin_control_ops),
-	VREG_DESC(L8_PC,  "8921_l8_pc",  &pin_control_ops),
-	VREG_DESC(L9_PC,  "8921_l9_pc",  &pin_control_ops),
-	VREG_DESC(L10_PC, "8921_l10_pc", &pin_control_ops),
-	VREG_DESC(L11_PC, "8921_l11_pc", &pin_control_ops),
-	VREG_DESC(L12_PC, "8921_l12_pc", &pin_control_ops),
-	VREG_DESC(L14_PC, "8921_l14_pc", &pin_control_ops),
-	VREG_DESC(L15_PC, "8921_l15_pc", &pin_control_ops),
-	VREG_DESC(L16_PC, "8921_l16_pc", &pin_control_ops),
-	VREG_DESC(L17_PC, "8921_l17_pc", &pin_control_ops),
-	VREG_DESC(L18_PC, "8921_l18_pc", &pin_control_ops),
-	VREG_DESC(L21_PC, "8921_l21_pc", &pin_control_ops),
-	VREG_DESC(L22_PC, "8921_l22_pc", &pin_control_ops),
-	VREG_DESC(L23_PC, "8921_l23_pc", &pin_control_ops),
-	VREG_DESC(L29_PC, "8921_l29_pc", &pin_control_ops),
-
-	VREG_DESC(S1_PC, "8921_s1_pc", &pin_control_ops),
-	VREG_DESC(S2_PC, "8921_s2_pc", &pin_control_ops),
-	VREG_DESC(S3_PC, "8921_s3_pc", &pin_control_ops),
-	VREG_DESC(S4_PC, "8921_s4_pc", &pin_control_ops),
-	VREG_DESC(S7_PC, "8921_s7_pc", &pin_control_ops),
-	VREG_DESC(S8_PC, "8921_s8_pc", &pin_control_ops),
-
-	VREG_DESC(LVS1_PC, "8921_lvs1_pc", &pin_control_ops),
-	VREG_DESC(LVS3_PC, "8921_lvs3_pc", &pin_control_ops),
-	VREG_DESC(LVS4_PC, "8921_lvs4_pc", &pin_control_ops),
-	VREG_DESC(LVS5_PC, "8921_lvs5_pc", &pin_control_ops),
-	VREG_DESC(LVS6_PC, "8921_lvs6_pc", &pin_control_ops),
-	VREG_DESC(LVS7_PC, "8921_lvs7_pc", &pin_control_ops),
-};
-
-static inline int is_real_regulator(int id)
+static int is_real_id(int id)
 {
 	return (id >= 0) && (id <= RPM_VREG_ID_PM8921_MAX_REAL);
 }
@@ -1431,237 +279,36 @@
 	return real_id;
 }
 
-static int __devinit
-rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
-			struct device *dev)
-{
-	enum rpm_vreg_pin_fn pin_fn;
-	struct regulator_desc *rdesc;
-	struct regulator_dev *rdev;
-	struct vreg *vreg;
-	const char *reg_name = "";
-	unsigned pin_ctrl;
-	int rc = 0, id = pdata->id;
+static struct vreg_config config = {
+	.vregs			= vregs,
+	.vregs_len		= ARRAY_SIZE(vregs),
 
-	if (id < 0 || id > RPM_VREG_ID_PM8921_MAX) {
-		pr_err("invalid regulator id: %d\n", id);
-		return -ENODEV;
-	}
+	.vreg_id_min		= RPM_VREG_ID_PM8921_L1,
+	.vreg_id_max		= RPM_VREG_ID_PM8921_MAX,
 
-	rdesc = &vreg_description[pdata->id];
-	if (!is_real_regulator(pdata->id))
-		id = pc_id_to_real_id(pdata->id);
-	vreg = &vregs[id];
-	reg_name = vreg_description[pdata->id].name;
-	if (!pdata) {
-		pr_err("%s: requires platform data\n", reg_name);
-		return -EINVAL;
-	}
-	if (vreg->set_points)
-		rdesc->n_voltages = vreg->set_points->n_voltages;
-	else
-		rdesc->n_voltages = 0;
+	.pin_func_none		= RPM_VREG_PIN_FN_8960_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_8960_SLEEP_B,
 
-	mutex_lock(&vreg->pc_lock);
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
 
-	if (is_real_regulator(pdata->id)) {
-		/* Do not modify pin control and pin function values. */
-		pin_ctrl = vreg->pdata.pin_ctrl;
-		pin_fn = vreg->pdata.pin_fn;
-		memcpy(&(vreg->pdata), pdata,
-			sizeof(struct rpm_regulator_init_data));
-		vreg->pdata.pin_ctrl = pin_ctrl;
-		vreg->pdata.pin_fn = pin_fn;
-		vreg->name = reg_name;
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
 
-		vreg->save_uV = vreg->pdata.default_uV;
-		if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
-			vreg->mode = REGULATOR_MODE_NORMAL;
-		else
-			vreg->mode = REGULATOR_MODE_IDLE;
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
 
-		/* Initialize the RPM request. */
-		SET_PART(vreg, ip,
-		 MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
-		SET_PART(vreg, fm, vreg->pdata.force_mode);
-		SET_PART(vreg, pm, vreg->pdata.power_mode);
-		SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
-		SET_PART(vreg, ia,
-		   MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
-		SET_PART(vreg, freq, vreg->pdata.freq);
-		SET_PART(vreg, freq_clk_src, 0);
-		SET_PART(vreg, comp_mode, 0);
-		SET_PART(vreg, hpm, 0);
-		if (!vreg->is_enabled_pc) {
-			SET_PART(vreg, pf, RPM_VREG_PIN_FN_NONE);
-			SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
-		}
-	} else {
-		/* Pin control regulator */
-		if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
-		      == RPM_VREG_PIN_CTRL_NONE
-		    && pdata->pin_fn != RPM_VREG_PIN_FN_SLEEP_B) {
-			pr_err("%s: no pin control input specified\n",
-				reg_name);
-			mutex_unlock(&vreg->pc_lock);
-			return -EINVAL;
-		}
-		vreg->pdata.pin_ctrl = pdata->pin_ctrl;
-		vreg->pdata.pin_fn = pdata->pin_fn;
-		if (!vreg->name)
-			vreg->name = reg_name;
-
-		/* Initialize the RPM request. */
-		pin_fn = RPM_VREG_PIN_FN_NONE;
-		/* Allow pf=sleep_b to be specified by platform data. */
-		if (vreg->pdata.pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
-			pin_fn = RPM_VREG_PIN_FN_SLEEP_B;
-		SET_PART(vreg, pf, pin_fn);
-		SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
-	}
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		goto bail;
-
-	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
-	if (IS_ERR(rdev)) {
-		rc = PTR_ERR(rdev);
-		pr_err("regulator_register failed: %s, rc=%d\n", reg_name, rc);
-		return rc;
-	} else {
-		if (is_real_regulator(pdata->id))
-			vreg->rdev = rdev;
-		else
-			vreg->rdev_pc = rdev;
-	}
-
-bail:
-	if (rc)
-		pr_err("error for %s, rc=%d\n", reg_name, rc);
-
-	return rc;
-}
-
-static int __devinit rpm_vreg_probe(struct platform_device *pdev)
-{
-	struct rpm_regulator_platform_data *platform_data;
-	int rc = 0;
-	int i;
-
-	platform_data = pdev->dev.platform_data;
-	if (!platform_data) {
-		pr_err("rpm-regulator requires platform data\n");
-		return -EINVAL;
-	}
-
-	/* Initialize all of the regulators listed in the platform data. */
-	for (i = 0; i < platform_data->num_regulators; i++) {
-		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
-			&pdev->dev);
-		if (rc) {
-			pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
-			goto remove_regulators;
-		}
-	}
-
-	platform_set_drvdata(pdev, platform_data);
-
-	return rc;
-
-remove_regulators:
-	/* Unregister all regulators added before the erroring one. */
-	for (; i >= 0; i--) {
-		if (is_real_regulator(platform_data->init_data[i].id))
-			regulator_unregister(vregs[i].rdev);
-		else
-			regulator_unregister(
-				vregs[pc_id_to_real_id(i)].rdev_pc);
-	}
-
-	return rc;
-}
-
-static int __devexit rpm_vreg_remove(struct platform_device *pdev)
-{
-	struct rpm_regulator_platform_data *platform_data;
-	int i, id;
-
-	platform_data = platform_get_drvdata(pdev);
-	platform_set_drvdata(pdev, NULL);
-
-	if (platform_data) {
-		for (i = 0; i < platform_data->num_regulators; i++) {
-			id = platform_data->init_data[i].id;
-			if (is_real_regulator(id)) {
-				regulator_unregister(vregs[id].rdev);
-				vregs[id].rdev = NULL;
-			} else {
-				regulator_unregister(
-					vregs[pc_id_to_real_id(id)].rdev_pc);
-				vregs[id].rdev_pc = NULL;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static struct platform_driver rpm_vreg_driver = {
-	.probe = rpm_vreg_probe,
-	.remove = __devexit_p(rpm_vreg_remove),
-	.driver = {
-		.name = RPM_REGULATOR_DEV_NAME,
-		.owner = THIS_MODULE,
-	},
+	.is_real_id		= is_real_id,
+	.pc_id_to_real_id	= pc_id_to_real_id,
 };
 
-static int __init rpm_vreg_init(void)
+struct vreg_config *get_config_8960(void)
 {
-	struct vreg_set_points *set_points[] = {
-		&pldo_set_points,
-		&nldo_set_points,
-		&nldo1200_set_points,
-		&smps_set_points,
-		&ftsmps_set_points,
-		&ncp_set_points,
-	};
-	int i, j;
-
-	/* Calculate the number of set points available for each regualtor. */
-	for (i = 0; i < ARRAY_SIZE(set_points); i++) {
-		for (j = 0; j < set_points[i]->count; j++) {
-			set_points[i]->range[j].n_voltages
-				= (set_points[i]->range[j].max_uV
-					- set_points[i]->range[j].min_uV)
-				   / set_points[i]->range[j].step_uV + 1;
-			set_points[i]->n_voltages
-				+= set_points[i]->range[j].n_voltages;
-		}
-	}
-
-	/* Initialize pin control mutexes */
-	for (i = 0; i < ARRAY_SIZE(vregs); i++)
-		mutex_init(&vregs[i].pc_lock);
-
-	return platform_driver_register(&rpm_vreg_driver);
+	return &config;
 }
-
-static void __exit rpm_vreg_exit(void)
-{
-	int i;
-
-	platform_driver_unregister(&rpm_vreg_driver);
-
-	for (i = 0; i < ARRAY_SIZE(vregs); i++)
-		mutex_destroy(&vregs[i].pc_lock);
-}
-
-postcore_initcall(rpm_vreg_init);
-module_exit(rpm_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MSM8960 rpm regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c
new file mode 100644
index 0000000..23c0ee3
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-9615.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+	.pm		= REQUEST_MEMBER(1, 0x00800000, 23),
+	.freq		= REQUEST_MEMBER(1, 0x1F000000, 24),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x60000000, 29),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000003C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range nldo1200_ranges[] = {
+	VOLTAGE_RANGE( 375000,  743750,  6250),
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&nldo1200_set_points,
+	&smps_set_points,
+};
+
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_id, _name, _name_pc) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(L2,   "8018_l2",   "8018_l2_pc",  pldo,     LDO_50),
+	LDO(L3,   "8018_l3",   "8018_l3_pc",  pldo,     LDO_50),
+	LDO(L4,   "8018_l4",   "8018_l4_pc",  pldo,     LDO_300),
+	LDO(L5,   "8018_l5",   "8018_l5_pc",  pldo,     LDO_150),
+	LDO(L6,   "8018_l6",   "8018_l6_pc",  pldo,     LDO_150),
+	LDO(L7,   "8018_l7",   "8018_l7_pc",  pldo,     LDO_300),
+	LDO(L8,   "8018_l8",   "8018_l8_pc",  nldo,     LDO_150),
+	LDO(L9,   "8018_l9",   NULL,          nldo1200, LDO_1200),
+	LDO(L10,  "8018_l10",  NULL,          nldo1200, LDO_1200),
+	LDO(L11,  "8018_l11",  NULL,          nldo1200, LDO_1200),
+	LDO(L12,  "8018_l12",  NULL,          nldo1200, LDO_1200),
+	LDO(L13,  "8018_l13",  "8018_l13_pc", pldo,     LDO_50),
+	LDO(L14,  "8018_l14",  "8018_l14_pc", pldo,     LDO_50),
+
+	SMPS(S1,  "8018_s1",   "8018_s1_pc",  smps,     SMPS_1500),
+	SMPS(S2,  "8018_s2",   "8018_s2_pc",  smps,     SMPS_1500),
+	SMPS(S3,  "8018_s3",   "8018_s3_pc",  smps,     SMPS_1500),
+	SMPS(S4,  "8018_s4",   "8018_s4_pc",  smps,     SMPS_1500),
+	SMPS(S5,  "8018_s5",   "8018_s5_pc",  smps,     SMPS_1500),
+
+	LVS(LVS1, "8018_lvs1", "8018_lvs1_pc"),
+};
+
+static const char *pin_control_label[] = {
+	" D1",
+	" A0",
+	" A1",
+	" A2",
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_9615_DONT_CARE]	= "don't care",
+	[RPM_VREG_PIN_FN_9615_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_9615_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_9615_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_9615_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_9615_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_9615_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_9615_AUTO]		= "auto",
+	[RPM_VREG_FORCE_MODE_9615_HPM]		= "HPM",
+	[RPM_VREG_FORCE_MODE_9615_BYPASS]	= "BYP",
+};
+
+static const char *power_mode_label[] = {
+	[RPM_VREG_POWER_MODE_9615_HYSTERETIC]	= "HYS",
+	[RPM_VREG_POWER_MODE_9615_PWM]		= "PWM",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8018_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id;
+
+	if (id >= RPM_VREG_ID_PM8018_L2_PC && id <= RPM_VREG_ID_PM8018_L8_PC)
+		real_id = id - RPM_VREG_ID_PM8018_L2_PC + RPM_VREG_ID_PM8018_L2;
+	else
+		real_id = id - RPM_VREG_ID_PM8018_L13_PC
+				+ RPM_VREG_ID_PM8018_L13;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs			= vregs,
+	.vregs_len		= ARRAY_SIZE(vregs),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8018_L2,
+	.vreg_id_max		= RPM_VREG_ID_PM8018_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_9615_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_9615_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id,
+	.pc_id_to_real_id	= pc_id_to_real_id,
+};
+
+struct vreg_config *get_config_9615(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
new file mode 100644
index 0000000..ff127d9
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+
+#include <linux/regulator/driver.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+
+/* Possible RPM regulator request types */
+enum rpm_regulator_type {
+	RPM_REGULATOR_TYPE_LDO,
+	RPM_REGULATOR_TYPE_SMPS,
+	RPM_REGULATOR_TYPE_VS,
+	RPM_REGULATOR_TYPE_NCP,
+	RPM_REGULATOR_TYPE_MAX = RPM_REGULATOR_TYPE_NCP,
+};
+
+struct request_member {
+	int			word;
+	unsigned int		mask;
+	int			shift;
+};
+
+/* Possible RPM regulator request members */
+struct rpm_vreg_parts {
+	struct request_member	mV;	/* voltage: used if voltage is in mV */
+	struct request_member	uV;	/* voltage: used if voltage is in uV */
+	struct request_member	ip;		/* peak current in mA */
+	struct request_member	pd;		/* pull down enable */
+	struct request_member	ia;		/* average current in mA */
+	struct request_member	fm;		/* force mode */
+	struct request_member	pm;		/* power mode */
+	struct request_member	pc;		/* pin control */
+	struct request_member	pf;		/* pin function */
+	struct request_member	enable_state;	/* NCP and switch */
+	struct request_member	comp_mode;	/* NCP */
+	struct request_member	freq;		/* frequency: NCP and SMPS */
+	struct request_member	freq_clk_src;	/* clock source: SMPS */
+	struct request_member	hpm;		/* switch: control OCP and SS */
+	int			request_len;
+};
+
+struct vreg_range {
+	int			min_uV;
+	int			max_uV;
+	int			step_uV;
+	unsigned		n_voltages;
+};
+
+struct vreg_set_points {
+	struct vreg_range	*range;
+	int			count;
+	unsigned		n_voltages;
+};
+
+struct vreg {
+	struct msm_rpm_iv_pair		req[2];
+	struct msm_rpm_iv_pair		prev_active_req[2];
+	struct msm_rpm_iv_pair		prev_sleep_req[2];
+	struct rpm_regulator_init_data	pdata;
+	struct regulator_desc		rdesc;
+	struct regulator_desc		rdesc_pc;
+	struct regulator_dev		*rdev;
+	struct regulator_dev		*rdev_pc;
+	struct vreg_set_points		*set_points;
+	struct rpm_vreg_parts		*part;
+	int				type;
+	int				id;
+	struct mutex			pc_lock;
+	int				save_uV;
+	int				mode;
+	bool				is_enabled;
+	bool				is_enabled_pc;
+	const int			hpm_min_load;
+	int			       active_min_uV_vote[RPM_VREG_VOTER_COUNT];
+	int				sleep_min_uV_vote[RPM_VREG_VOTER_COUNT];
+};
+
+struct vreg_config {
+	struct vreg			*vregs;
+	int				vregs_len;
+
+	int				vreg_id_min;
+	int				vreg_id_max;
+
+	int				pin_func_none;
+	int				pin_func_sleep_b;
+
+	unsigned int			mode_lpm;
+	unsigned int			mode_hpm;
+
+	struct vreg_set_points		**set_points;
+	int				set_points_len;
+
+	const char			**label_pin_ctrl;
+	int				label_pin_ctrl_len;
+	const char			**label_pin_func;
+	int				label_pin_func_len;
+	const char			**label_force_mode;
+	int				label_force_mode_len;
+	const char			**label_power_mode;
+	int				label_power_mode_len;
+
+	int				(*is_real_id) (int vreg_id);
+	int				(*pc_id_to_real_id) (int vreg_id);
+
+	/* Legacy options to be used with MSM8660 */
+	int				use_legacy_optimum_mode;
+	int				ia_follows_ip;
+};
+
+#define REQUEST_MEMBER(_word, _mask, _shift) \
+	{ \
+		.word	= _word, \
+		.mask	= _mask, \
+		.shift	= _shift, \
+	}
+
+#define VOLTAGE_RANGE(_min_uV, _max_uV, _step_uV) \
+	{ \
+		.min_uV  = _min_uV, \
+		.max_uV  = _max_uV, \
+		.step_uV = _step_uV, \
+	}
+
+#define SET_POINTS(_ranges) \
+{ \
+	.range	= _ranges, \
+	.count	= ARRAY_SIZE(_ranges), \
+};
+
+#define MICRO_TO_MILLI(uV)			((uV) / 1000)
+#define MILLI_TO_MICRO(mV)			((mV) * 1000)
+
+#if defined(CONFIG_ARCH_MSM8X60)
+struct vreg_config *get_config_8660(void);
+#else
+static inline struct vreg_config *get_config_8660(void)
+{
+	return NULL;
+}
+#endif
+
+#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064)
+struct vreg_config *get_config_8960(void);
+#else
+static inline struct vreg_config *get_config_8960(void)
+{
+	return NULL;
+}
+#endif
+
+#if defined(CONFIG_ARCH_MSM9615)
+struct vreg_config *get_config_9615(void);
+#else
+static inline struct vreg_config *get_config_9615(void)
+{
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index b9e577a..2494969 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,18 +11,22 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
-#include <linux/mfd/pmic8901.h>
 #include <mach/rpm.h>
 #include <mach/rpm-regulator.h>
+#include <mach/socinfo.h>
 
 #include "rpm_resources.h"
+#include "rpm-regulator-private.h"
 
 /* Debug Definitions */
 
@@ -29,7 +34,7 @@
 	MSM_RPM_VREG_DEBUG_REQUEST = BIT(0),
 	MSM_RPM_VREG_DEBUG_VOTE = BIT(1),
 	MSM_RPM_VREG_DEBUG_DUPLICATE = BIT(2),
-	MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1 = BIT(3),
+	MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG = BIT(3),
 };
 
 static int msm_rpm_vreg_debug_mask;
@@ -37,241 +42,242 @@
 	debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
 );
 
-#define MICRO_TO_MILLI(uV)			((uV) / 1000)
-#define MILLI_TO_MICRO(mV)			((mV) * 1000)
+struct vreg_config *(*get_config[])(void) = {
+	[RPM_VREG_VERSION_8660] = get_config_8660,
+	[RPM_VREG_VERSION_8960] = get_config_8960,
+	[RPM_VREG_VERSION_9615] = get_config_9615,
+};
 
-/* LDO register word 1 */
-#define LDO_VOLTAGE				0x00000FFF
-#define LDO_VOLTAGE_SHIFT			0
-#define LDO_PEAK_CURRENT			0x00FFF000
-#define LDO_PEAK_CURRENT_SHIFT			12
-#define LDO_MODE				0x03000000
-#define LDO_MODE_SHIFT				24
-#define LDO_PIN_CTRL				0x3C000000
-#define LDO_PIN_CTRL_SHIFT			26
-#define LDO_PIN_FN				0xC0000000
-#define LDO_PIN_FN_SHIFT			30
+#define SET_PART(_vreg, _part, _val) \
+	_vreg->req[_vreg->part->_part.word].value \
+		= (_vreg->req[_vreg->part->_part.word].value \
+			& ~vreg->part->_part.mask) \
+		| (((_val) << vreg->part->_part.shift) & vreg->part->_part.mask)
 
-/* LDO register word 2 */
-#define LDO_PULL_DOWN_ENABLE			0x00000001
-#define LDO_PULL_DOWN_ENABLE_SHIFT		0
-#define LDO_AVG_CURRENT				0x00001FFE
-#define LDO_AVG_CURRENT_SHIFT			1
+#define GET_PART(_vreg, _part) \
+	((_vreg->req[_vreg->part->_part.word].value & vreg->part->_part.mask) \
+		>> vreg->part->_part.shift)
 
-/* SMPS register word 1 */
-#define SMPS_VOLTAGE				0x00000FFF
-#define SMPS_VOLTAGE_SHIFT			0
-#define SMPS_PEAK_CURRENT			0x00FFF000
-#define SMPS_PEAK_CURRENT_SHIFT			12
-#define SMPS_MODE				0x03000000
-#define SMPS_MODE_SHIFT				24
-#define SMPS_PIN_CTRL				0x3C000000
-#define SMPS_PIN_CTRL_SHIFT			26
-#define SMPS_PIN_FN				0xC0000000
-#define SMPS_PIN_FN_SHIFT			30
+#define USES_PART(_vreg, _part) (vreg->part->_part.mask)
 
-/* SMPS register word 2 */
-#define SMPS_PULL_DOWN_ENABLE			0x00000001
-#define SMPS_PULL_DOWN_ENABLE_SHIFT		0
-#define SMPS_AVG_CURRENT			0x00001FFE
-#define SMPS_AVG_CURRENT_SHIFT			1
-#define SMPS_FREQ				0x001FE000
-#define SMPS_FREQ_SHIFT				13
-#define SMPS_CLK_SRC				0x00600000
-#define SMPS_CLK_SRC_SHIFT			21
+#define vreg_err(vreg, fmt, ...) \
+	pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
 
-/* SWITCH register word 1 */
-#define SWITCH_STATE				0x0001
-#define SWITCH_STATE_SHIFT			0
-#define SWITCH_PULL_DOWN_ENABLE			0x0002
-#define SWITCH_PULL_DOWN_ENABLE_SHIFT		1
-#define SWITCH_PIN_CTRL				0x003C
-#define SWITCH_PIN_CTRL_SHIFT			2
-#define SWITCH_PIN_FN				0x00C0
-#define SWITCH_PIN_FN_SHIFT			6
+#define RPM_VREG_PIN_CTRL_EN0		0x01
+#define RPM_VREG_PIN_CTRL_EN1		0x02
+#define RPM_VREG_PIN_CTRL_EN2		0x04
+#define RPM_VREG_PIN_CTRL_EN3		0x08
+#define RPM_VREG_PIN_CTRL_ALL		0x0F
 
-/* NCP register word 1 */
-#define NCP_VOLTAGE				0x0FFF
-#define NCP_VOLTAGE_SHIFT			0
-#define NCP_STATE				0x1000
-#define NCP_STATE_SHIFT				12
-
+static const char *label_freq[] = {
+	[RPM_VREG_FREQ_NONE]		= " N/A",
+	[RPM_VREG_FREQ_19p20]		= "19.2",
+	[RPM_VREG_FREQ_9p60]		= "9.60",
+	[RPM_VREG_FREQ_6p40]		= "6.40",
+	[RPM_VREG_FREQ_4p80]		= "4.80",
+	[RPM_VREG_FREQ_3p84]		= "3.84",
+	[RPM_VREG_FREQ_3p20]		= "3.20",
+	[RPM_VREG_FREQ_2p74]		= "2.74",
+	[RPM_VREG_FREQ_2p40]		= "2.40",
+	[RPM_VREG_FREQ_2p13]		= "2.13",
+	[RPM_VREG_FREQ_1p92]		= "1.92",
+	[RPM_VREG_FREQ_1p75]		= "1.75",
+	[RPM_VREG_FREQ_1p60]		= "1.60",
+	[RPM_VREG_FREQ_1p48]		= "1.48",
+	[RPM_VREG_FREQ_1p37]		= "1.37",
+	[RPM_VREG_FREQ_1p28]		= "1.28",
+	[RPM_VREG_FREQ_1p20]		= "1.20",
+};
 /*
  * This is used when voting for LPM or HPM by subtracting or adding to the
  * hpm_min_load of a regulator.  It has units of uA.
  */
-#define LOAD_THRESHOLD_STEP			1000
+#define LOAD_THRESHOLD_STEP		1000
 
-/* This is the maximum uA load that can be passed to the RPM. */
-#define MAX_POSSIBLE_LOAD			(MILLI_TO_MICRO(0xFFF))
+/* rpm_version keeps track of the version for the currently running driver. */
+enum rpm_vreg_version rpm_version = -1;
 
-/* Voltage regulator types */
-#define IS_LDO(id)	((id >= RPM_VREG_ID_PM8058_L0 && \
-			  id <= RPM_VREG_ID_PM8058_L25) || \
-			 (id >= RPM_VREG_ID_PM8901_L0 && \
-			  id <= RPM_VREG_ID_PM8901_L6))
-#define IS_SMPS(id)	((id >= RPM_VREG_ID_PM8058_S0 && \
-			  id <= RPM_VREG_ID_PM8058_S4) || \
-			 (id >= RPM_VREG_ID_PM8901_S0 && \
-			  id <= RPM_VREG_ID_PM8901_S4))
-#define IS_SWITCH(id)	((id >= RPM_VREG_ID_PM8058_LVS0 && \
-			  id <= RPM_VREG_ID_PM8058_LVS1) || \
-			 (id >= RPM_VREG_ID_PM8901_LVS0 && \
-			  id <= RPM_VREG_ID_PM8901_LVS3) || \
-			 (id == RPM_VREG_ID_PM8901_MVS0))
-#define IS_NCP(id)	(id == RPM_VREG_ID_PM8058_NCP)
+/* config holds all configuration data of the currently running driver. */
+static struct vreg_config *config;
 
-#define IS_8901_SMPS(id) ((id >= RPM_VREG_ID_PM8901_S0 && \
-			  id <= RPM_VREG_ID_PM8901_S4))
+/* These regulator ID values are specified in the board file. */
+static int vreg_id_vdd_mem, vreg_id_vdd_dig;
 
-struct vreg {
-	struct msm_rpm_iv_pair	req[2];
-	struct msm_rpm_iv_pair	prev_active_req[2];
-	struct msm_rpm_iv_pair	prev_sleep_req[2];
-	struct rpm_vreg_pdata	*pdata;
-	int			save_uV;
-	const int		hpm_min_load;
-	unsigned		pc_vote;
-	unsigned		optimum;
-	unsigned		mode_initialized;
-	int			active_min_mV_vote[RPM_VREG_VOTER_COUNT];
-	int			sleep_min_mV_vote[RPM_VREG_VOTER_COUNT];
-	enum rpm_vreg_id	id;
-};
+static inline int vreg_id_is_vdd_mem_or_dig(int id)
+{
+	return id == vreg_id_vdd_mem || id == vreg_id_vdd_dig;
+}
 
-#define RPM_VREG_NCP_HPM_MIN_LOAD	0
+#define DEBUG_PRINT_BUFFER_SIZE 512
 
-#define VREG_2(_vreg_id, _rpm_id, _hpm_min_load) \
-	[RPM_VREG_ID_##_vreg_id] = { \
-		.req = { \
-			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
-			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
-		}, \
-		.hpm_min_load = RPM_VREG_##_hpm_min_load, \
+static void rpm_regulator_req(struct vreg *vreg, int set)
+{
+	int uV, mV, fm, pm, pc, pf, pd, freq, state, i;
+	const char *pf_label = "", *fm_label = "", *pc_total = "";
+	const char *pc_en[4] = {"", "", "", ""};
+	const char *pm_label = "", *freq_label = "";
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	int pos = 0;
+
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
+
+	uV = GET_PART(vreg, uV);
+	mV = GET_PART(vreg, mV);
+	if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
+		uV = -uV;
+		mV = -mV;
 	}
 
-#define VREG_1(_vreg_id, _rpm_id) \
-	[RPM_VREG_ID_##_vreg_id] = { \
-		.req = { \
-			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
-			[1] = { .id = -1, }, \
-		}, \
+	fm = GET_PART(vreg, fm);
+	pm = GET_PART(vreg, pm);
+	pc = GET_PART(vreg, pc);
+	pf = GET_PART(vreg, pf);
+	pd = GET_PART(vreg, pd);
+	freq = GET_PART(vreg, freq);
+	state = GET_PART(vreg, enable_state);
+
+	if (pf >= 0 && pf < config->label_pin_func_len)
+		pf_label = config->label_pin_func[pf];
+
+	if (fm >= 0 && fm < config->label_force_mode_len)
+		fm_label = config->label_force_mode[fm];
+
+	if (pm >= 0 && pm < config->label_power_mode_len)
+		pm_label = config->label_power_mode[pm];
+
+	if (freq >= 0 && freq < ARRAY_SIZE(label_freq))
+		freq_label = label_freq[freq];
+
+	for (i = 0; i < config->label_pin_ctrl_len; i++)
+		if (pc & (1 << i))
+			pc_en[i] = config->label_pin_ctrl[i];
+
+	if (pc == RPM_VREG_PIN_CTRL_NONE)
+		pc_total = " none";
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+			 KERN_INFO, __func__);
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s %-9s: s=%c",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg->rdesc.name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'));
+
+	if (USES_PART(vreg, uV))
+		pos += scnprintf(buf + pos, buflen - pos, ", v=%7d uV", uV);
+	if (USES_PART(vreg, mV))
+		pos += scnprintf(buf + pos, buflen - pos, ", v=%4d mV", mV);
+	if (USES_PART(vreg, enable_state))
+		pos += scnprintf(buf + pos, buflen - pos, ", state=%s (%d)",
+				 (state == 1 ? "on" : "off"), state);
+	if (USES_PART(vreg, ip))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", ip=%4d mA", GET_PART(vreg, ip));
+	if (USES_PART(vreg, fm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", fm=%s (%d)", fm_label, fm);
+	if (USES_PART(vreg, pc))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pc=%s%s%s%s%s (%X)", pc_en[0], pc_en[1],
+				 pc_en[2], pc_en[3], pc_total, pc);
+	if (USES_PART(vreg, pf))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pf=%s (%d)", pf_label, pf);
+	if (USES_PART(vreg, pd))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pd=%s (%d)", (pd == 1 ? "Y" : "N"), pd);
+	if (USES_PART(vreg, ia))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", ia=%4d mA", GET_PART(vreg, ia));
+	if (USES_PART(vreg, freq)) {
+		if (vreg->type == RPM_REGULATOR_TYPE_NCP)
+			pos += scnprintf(buf + pos, buflen - pos,
+				       ", freq=%2d", freq);
+		else
+			pos += scnprintf(buf + pos, buflen - pos,
+				       ", freq=%s MHz (%2d)", freq_label, freq);
 	}
+	if (USES_PART(vreg, pm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pm=%s (%d)", pm_label, pm);
+	if (USES_PART(vreg, freq_clk_src))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", clk_src=%d", GET_PART(vreg, freq_clk_src));
+	if (USES_PART(vreg, comp_mode))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", comp=%d", GET_PART(vreg, comp_mode));
+	if (USES_PART(vreg, hpm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", hpm=%d", GET_PART(vreg, hpm));
 
-static struct vreg vregs[RPM_VREG_ID_MAX] = {
-	VREG_2(PM8058_L0, LDO0, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L1, LDO1, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L2, LDO2, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L3, LDO3, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L4, LDO4, LDO_50_HPM_MIN_LOAD),
-	VREG_2(PM8058_L5, LDO5, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L6, LDO6, LDO_50_HPM_MIN_LOAD),
-	VREG_2(PM8058_L7, LDO7, LDO_50_HPM_MIN_LOAD),
-	VREG_2(PM8058_L8, LDO8, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L9, LDO9, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L10, LDO10, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L11, LDO11, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L12, LDO12, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L13, LDO13, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L14, LDO14, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L15, LDO15, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L16, LDO16, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L17, LDO17, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L18, LDO18, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L19, LDO19, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L20, LDO20, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L21, LDO21, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L22, LDO22, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L23, LDO23, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8058_L24, LDO24, LDO_150_HPM_MIN_LOAD),
-	VREG_2(PM8058_L25, LDO25, LDO_150_HPM_MIN_LOAD),
+	pos += scnprintf(buf + pos, buflen - pos, "; req[0]={%d, 0x%08X}",
+			 vreg->req[0].id, vreg->req[0].value);
+	if (vreg->part->request_len > 1)
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", req[1]={%d, 0x%08X}", vreg->req[1].id,
+				 vreg->req[1].value);
 
-	VREG_2(PM8058_S0, SMPS0, SMPS_HPM_MIN_LOAD),
-	VREG_2(PM8058_S1, SMPS1, SMPS_HPM_MIN_LOAD),
-	VREG_2(PM8058_S2, SMPS2, SMPS_HPM_MIN_LOAD),
-	VREG_2(PM8058_S3, SMPS3, SMPS_HPM_MIN_LOAD),
-	VREG_2(PM8058_S4, SMPS4, SMPS_HPM_MIN_LOAD),
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
 
-	VREG_1(PM8058_LVS0, LVS0),
-	VREG_1(PM8058_LVS1, LVS1),
+static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
+			int set, int voter_uV, int aggregate_uV)
+{
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
 
-	VREG_2(PM8058_NCP, NCP, NCP_HPM_MIN_LOAD),
+	pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
+		"v_aggregate=%7d uV\n", vreg->rdesc.name, voter,
+		(set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
+}
 
-	VREG_2(PM8901_L0, LDO0B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L1, LDO1B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L2, LDO2B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L3, LDO3B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L4, LDO4B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L5, LDO5B, LDO_300_HPM_MIN_LOAD),
-	VREG_2(PM8901_L6, LDO6B, LDO_300_HPM_MIN_LOAD),
+static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
+{
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
 
-	VREG_2(PM8901_S0, SMPS0B, FTSMPS_HPM_MIN_LOAD),
-	VREG_2(PM8901_S1, SMPS1B, FTSMPS_HPM_MIN_LOAD),
-	VREG_2(PM8901_S2, SMPS2B, FTSMPS_HPM_MIN_LOAD),
-	VREG_2(PM8901_S3, SMPS3B, FTSMPS_HPM_MIN_LOAD),
-	VREG_2(PM8901_S4, SMPS4B, FTSMPS_HPM_MIN_LOAD),
-
-	VREG_1(PM8901_LVS0, LVS0B),
-	VREG_1(PM8901_LVS1, LVS1B),
-	VREG_1(PM8901_LVS2, LVS2B),
-	VREG_1(PM8901_LVS3, LVS3B),
-
-	VREG_1(PM8901_MVS0, MVS),
-};
-
-static void print_rpm_request(struct vreg *vreg, int set);
-static void print_rpm_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
-			int set, int voter_mV, int aggregate_mV);
-static void print_rpm_duplicate(struct vreg *vreg, int set, int cnt);
-
-static unsigned int smps_get_mode(struct regulator_dev *dev);
-static unsigned int ldo_get_mode(struct regulator_dev *dev);
-static unsigned int switch_get_mode(struct regulator_dev *dev);
+	if (cnt == 2)
+		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
+			"req[1]={%d, 0x%08X}\n", vreg->rdesc.name,
+			(set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value,
+			vreg->req[1].id, vreg->req[1].value);
+	else if (cnt == 1)
+		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
+			vreg->rdesc.name, (set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value);
+}
 
 /* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(pm8058_noirq_lock);
+static DEFINE_SPINLOCK(rpm_noirq_lock);
 
 static int voltage_from_req(struct vreg *vreg)
 {
-	int shift = 0;
-	uint32_t value = 0, mask = 0;
+	int uV = 0;
 
-	value = vreg->req[0].value;
+	if (vreg->part->uV.mask)
+		uV = GET_PART(vreg, uV);
+	else
+		uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
 
-	if (IS_SMPS(vreg->id)) {
-		mask = SMPS_VOLTAGE;
-		shift = SMPS_VOLTAGE_SHIFT;
-	} else if (IS_LDO(vreg->id)) {
-		mask = LDO_VOLTAGE;
-		shift = LDO_VOLTAGE_SHIFT;
-	} else if (IS_NCP(vreg->id)) {
-		mask = NCP_VOLTAGE;
-		shift = NCP_VOLTAGE_SHIFT;
-	}
-
-	return (value & mask) >> shift;
+	return uV;
 }
 
-static void voltage_to_req(int voltage, struct vreg *vreg)
+static void voltage_to_req(int uV, struct vreg *vreg)
 {
-	int shift = 0;
-	uint32_t *value = NULL, mask = 0;
-
-	value = &(vreg->req[0].value);
-
-	if (IS_SMPS(vreg->id)) {
-		mask = SMPS_VOLTAGE;
-		shift = SMPS_VOLTAGE_SHIFT;
-	} else if (IS_LDO(vreg->id)) {
-		mask = LDO_VOLTAGE;
-		shift = LDO_VOLTAGE_SHIFT;
-	} else if (IS_NCP(vreg->id)) {
-		mask = NCP_VOLTAGE;
-		shift = NCP_VOLTAGE_SHIFT;
-	}
-
-	*value &= ~mask;
-	*value |= (voltage << shift) & mask;
+	if (vreg->part->uV.mask)
+		SET_PART(vreg, uV, uV);
+	else
+		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
 }
 
 static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
@@ -280,15 +286,16 @@
 			  int update_voltage)
 {
 	struct msm_rpm_iv_pair *prev_req;
-	int rc = 0, max_mV_vote = 0, i;
+	int rc = 0, max_uV_vote = 0;
 	unsigned prev0, prev1;
-	int *min_mV_vote;
+	int *min_uV_vote;
+	int i;
 
 	if (set == MSM_RPM_CTX_SET_0) {
-		min_mV_vote = vreg->active_min_mV_vote;
+		min_uV_vote = vreg->active_min_uV_vote;
 		prev_req = vreg->prev_active_req;
 	} else {
-		min_mV_vote = vreg->sleep_min_mV_vote;
+		min_uV_vote = vreg->sleep_min_uV_vote;
 		prev_req = vreg->prev_sleep_req;
 	}
 
@@ -301,42 +308,41 @@
 	vreg->req[1].value |= val1 & mask1;
 
 	if (update_voltage)
-		min_mV_vote[voter] = voltage_from_req(vreg);
+		min_uV_vote[voter] = voltage_from_req(vreg);
 
 	/* Find the highest voltage voted for and use it. */
 	for (i = 0; i < RPM_VREG_VOTER_COUNT; i++)
-		max_mV_vote = max(max_mV_vote, min_mV_vote[i]);
-	voltage_to_req(max_mV_vote, vreg);
+		max_uV_vote = max(max_uV_vote, min_uV_vote[i]);
+	voltage_to_req(max_uV_vote, vreg);
 
 	if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
-		print_rpm_vote(vreg, voter, set, min_mV_vote[voter],
-				max_mV_vote);
+		rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
+				max_uV_vote);
 
 	/* Ignore duplicate requests */
 	if (vreg->req[0].value != prev_req[0].value ||
 	    vreg->req[1].value != prev_req[1].value) {
-
 		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
 		if (rc) {
 			vreg->req[0].value = prev0;
 			vreg->req[1].value = prev1;
 
-			pr_err("%s: msm_rpmrs_set_noirq failed - "
-				"set=%s, id=%d, rc=%d\n", __func__,
+			vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
+				"set=%s, id=%d, rc=%d\n",
 				(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
 				vreg->req[0].id, rc);
 		} else {
 			/* Only save if nonzero and active set. */
-			if (max_mV_vote && (set == MSM_RPM_CTX_SET_0))
-				vreg->save_uV = MILLI_TO_MICRO(max_mV_vote);
+			if (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
+				vreg->save_uV = max_uV_vote;
 			if (msm_rpm_vreg_debug_mask
 			    & MSM_RPM_VREG_DEBUG_REQUEST)
-				print_rpm_request(vreg, set);
+				rpm_regulator_req(vreg, set);
 			prev_req[0].value = vreg->req[0].value;
 			prev_req[1].value = vreg->req[1].value;
 		}
 	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
-		print_rpm_duplicate(vreg, set, cnt);
+		rpm_regulator_duplicate(vreg, set, cnt);
 	}
 
 	return rc;
@@ -347,14 +353,14 @@
 			  unsigned mask1, unsigned val1, unsigned cnt,
 			  int update_voltage)
 {
+	unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
 	unsigned long flags;
 	int rc;
-	unsigned val0_sleep, mask0_sleep;
 
 	if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
 		return -EINVAL;
 
-	spin_lock_irqsave(&pm8058_noirq_lock, flags);
+	spin_lock_irqsave(&rpm_noirq_lock, flags);
 
 	/*
 	 * Send sleep set request first so that subsequent set_mode, etc calls
@@ -369,28 +375,23 @@
 		 * specified.  This ensures that a disable vote will be issued
 		 * at some point for the sleep set of the regulator.
 		 */
-		val0_sleep = val0;
-		mask0_sleep = mask0;
-		if (IS_SMPS(vreg->id)) {
-			val0_sleep &= ~SMPS_VOLTAGE;
-			mask0_sleep |= SMPS_VOLTAGE;
-		} else if (IS_LDO(vreg->id)) {
-			val0_sleep &= ~LDO_VOLTAGE;
-			mask0_sleep |= LDO_VOLTAGE;
-		} else if (IS_NCP(vreg->id)) {
-			val0_sleep &= ~NCP_VOLTAGE;
-			mask0_sleep |= NCP_VOLTAGE;
+		if (vreg->part->uV.mask) {
+			s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
+			s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
+		} else {
+			s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
+			s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
 		}
 
 		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
-					mask0_sleep, val0_sleep,
-					mask1, val1, cnt, update_voltage);
+				       s_mask[0], s_val[0], s_mask[1], s_val[1],
+				       cnt, update_voltage);
 	}
 
 	rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
 					mask1, val1, cnt, update_voltage);
 
-	spin_unlock_irqrestore(&pm8058_noirq_lock, flags);
+	spin_unlock_irqrestore(&rpm_noirq_lock, flags);
 
 	return rc;
 }
@@ -416,38 +417,87 @@
  * This function may only be called for regulators which have the sleep flag
  * specified in their private data.
  */
-int rpm_vreg_set_voltage(enum rpm_vreg_id vreg_id, enum rpm_vreg_voter voter,
-			 int min_uV, int max_uV, int sleep_also)
+int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
+			 int max_uV, int sleep_also)
 {
-	int rc;
-	unsigned val0 = 0, val1 = 0, mask0 = 0, mask1 = 0, cnt = 2;
+	unsigned int mask[2] = {0}, val[2] = {0};
+	struct vreg_range *range;
+	struct vreg *vreg;
+	int uV = min_uV;
+	int lim_min_uV, lim_max_uV, i, rc;
 
-	if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX)
-		return -EINVAL;
+	/*
+	 * HACK: make this function a no-op for 8064 so that it can be called by
+	 * consumers on 8064 before RPM capabilities are present. (needed for
+	 * acpuclock driver)
+	 */
+	if (cpu_is_apq8064())
+		return 0;
 
-	if (!vregs[vreg_id].pdata->sleep_selectable)
-		return -EINVAL;
-
-	if (min_uV < vregs[vreg_id].pdata->init_data.constraints.min_uV ||
-	    min_uV > vregs[vreg_id].pdata->init_data.constraints.max_uV)
-		return -EINVAL;
-
-	if (IS_SMPS(vreg_id)) {
-		mask0 = SMPS_VOLTAGE;
-		val0 = MICRO_TO_MILLI(min_uV) << SMPS_VOLTAGE_SHIFT;
-	} else if (IS_LDO(vreg_id)) {
-		mask0 = LDO_VOLTAGE;
-		val0 = MICRO_TO_MILLI(min_uV) << LDO_VOLTAGE_SHIFT;
-	} else if (IS_NCP(vreg_id)) {
-		mask0 = NCP_VOLTAGE;
-		val0 = MICRO_TO_MILLI(min_uV) << NCP_VOLTAGE_SHIFT;
-		cnt = 1;
-	} else {
-		cnt = 1;
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return -ENODEV;
 	}
 
-	rc = vreg_set_noirq(&vregs[vreg_id], voter, sleep_also, mask0, val0,
-			    mask1, val1, cnt, 1);
+	if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", vreg_id);
+		return -EINVAL;
+	}
+
+	vreg = &config->vregs[vreg_id];
+	range = &vreg->set_points->range[0];
+
+	if (!vreg->pdata.sleep_selectable) {
+		vreg_err(vreg, "regulator is not marked sleep selectable\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Check if request voltage is outside of allowed range. The regulator
+	 * core has already checked that constraint range is inside of the
+	 * physically allowed range.
+	 */
+	lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
+	lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
+
+	if (uV < lim_min_uV && max_uV >= lim_min_uV)
+		uV = lim_min_uV;
+
+	if (uV < lim_min_uV || uV > lim_max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside allowed v=[%d, %d]\n",
+			 min_uV, max_uV, lim_min_uV, lim_max_uV);
+		return -EINVAL;
+	}
+
+	/* Find the range which uV is inside of. */
+	for (i = vreg->set_points->count - 1; i > 0; i--) {
+		if (uV > vreg->set_points->range[i - 1].max_uV) {
+			range = &vreg->set_points->range[i];
+			break;
+		}
+	}
+
+	/*
+	 * Force uV to be an allowed set point and apply a ceiling function
+	 * to non-set point values.
+	 */
+	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+	uV = uV * range->step_uV + range->min_uV;
+
+	if (vreg->part->uV.mask) {
+		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+		mask[vreg->part->uV.word] = vreg->part->uV.mask;
+	} else {
+		val[vreg->part->mV.word]
+			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+		mask[vreg->part->mV.word] = vreg->part->mV.mask;
+	}
+
+	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
+			    val[1], vreg->part->request_len, 1);
+	if (rc)
+		vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
 
 	return rc;
 }
@@ -456,52 +506,60 @@
 /**
  * rpm_vreg_set_frequency - sets the frequency of a switching regulator
  * @vreg: ID for regulator
- * @min_uV: minimum acceptable frequency of operation
+ * @freq: enum corresponding to desired frequency
  *
  * Returns 0 on success or errno.
  */
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq)
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
 {
-	unsigned val0 = 0, val1 = 0, mask0 = 0, mask1 = 0, cnt = 2;
+	unsigned int mask[2] = {0}, val[2] = {0};
+	struct vreg *vreg;
 	int rc;
 
-	if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX) {
-		pr_err("%s: invalid regulator id=%d\n", __func__, vreg_id);
+	/*
+	 * HACK: make this function a no-op for 8064 so that it can be called by
+	 * consumers on 8064 before RPM capabilities are present.
+	 */
+	if (cpu_is_apq8064())
+		return 0;
+
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return -ENODEV;
+	}
+
+	if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", vreg_id);
 		return -EINVAL;
 	}
 
+	vreg = &config->vregs[vreg_id];
+
 	if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
-		pr_err("%s: invalid frequency=%d\n", __func__, freq);
+		vreg_err(vreg, "invalid frequency=%d\n", freq);
+		return -EINVAL;
+	}
+	if (!vreg->pdata.sleep_selectable) {
+		vreg_err(vreg, "regulator is not marked sleep selectable\n");
+		return -EINVAL;
+	}
+	if (!vreg->part->freq.mask) {
+		vreg_err(vreg, "frequency not supported\n");
 		return -EINVAL;
 	}
 
-	if (!IS_SMPS(vreg_id)) {
-		pr_err("%s: regulator id=%d does not support frequency\n",
-			__func__, vreg_id);
-		return -EINVAL;
-	}
+	val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
+	mask[vreg->part->freq.word] = vreg->part->freq.mask;
 
-	if (!vregs[vreg_id].pdata->sleep_selectable) {
-		pr_err("%s: regulator id=%d is not marked sleep selectable\n",
-			__func__, vreg_id);
-		return -EINVAL;
-	}
-
-	mask1 = SMPS_FREQ;
-	val1 = freq << SMPS_FREQ_SHIFT;
-
-	rc = vreg_set_noirq(&vregs[vreg_id], RPM_VREG_VOTER_REG_FRAMEWORK,
-			    1, mask0, val0, mask1, val1, cnt, 0);
+	rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
+			   val[0], mask[1], val[1], vreg->part->request_len, 0);
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
 
 	return rc;
 }
 EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
 
-#define IS_PMIC_8901_V1(rev)		((rev) == PM_8901_REV_1p0 || \
-					 (rev) == PM_8901_REV_1p1)
-
-#define PMIC_8901_V1_SCALE(uV)		((((uV) - 62100) * 23) / 25)
-
 static inline int vreg_hpm_min_uA(struct vreg *vreg)
 {
 	return vreg->hpm_min_load;
@@ -512,9 +570,19 @@
 	return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
 }
 
-static inline unsigned saturate_load(unsigned load_uA)
+static inline unsigned saturate_peak_load(struct vreg *vreg, unsigned load_uA)
 {
-	return (load_uA > MAX_POSSIBLE_LOAD ? MAX_POSSIBLE_LOAD : load_uA);
+	unsigned load_max
+		= MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
+
+	return (load_uA > load_max ? load_max : load_uA);
+}
+
+static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
+{
+	unsigned load_max
+		= MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
+	return (load_uA > load_max ? load_max : load_uA);
 }
 
 /* Change vreg->req, but do not send it to the RPM. */
@@ -523,8 +591,8 @@
 {
 	unsigned long flags = 0;
 
-	if (vreg->pdata->sleep_selectable)
-		spin_lock_irqsave(&pm8058_noirq_lock, flags);
+	if (vreg->pdata.sleep_selectable)
+		spin_lock_irqsave(&rpm_noirq_lock, flags);
 
 	vreg->req[0].value &= ~mask0;
 	vreg->req[0].value |= val0 & mask0;
@@ -532,8 +600,8 @@
 	vreg->req[1].value &= ~mask1;
 	vreg->req[1].value |= val1 & mask1;
 
-	if (vreg->pdata->sleep_selectable)
-		spin_unlock_irqrestore(&pm8058_noirq_lock, flags);
+	if (vreg->pdata.sleep_selectable)
+		spin_unlock_irqrestore(&rpm_noirq_lock, flags);
 
 	return 0;
 }
@@ -548,7 +616,7 @@
 	 * Bypass the normal route for regulators that can be called to change
 	 * just the active set values.
 	 */
-	if (vreg->pdata->sleep_selectable)
+	if (vreg->pdata.sleep_selectable)
 		return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
 					mask0, val0, mask1, val1, cnt, 1);
 
@@ -564,7 +632,7 @@
 	if (vreg->req[0].value == vreg->prev_active_req[0].value &&
 	    vreg->req[1].value == vreg->prev_active_req[1].value) {
 		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE)
-			print_rpm_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
+			rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
 		return 0;
 	}
 
@@ -573,11 +641,11 @@
 		vreg->req[0].value = prev0;
 		vreg->req[1].value = prev1;
 
-		pr_err("%s: msm_rpm_set fail id=%d, rc=%d\n",
-				__func__, vreg->req[0].id, rc);
+		vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
+			vreg->req[0].id, rc);
 	} else {
 		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
-			print_rpm_request(vreg, MSM_RPM_CTX_SET_0);
+			rpm_regulator_req(vreg, MSM_RPM_CTX_SET_0);
 		vreg->prev_active_req[0].value = vreg->req[0].value;
 		vreg->prev_active_req[1].value = vreg->req[1].value;
 	}
@@ -585,880 +653,736 @@
 	return rc;
 }
 
-static int smps_is_enabled(struct regulator_dev *dev)
+static int vreg_is_enabled(struct regulator_dev *rdev)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	return ((vreg->req[0].value & SMPS_VOLTAGE) >> SMPS_VOLTAGE_SHIFT) != 0;
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	int enabled;
+
+	mutex_lock(&vreg->pc_lock);
+	enabled = vreg->is_enabled;
+	mutex_unlock(&vreg->pc_lock);
+
+	return enabled;
 }
 
-static int _smps_set_voltage(struct regulator_dev *dev, int min_uV)
+static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	int scaled_min_uV = min_uV;
-	static int pmic8901_rev;
-
-	/* Scale input request voltage down if using v1 PMIC 8901. */
-	if (IS_8901_SMPS(vreg->id) && min_uV) {
-		if (pmic8901_rev <= 0)
-			pmic8901_rev = pm8901_rev(NULL);
-
-		if (pmic8901_rev < 0)
-			pr_err("%s: setting %s to %d uV; PMIC 8901 revision "
-				"unavailable, no scaling can be performed.\n",
-				__func__, dev->desc->name, min_uV);
-		else if (IS_PMIC_8901_V1(pmic8901_rev))
-			scaled_min_uV = PMIC_8901_V1_SCALE(min_uV);
+	switch (vreg->type) {
+	case RPM_REGULATOR_TYPE_LDO:
+	case RPM_REGULATOR_TYPE_SMPS:
+		/* Enable by setting a voltage. */
+		if (vreg->part->uV.mask) {
+			val[vreg->part->uV.word]
+				|= vreg->save_uV << vreg->part->uV.shift;
+			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+		} else {
+			val[vreg->part->mV.word]
+				|= MICRO_TO_MILLI(vreg->save_uV)
+					<< vreg->part->mV.shift;
+			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+		}
+		break;
+	case RPM_REGULATOR_TYPE_VS:
+	case RPM_REGULATOR_TYPE_NCP:
+		/* Enable by setting enable_state. */
+		val[vreg->part->enable_state.word]
+			|= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+			|= vreg->part->enable_state.mask;
 	}
-
-	return vreg_set(vreg, SMPS_VOLTAGE,
-			MICRO_TO_MILLI(scaled_min_uV) << SMPS_VOLTAGE_SHIFT,
-			0, 0, 2);
 }
 
-static int smps_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
+static int vreg_enable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+
+	set_enable(vreg, mask, val);
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
+	if (!rc)
+		vreg->is_enabled = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static void set_disable(struct vreg *vreg, unsigned int *mask,
+			unsigned int *val)
+{
+	switch (vreg->type) {
+	case RPM_REGULATOR_TYPE_LDO:
+	case RPM_REGULATOR_TYPE_SMPS:
+		/* Disable by setting a voltage of 0 uV. */
+		if (vreg->part->uV.mask) {
+			val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
+			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+		} else {
+			val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
+			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+		}
+		break;
+	case RPM_REGULATOR_TYPE_VS:
+	case RPM_REGULATOR_TYPE_NCP:
+		/* Disable by setting enable_state. */
+		val[vreg->part->enable_state.word]
+			|= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+			|= vreg->part->enable_state.mask;
+	}
+}
+
+static int vreg_disable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+
+	set_disable(vreg, mask, val);
+
+	mutex_lock(&vreg->pc_lock);
+
+	/* Only disable if pin control is not in use. */
+	if (!vreg->is_enabled_pc)
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+				vreg->part->request_len);
+
+	if (!rc)
+		vreg->is_enabled = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
 			    unsigned *selector)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	int rc = 0;
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	struct vreg_range *range = &vreg->set_points->range[0];
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0, uV = min_uV;
+	int lim_min_uV, lim_max_uV, i;
 
-	if (smps_is_enabled(dev))
-		rc = _smps_set_voltage(dev, min_uV);
-	if (rc)
-		return rc;
+	/* Check if request voltage is outside of physically settable range. */
+	lim_min_uV = vreg->set_points->range[0].min_uV;
+	lim_max_uV =
+		vreg->set_points->range[vreg->set_points->count - 1].max_uV;
 
-	/* only save if nonzero (or not disabling) */
-	if (min_uV && (!vreg->pdata->sleep_selectable || !smps_is_enabled(dev)))
-		vreg->save_uV = min_uV;
+	if (uV < lim_min_uV && max_uV >= lim_min_uV)
+		uV = lim_min_uV;
 
-	return rc;
-}
-
-static int smps_get_voltage(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	return vreg->save_uV;
-}
-
-static int smps_enable(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	int rc = 0;
-	unsigned mask, val;
-
-	/* enable by setting voltage */
-	if (MICRO_TO_MILLI(vreg->save_uV) > 0) {
-		/* reenable pin control if it is in use */
-		if (smps_get_mode(dev) == REGULATOR_MODE_IDLE) {
-			mask = SMPS_PIN_CTRL | SMPS_PIN_FN;
-			val = vreg->pdata->pin_ctrl << SMPS_PIN_CTRL_SHIFT
-				| vreg->pdata->pin_fn << SMPS_PIN_FN_SHIFT;
-			vreg_store(vreg, mask, val, 0, 0);
-		}
-
-		rc = _smps_set_voltage(dev, vreg->save_uV);
-	}
-	return rc;
-}
-
-static int smps_disable(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned mask, val;
-
-	/* turn off pin control */
-	mask = SMPS_PIN_CTRL | SMPS_PIN_FN;
-	val = RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT
-		| RPM_VREG_PIN_FN_NONE << SMPS_PIN_FN_SHIFT;
-	vreg_store(vreg, mask, val, 0, 0);
-
-	/* disable by setting voltage to zero */
-	return _smps_set_voltage(dev, 0);
-}
-
-/*
- * Optimum mode programming:
- * REGULATOR_MODE_FAST: Go to HPM (highest priority)
- * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
- * votes, else go to LPM
- *
- * Pin ctrl mode voting via regulator set_mode:
- * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
- * go to HPM
- * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
- *
- * Pin ctrl mode takes priority on the RPM when force mode is not set;
- * therefore, pin ctrl bits must be cleared if LPM or HPM is being voted for.
- */
-static int smps_set_mode(struct regulator_dev *dev, unsigned int mode)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned optimum = vreg->optimum;
-	unsigned pc_vote = vreg->pc_vote;
-	unsigned mode_initialized = vreg->mode_initialized;
-	unsigned mask0 = 0, val0 = 0, mask1 = 0, val1 = 0;
-	int set_hpm = -1, set_pin_control = -1;
-	int peak_uA;
-	int rc = 0;
-
-	peak_uA = MILLI_TO_MICRO((vreg->req[0].value & SMPS_PEAK_CURRENT) >>
-		  SMPS_PEAK_CURRENT_SHIFT);
-
-	switch (mode) {
-	case REGULATOR_MODE_FAST:
-		set_hpm = 1;
-		set_pin_control = 0;
-		optimum = REGULATOR_MODE_FAST;
-		mode_initialized = 1;
-		break;
-
-	case REGULATOR_MODE_STANDBY:
-		set_hpm = 0;
-		if (pc_vote)
-			set_pin_control = 1;
-		else
-			set_pin_control = 0;
-		optimum = REGULATOR_MODE_STANDBY;
-		mode_initialized = 1;
-		break;
-
-	case REGULATOR_MODE_IDLE:
-		if (pc_vote++)
-			goto done; /* already taken care of */
-
-		if (mode_initialized && optimum == REGULATOR_MODE_FAST) {
-			set_hpm = 1;
-			set_pin_control = 0;
-		} else {
-			set_pin_control = 1;
-		}
-		break;
-
-	case REGULATOR_MODE_NORMAL:
-		if (pc_vote && --pc_vote)
-			goto done; /* already taken care of */
-
-		if (optimum == REGULATOR_MODE_STANDBY)
-			set_hpm = 0;
-		else
-			set_hpm = 1;
-		set_pin_control = 0;
-		break;
-
-	default:
+	if (uV < lim_min_uV || uV > lim_max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, lim_min_uV, lim_max_uV);
 		return -EINVAL;
 	}
 
-	if (set_hpm == 1) {
-		/* Make sure that request currents are at HPM level. */
-		if (peak_uA < vreg_hpm_min_uA(vreg)) {
-			mask0 = SMPS_PEAK_CURRENT;
-			mask1 = SMPS_AVG_CURRENT;
-			val0 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
-			   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
-			val1 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
-			     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
-		}
-	} else if (set_hpm == 0) {
-		/* Make sure that request currents are at LPM level. */
-		if (peak_uA > vreg_lpm_max_uA(vreg)) {
-			mask0 = SMPS_PEAK_CURRENT;
-			mask1 = SMPS_AVG_CURRENT;
-			val0 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
-			   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
-			val1 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
-			     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
+	/* Find the range which uV is inside of. */
+	for (i = vreg->set_points->count - 1; i > 0; i--) {
+		if (uV > vreg->set_points->range[i - 1].max_uV) {
+			range = &vreg->set_points->range[i];
+			break;
 		}
 	}
 
-	if (set_pin_control == 1) {
-		/* Enable pin control and pin function. */
-		mask0 |= SMPS_PIN_CTRL | SMPS_PIN_FN;
-		val0 |= vreg->pdata->pin_ctrl << SMPS_PIN_CTRL_SHIFT
-			| vreg->pdata->pin_fn << SMPS_PIN_FN_SHIFT;
-	} else if (set_pin_control == 0) {
-		/* Clear pin control and pin function*/
-		mask0 |= SMPS_PIN_CTRL | SMPS_PIN_FN;
-		val0 |= RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT
-			| RPM_VREG_PIN_FN_NONE << SMPS_PIN_FN_SHIFT;
-	}
+	/*
+	 * Force uV to be an allowed set point and apply a ceiling function
+	 * to non-set point values.
+	 */
+	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+	uV = uV * range->step_uV + range->min_uV;
 
-	if (smps_is_enabled(dev)) {
-		rc = vreg_set(vreg, mask0, val0, mask1, val1, 2);
+	if (vreg->part->uV.mask) {
+		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+		mask[vreg->part->uV.word] = vreg->part->uV.mask;
 	} else {
+		val[vreg->part->mV.word]
+			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+		mask[vreg->part->mV.word] = vreg->part->mV.mask;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	/*
+	 * Only send a request for a new voltage if the regulator is currently
+	 * enabled.  This will ensure that LDO and SMPS regulators are not
+	 * inadvertently turned on because voltage > 0 is equivalent to
+	 * enabling.  For NCP, this just removes unnecessary RPM requests.
+	 */
+	if (vreg->is_enabled) {
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+				vreg->part->request_len);
+		if (rc)
+			vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+	} else if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
 		/* Regulator is disabled; store but don't send new request. */
-		rc = vreg_store(vreg, mask0, val0, mask1, val1);
-	}
-	if (rc)
-		return rc;
-
-done:
-	vreg->mode_initialized = mode_initialized;
-	vreg->optimum = optimum;
-	vreg->pc_vote = pc_vote;
-
-	return 0;
-}
-
-static unsigned int smps_get_mode(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-
-	if ((vreg->optimum == REGULATOR_MODE_FAST) && vreg->mode_initialized)
-		return REGULATOR_MODE_FAST;
-	else if (vreg->pc_vote)
-		return REGULATOR_MODE_IDLE;
-	else if (vreg->optimum == REGULATOR_MODE_STANDBY)
-		return REGULATOR_MODE_STANDBY;
-	return REGULATOR_MODE_FAST;
-}
-
-unsigned int smps_get_optimum_mode(struct regulator_dev *dev, int input_uV,
-		int output_uV, int load_uA)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-
-	if (MICRO_TO_MILLI(load_uA) > 0) {
-		vreg->req[0].value &= ~SMPS_PEAK_CURRENT;
-		vreg->req[0].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
-				   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
-		vreg->req[1].value &= ~SMPS_AVG_CURRENT;
-		vreg->req[1].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
-				     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
-	} else {
-		/*
-		 * smps_get_optimum_mode is being called before consumers have
-		 * specified their load currents via regulator_set_optimum_mode.
-		 * Return whatever the existing mode is.
-		 */
-		return smps_get_mode(dev);
+		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
 	}
 
-	if (load_uA >= vreg->hpm_min_load)
-		return REGULATOR_MODE_FAST;
-	return REGULATOR_MODE_STANDBY;
-}
+	if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
+		vreg->save_uV = uV;
 
-static int ldo_is_enabled(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	return ((vreg->req[0].value & LDO_VOLTAGE) >> LDO_VOLTAGE_SHIFT) != 0;
-}
-
-static int _ldo_set_voltage(struct regulator_dev *dev, int min_uV)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-
-	return vreg_set(vreg, LDO_VOLTAGE,
-			MICRO_TO_MILLI(min_uV) << LDO_VOLTAGE_SHIFT,
-			0, 0, 2);
-}
-
-static int ldo_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
-			   unsigned *selector)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	int rc = 0;
-
-	if (ldo_is_enabled(dev))
-		rc = _ldo_set_voltage(dev, min_uV);
-	if (rc)
-		return rc;
-
-	/* only save if nonzero (or not disabling) */
-	if (min_uV && (!vreg->pdata->sleep_selectable || !ldo_is_enabled(dev)))
-		vreg->save_uV = min_uV;
+	mutex_unlock(&vreg->pc_lock);
 
 	return rc;
 }
 
-static int ldo_get_voltage(struct regulator_dev *dev)
+static int vreg_get_voltage(struct regulator_dev *rdev)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
 	return vreg->save_uV;
 }
 
-static int ldo_enable(struct regulator_dev *dev)
+static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	int rc = 0;
-	unsigned mask, val;
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	int uV = 0;
+	int i;
 
-	/* enable by setting voltage */
-	if (MICRO_TO_MILLI(vreg->save_uV) > 0) {
-		/* reenable pin control if it is in use */
-		if (ldo_get_mode(dev) == REGULATOR_MODE_IDLE) {
-			mask = LDO_PIN_CTRL | LDO_PIN_FN;
-			val = vreg->pdata->pin_ctrl << LDO_PIN_CTRL_SHIFT
-				| vreg->pdata->pin_fn << LDO_PIN_FN_SHIFT;
-			vreg_store(vreg, mask, val, 0, 0);
-		}
-
-		rc = _ldo_set_voltage(dev, vreg->save_uV);
-	}
-	return rc;
-}
-
-static int ldo_disable(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned mask, val;
-
-	/* turn off pin control */
-	mask = LDO_PIN_CTRL | LDO_PIN_FN;
-	val = RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT
-		| RPM_VREG_PIN_FN_NONE << LDO_PIN_FN_SHIFT;
-	vreg_store(vreg, mask, val, 0, 0);
-
-	/* disable by setting voltage to zero */
-	return _ldo_set_voltage(dev, 0);
-}
-
-/*
- * Optimum mode programming:
- * REGULATOR_MODE_FAST: Go to HPM (highest priority)
- * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
- * votes, else go to LPM
- *
- * Pin ctrl mode voting via regulator set_mode:
- * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
- * go to HPM
- * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
- *
- * Pin ctrl mode takes priority on the RPM when force mode is not set;
- * therefore, pin ctrl bits must be cleared if LPM or HPM is being voted for.
- */
-static int ldo_set_mode(struct regulator_dev *dev, unsigned int mode)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned optimum = vreg->optimum;
-	unsigned pc_vote = vreg->pc_vote;
-	unsigned mode_initialized = vreg->mode_initialized;
-	unsigned mask0 = 0, val0 = 0, mask1 = 0, val1 = 0;
-	int set_hpm = -1, set_pin_control = -1;
-	int peak_uA;
-	int rc = 0;
-
-	peak_uA = MILLI_TO_MICRO((vreg->req[0].value & LDO_PEAK_CURRENT) >>
-		  LDO_PEAK_CURRENT_SHIFT);
-
-	switch (mode) {
-	case REGULATOR_MODE_FAST:
-		set_hpm = 1;
-		set_pin_control = 0;
-		optimum = REGULATOR_MODE_FAST;
-		mode_initialized = 1;
-		break;
-
-	case REGULATOR_MODE_STANDBY:
-		set_hpm = 0;
-		if (pc_vote)
-			set_pin_control = 1;
-		else
-			set_pin_control = 0;
-		optimum = REGULATOR_MODE_STANDBY;
-		mode_initialized = 1;
-		break;
-
-	case REGULATOR_MODE_IDLE:
-		if (pc_vote++)
-			goto done; /* already taken care of */
-
-		if (mode_initialized && optimum == REGULATOR_MODE_FAST) {
-			set_hpm = 1;
-			set_pin_control = 0;
-		} else {
-			set_pin_control = 1;
-		}
-		break;
-
-	case REGULATOR_MODE_NORMAL:
-		if (pc_vote && --pc_vote)
-			goto done; /* already taken care of */
-
-		if (optimum == REGULATOR_MODE_STANDBY)
-			set_hpm = 0;
-		else
-			set_hpm = 1;
-		set_pin_control = 0;
-		break;
-
-	default:
+	if (!vreg->set_points) {
+		vreg_err(vreg, "no voltages available\n");
 		return -EINVAL;
 	}
 
-	if (set_hpm == 1) {
-		/* Make sure that request currents are at HPM level. */
+	if (selector >= vreg->set_points->n_voltages)
+		return 0;
+
+	for (i = 0; i < vreg->set_points->count; i++) {
+		if (selector < vreg->set_points->range[i].n_voltages) {
+			uV = selector * vreg->set_points->range[i].step_uV
+				+ vreg->set_points->range[i].min_uV;
+			break;
+		} else {
+			selector -= vreg->set_points->range[i].n_voltages;
+		}
+	}
+
+	return uV;
+}
+
+static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+	int peak_uA;
+
+	mutex_lock(&vreg->pc_lock);
+
+	peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
+				& vreg->part->ip.mask) >> vreg->part->ip.shift);
+
+	if (mode == config->mode_hpm) {
+		/* Make sure that request currents are in HPM range. */
 		if (peak_uA < vreg_hpm_min_uA(vreg)) {
-			mask0 = LDO_PEAK_CURRENT;
-			mask1 = LDO_AVG_CURRENT;
-			val0 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
-				LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
-			val1 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
-				LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
+			val[vreg->part->ip.word]
+				= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+					<< vreg->part->ip.shift;
+			mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+			if (config->ia_follows_ip) {
+				val[vreg->part->ia.word]
+					|= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+						<< vreg->part->ia.shift;
+				mask[vreg->part->ia.word]
+					|= vreg->part->ia.mask;
+			}
 		}
-	} else if (set_hpm == 0) {
-		/* Make sure that request currents are at LPM level. */
+	} else if (mode == config->mode_lpm) {
+		/* Make sure that request currents are in LPM range. */
 		if (peak_uA > vreg_lpm_max_uA(vreg)) {
-			mask0 = LDO_PEAK_CURRENT;
-			mask1 = LDO_AVG_CURRENT;
-			val0 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
-				LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
-			val1 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
-				LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
+			val[vreg->part->ip.word]
+				= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+					<< vreg->part->ip.shift;
+			mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+			if (config->ia_follows_ip) {
+				val[vreg->part->ia.word]
+					|= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+						<< vreg->part->ia.shift;
+				mask[vreg->part->ia.word]
+					|= vreg->part->ia.mask;
+			}
 		}
+	} else {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		mutex_unlock(&vreg->pc_lock);
+		return -EINVAL;
 	}
 
-	if (set_pin_control == 1) {
-		/* Enable pin control and pin function. */
-		mask0 |= LDO_PIN_CTRL | LDO_PIN_FN;
-		val0 |= vreg->pdata->pin_ctrl << LDO_PIN_CTRL_SHIFT
-			| vreg->pdata->pin_fn << LDO_PIN_FN_SHIFT;
-	} else if (set_pin_control == 0) {
-		/* Clear pin control and pin function*/
-		mask0 |= LDO_PIN_CTRL | LDO_PIN_FN;
-		val0 |= RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT
-			| RPM_VREG_PIN_FN_NONE << LDO_PIN_FN_SHIFT;
-	}
-
-	if (ldo_is_enabled(dev)) {
-		rc = vreg_set(vreg, mask0, val0, mask1, val1, 2);
+	if (vreg->is_enabled) {
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+					vreg->part->request_len);
 	} else {
 		/* Regulator is disabled; store but don't send new request. */
-		rc = vreg_store(vreg, mask0, val0, mask1, val1);
+		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
 	}
+
 	if (rc)
-		return rc;
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+	else
+		vreg->mode = mode;
 
-done:
-	vreg->mode_initialized = mode_initialized;
-	vreg->optimum = optimum;
-	vreg->pc_vote = pc_vote;
+	mutex_unlock(&vreg->pc_lock);
 
-	return 0;
+	return rc;
 }
 
-static unsigned int ldo_get_mode(struct regulator_dev *dev)
+static unsigned int vreg_get_mode(struct regulator_dev *rdev)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
+	struct vreg *vreg = rdev_get_drvdata(rdev);
 
-	if ((vreg->optimum == REGULATOR_MODE_FAST) && vreg->mode_initialized)
-		return REGULATOR_MODE_FAST;
-	else if (vreg->pc_vote)
-		return REGULATOR_MODE_IDLE;
-	else if (vreg->optimum == REGULATOR_MODE_STANDBY)
-		return REGULATOR_MODE_STANDBY;
-	return REGULATOR_MODE_FAST;
+	return vreg->mode;
 }
 
-unsigned int ldo_get_optimum_mode(struct regulator_dev *dev, int input_uV,
-		int output_uV, int load_uA)
+static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode;
 
-	if (MICRO_TO_MILLI(load_uA) > 0) {
-		vreg->req[0].value &= ~LDO_PEAK_CURRENT;
-		vreg->req[0].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
-				     LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
-		vreg->req[1].value &= ~LDO_AVG_CURRENT;
-		vreg->req[1].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
-				       LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
-	} else {
-		/*
-		 * ldo_get_optimum_mode is being called before consumers have
-		 * specified their load currents via regulator_set_optimum_mode.
-		 * Return whatever the existing mode is.
-		 */
-		return ldo_get_mode(dev);
-	}
+	load_uA += vreg->pdata.system_uA;
+
+	mutex_lock(&vreg->pc_lock);
+	SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
+	if (config->ia_follows_ip)
+		SET_PART(vreg, ia,
+			 MICRO_TO_MILLI(saturate_avg_load(vreg, load_uA)));
+	mutex_unlock(&vreg->pc_lock);
 
 	if (load_uA >= vreg->hpm_min_load)
-		return REGULATOR_MODE_FAST;
-	return REGULATOR_MODE_STANDBY;
+		mode = config->mode_hpm;
+	else
+		mode = config->mode_lpm;
+
+	return mode;
 }
 
-static int switch_enable(struct regulator_dev *dev)
+static unsigned int vreg_legacy_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned mask = 0, val = 0;
+	struct vreg *vreg = rdev_get_drvdata(rdev);
 
-	/* reenable pin control if it is in use */
-	if (switch_get_mode(dev) == REGULATOR_MODE_IDLE) {
-		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
-		val = vreg->pdata->pin_ctrl << SWITCH_PIN_CTRL_SHIFT
-			| vreg->pdata->pin_fn << SWITCH_PIN_FN_SHIFT;
+	if (MICRO_TO_MILLI(load_uA) <= 0) {
+		/*
+		 * vreg_legacy_get_optimum_mode is being called before consumers
+		 * have specified their load currents via
+		 * regulator_set_optimum_mode. Return whatever the existing mode
+		 * is.
+		 */
+		return vreg->mode;
 	}
 
-	return vreg_set(rdev_get_drvdata(dev), SWITCH_STATE | mask,
-		(RPM_VREG_STATE_ON << SWITCH_STATE_SHIFT) | val, 0, 0, 1);
-}
-
-static int switch_disable(struct regulator_dev *dev)
-{
-	unsigned mask, val;
-
-	/* turn off pin control */
-	mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
-	val = RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT
-		| RPM_VREG_PIN_FN_NONE << SWITCH_PIN_FN_SHIFT;
-
-	return vreg_set(rdev_get_drvdata(dev), SWITCH_STATE | mask,
-		(RPM_VREG_STATE_OFF << SWITCH_STATE_SHIFT) | val, 0, 0, 1);
-}
-
-static int switch_is_enabled(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	enum rpm_vreg_state state;
-
-	state = (vreg->req[0].value & SWITCH_STATE) >> SWITCH_STATE_SHIFT;
-
-	return state == RPM_VREG_STATE_ON;
+	return vreg_get_optimum_mode(rdev, input_uV, output_uV, load_uA);
 }
 
 /*
- * Pin ctrl mode voting via regulator set_mode:
- * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
- * go to HPM
- * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
+ * Returns the logical pin control enable state because the pin control options
+ * present in the hardware out of restart could be different from those desired
+ * by the consumer.
  */
-static int switch_set_mode(struct regulator_dev *dev, unsigned int mode)
+static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	unsigned pc_vote = vreg->pc_vote;
-	unsigned mask, val;
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->is_enabled_pc;
+}
+
+static int vreg_pin_control_enable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
 	int rc;
 
-	switch (mode) {
-	case REGULATOR_MODE_IDLE:
-		if (pc_vote++)
-			goto done; /* already taken care of */
+	mutex_lock(&vreg->pc_lock);
 
-		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
-		val = vreg->pdata->pin_ctrl << SWITCH_PIN_CTRL_SHIFT
-			| vreg->pdata->pin_fn << SWITCH_PIN_FN_SHIFT;
-		break;
+	val[vreg->part->pc.word]
+		|= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
+	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
 
-	case REGULATOR_MODE_NORMAL:
-		if (--pc_vote)
-			goto done; /* already taken care of */
+	val[vreg->part->pf.word]  |= vreg->pdata.pin_fn << vreg->part->pf.shift;
+	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
 
-		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
-		val = RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT
-			| RPM_VREG_PIN_FN_NONE << SWITCH_PIN_FN_SHIFT;
-		break;
+	if (!vreg->is_enabled)
+		set_enable(vreg, mask, val);
 
-	default:
-		return -EINVAL;
-	}
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
 
-	if (switch_is_enabled(dev)) {
-		rc = vreg_set(vreg, mask, val, 0, 0, 2);
-	} else {
-		/* Regulator is disabled; store but don't send new request. */
-		rc = vreg_store(vreg, mask, val, 0, 0);
-	}
+	if (!rc)
+		vreg->is_enabled_pc = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
 	if (rc)
-		return rc;
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
 
-done:
-	vreg->pc_vote = pc_vote;
-	return 0;
+	return rc;
 }
 
-static unsigned int switch_get_mode(struct regulator_dev *dev)
+static int vreg_pin_control_disable(struct regulator_dev *rdev)
 {
-	struct vreg *vreg = rdev_get_drvdata(dev);
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int pin_fn, rc;
 
-	if (vreg->pc_vote)
-		return REGULATOR_MODE_IDLE;
-	return REGULATOR_MODE_NORMAL;
+	mutex_lock(&vreg->pc_lock);
+
+	val[vreg->part->pc.word]
+		|= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
+	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
+
+	pin_fn = config->pin_func_none;
+	if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+		pin_fn = config->pin_func_sleep_b;
+	val[vreg->part->pf.word]  |= pin_fn << vreg->part->pf.shift;
+	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
+
+	if (!vreg->is_enabled)
+		set_disable(vreg, mask, val);
+
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
+
+	if (!rc)
+		vreg->is_enabled_pc = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
 }
 
-static int ncp_enable(struct regulator_dev *dev)
+static int vreg_enable_time(struct regulator_dev *rdev)
 {
-	return vreg_set(rdev_get_drvdata(dev), NCP_STATE,
-			RPM_VREG_STATE_ON << NCP_STATE_SHIFT, 0, 0, 2);
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->pdata.enable_time;
 }
 
-static int ncp_disable(struct regulator_dev *dev)
-{
-	return vreg_set(rdev_get_drvdata(dev), NCP_STATE,
-			RPM_VREG_STATE_OFF << NCP_STATE_SHIFT, 0, 0, 2);
-}
-
-static int ncp_is_enabled(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-	enum rpm_vreg_state state;
-
-	state = (vreg->req[0].value & NCP_STATE) >> NCP_STATE_SHIFT;
-
-	return state == RPM_VREG_STATE_ON;
-}
-
-static int ncp_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
-			   unsigned *selector)
-{
-	return vreg_set(rdev_get_drvdata(dev), NCP_VOLTAGE,
-			MICRO_TO_MILLI(min_uV) << NCP_VOLTAGE_SHIFT, 0, 0, 2);
-}
-
-static int ncp_get_voltage(struct regulator_dev *dev)
-{
-	struct vreg *vreg = rdev_get_drvdata(dev);
-
-	return MILLI_TO_MICRO((vreg->req[0].value & NCP_VOLTAGE) >>
-			NCP_VOLTAGE_SHIFT);
-}
-
+/* Real regulator operations. */
 static struct regulator_ops ldo_ops = {
-	.enable = ldo_enable,
-	.disable = ldo_disable,
-	.is_enabled = ldo_is_enabled,
-	.set_voltage = ldo_set_voltage,
-	.get_voltage = ldo_get_voltage,
-	.set_mode = ldo_set_mode,
-	.get_optimum_mode = ldo_get_optimum_mode,
-	.get_mode = ldo_get_mode,
+	.enable			= vreg_enable,
+	.disable		= vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.set_mode		= vreg_set_mode,
+	.get_mode		= vreg_get_mode,
+	.get_optimum_mode	= vreg_get_optimum_mode,
+	.enable_time		= vreg_enable_time,
 };
 
 static struct regulator_ops smps_ops = {
-	.enable = smps_enable,
-	.disable = smps_disable,
-	.is_enabled = smps_is_enabled,
-	.set_voltage = smps_set_voltage,
-	.get_voltage = smps_get_voltage,
-	.set_mode = smps_set_mode,
-	.get_optimum_mode = smps_get_optimum_mode,
-	.get_mode = smps_get_mode,
+	.enable			= vreg_enable,
+	.disable		= vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.set_mode		= vreg_set_mode,
+	.get_mode		= vreg_get_mode,
+	.get_optimum_mode	= vreg_get_optimum_mode,
+	.enable_time		= vreg_enable_time,
 };
 
 static struct regulator_ops switch_ops = {
-	.enable = switch_enable,
-	.disable = switch_disable,
-	.is_enabled = switch_is_enabled,
-	.set_mode = switch_set_mode,
-	.get_mode = switch_get_mode,
+	.enable			= vreg_enable,
+	.disable		= vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.enable_time		= vreg_enable_time,
 };
 
 static struct regulator_ops ncp_ops = {
-	.enable = ncp_enable,
-	.disable = ncp_disable,
-	.is_enabled = ncp_is_enabled,
-	.set_voltage = ncp_set_voltage,
-	.get_voltage = ncp_get_voltage,
+	.enable			= vreg_enable,
+	.disable		= vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.enable_time		= vreg_enable_time,
 };
 
-#define DESC(_id, _name, _ops) \
-	[_id] = { \
-		.id = _id, \
-		.name = _name, \
-		.ops = _ops, \
-		.type = REGULATOR_VOLTAGE, \
-		.owner = THIS_MODULE, \
+/* Pin control regulator operations. */
+static struct regulator_ops pin_control_ops = {
+	.enable			= vreg_pin_control_enable,
+	.disable		= vreg_pin_control_disable,
+	.is_enabled		= vreg_pin_control_is_enabled,
+};
+
+struct regulator_ops *vreg_ops[] = {
+	[RPM_REGULATOR_TYPE_LDO]	= &ldo_ops,
+	[RPM_REGULATOR_TYPE_SMPS]	= &smps_ops,
+	[RPM_REGULATOR_TYPE_VS]		= &switch_ops,
+	[RPM_REGULATOR_TYPE_NCP]	= &ncp_ops,
+};
+
+static int __devinit
+rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
+			struct device *dev)
+{
+	struct regulator_desc *rdesc = NULL;
+	struct regulator_dev *rdev;
+	struct vreg *vreg;
+	unsigned pin_ctrl;
+	int id, pin_fn;
+	int rc = 0;
+
+	if (!pdata) {
+		pr_err("platform data missing\n");
+		return -EINVAL;
 	}
 
-static struct regulator_desc vreg_descrip[RPM_VREG_ID_MAX] = {
-	DESC(RPM_VREG_ID_PM8058_L0, "8058_l0", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L1, "8058_l1", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L2, "8058_l2", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L3, "8058_l3", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L4, "8058_l4", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L5, "8058_l5", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L6, "8058_l6", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L7, "8058_l7", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L8, "8058_l8", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L9, "8058_l9", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L10, "8058_l10", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L11, "8058_l11", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L12, "8058_l12", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L13, "8058_l13", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L14, "8058_l14", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L15, "8058_l15", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L16, "8058_l16", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L17, "8058_l17", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L18, "8058_l18", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L19, "8058_l19", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L20, "8058_l20", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L21, "8058_l21", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L22, "8058_l22", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L23, "8058_l23", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L24, "8058_l24", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8058_L25, "8058_l25", &ldo_ops),
+	id = pdata->id;
 
-	DESC(RPM_VREG_ID_PM8058_S0, "8058_s0", &smps_ops),
-	DESC(RPM_VREG_ID_PM8058_S1, "8058_s1", &smps_ops),
-	DESC(RPM_VREG_ID_PM8058_S2, "8058_s2", &smps_ops),
-	DESC(RPM_VREG_ID_PM8058_S3, "8058_s3", &smps_ops),
-	DESC(RPM_VREG_ID_PM8058_S4, "8058_s4", &smps_ops),
+	if (id < config->vreg_id_min || id > config->vreg_id_max) {
+		pr_err("invalid regulator id: %d\n", id);
+		return -ENODEV;
+	}
 
-	DESC(RPM_VREG_ID_PM8058_LVS0, "8058_lvs0", &switch_ops),
-	DESC(RPM_VREG_ID_PM8058_LVS1, "8058_lvs1", &switch_ops),
+	if (!config->is_real_id(pdata->id))
+		id = config->pc_id_to_real_id(pdata->id);
+	vreg = &config->vregs[id];
 
-	DESC(RPM_VREG_ID_PM8058_NCP, "8058_ncp", &ncp_ops),
-
-	DESC(RPM_VREG_ID_PM8901_L0, "8901_l0", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L1, "8901_l1", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L2, "8901_l2", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L3, "8901_l3", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L4, "8901_l4", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L5, "8901_l5", &ldo_ops),
-	DESC(RPM_VREG_ID_PM8901_L6, "8901_l6", &ldo_ops),
-
-	DESC(RPM_VREG_ID_PM8901_S0, "8901_s0", &smps_ops),
-	DESC(RPM_VREG_ID_PM8901_S1, "8901_s1", &smps_ops),
-	DESC(RPM_VREG_ID_PM8901_S2, "8901_s2", &smps_ops),
-	DESC(RPM_VREG_ID_PM8901_S3, "8901_s3", &smps_ops),
-	DESC(RPM_VREG_ID_PM8901_S4, "8901_s4", &smps_ops),
-
-	DESC(RPM_VREG_ID_PM8901_LVS0, "8901_lvs0", &switch_ops),
-	DESC(RPM_VREG_ID_PM8901_LVS1, "8901_lvs1", &switch_ops),
-	DESC(RPM_VREG_ID_PM8901_LVS2, "8901_lvs2", &switch_ops),
-	DESC(RPM_VREG_ID_PM8901_LVS3, "8901_lvs3", &switch_ops),
-
-	DESC(RPM_VREG_ID_PM8901_MVS0, "8901_mvs0", &switch_ops),
-};
-
-static void ldo_init(struct vreg *vreg)
-{
-	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
-
-	/* Allow pf=sleep_b to be specified by platform data. */
-	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
-		pf = RPM_VREG_PIN_FN_SLEEP_B;
-
-	vreg->req[0].value =
-		MICRO_TO_MILLI(saturate_load(vreg->pdata->peak_uA)) <<
-			LDO_PEAK_CURRENT_SHIFT |
-		vreg->pdata->mode << LDO_MODE_SHIFT | pf << LDO_PIN_FN_SHIFT |
-		RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT;
-
-	vreg->req[1].value =
-		vreg->pdata->pull_down_enable << LDO_PULL_DOWN_ENABLE_SHIFT |
-		MICRO_TO_MILLI(saturate_load(vreg->pdata->avg_uA)) <<
-			LDO_AVG_CURRENT_SHIFT;
-}
-
-static void smps_init(struct vreg *vreg)
-{
-	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
-
-	/* Allow pf=sleep_b to be specified by platform data. */
-	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
-		pf = RPM_VREG_PIN_FN_SLEEP_B;
-
-	vreg->req[0].value =
-		MICRO_TO_MILLI(saturate_load(vreg->pdata->peak_uA)) <<
-			SMPS_PEAK_CURRENT_SHIFT |
-		vreg->pdata->mode << SMPS_MODE_SHIFT | pf << SMPS_PIN_FN_SHIFT |
-		RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT;
-
-
-	vreg->req[1].value =
-		vreg->pdata->pull_down_enable << SMPS_PULL_DOWN_ENABLE_SHIFT |
-		MICRO_TO_MILLI(saturate_load(vreg->pdata->avg_uA)) <<
-			SMPS_AVG_CURRENT_SHIFT |
-		vreg->pdata->freq << SMPS_FREQ_SHIFT |
-		0 << SMPS_CLK_SRC_SHIFT;
-}
-
-static void ncp_init(struct vreg *vreg)
-{
-	vreg->req[0].value = vreg->pdata->state << NCP_STATE_SHIFT;
-}
-
-static void switch_init(struct vreg *vreg)
-{
-	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
-
-	/* Allow pf=sleep_b to be specified by platform data. */
-	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
-		pf = RPM_VREG_PIN_FN_SLEEP_B;
-
-	vreg->req[0].value =
-		vreg->pdata->state << SWITCH_STATE_SHIFT |
-		vreg->pdata->pull_down_enable <<
-			SWITCH_PULL_DOWN_ENABLE_SHIFT |
-		pf << SWITCH_PIN_FN_SHIFT |
-		RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT;
-}
-
-static int vreg_init(enum rpm_vreg_id id, struct vreg *vreg)
-{
-	vreg->save_uV = vreg->pdata->default_uV;
-
-	if (vreg->pdata->peak_uA >= vreg->hpm_min_load)
-		vreg->optimum = REGULATOR_MODE_FAST;
+	if (config->is_real_id(pdata->id))
+		rdesc = &vreg->rdesc;
 	else
-		vreg->optimum = REGULATOR_MODE_STANDBY;
+		rdesc = &vreg->rdesc_pc;
 
-	vreg->mode_initialized = 0;
-
-	if (IS_LDO(id))
-		ldo_init(vreg);
-	else if (IS_SMPS(id))
-		smps_init(vreg);
-	else if (IS_NCP(id))
-		ncp_init(vreg);
-	else if (IS_SWITCH(id))
-		switch_init(vreg);
-	else
+	if (vreg->type < 0 || vreg->type > RPM_REGULATOR_TYPE_MAX) {
+		pr_err("%s: invalid regulator type: %d\n",
+			vreg->rdesc.name, vreg->type);
 		return -EINVAL;
+	}
 
-	return 0;
+	mutex_lock(&vreg->pc_lock);
+
+	if (vreg->set_points)
+		rdesc->n_voltages = vreg->set_points->n_voltages;
+	else
+		rdesc->n_voltages = 0;
+
+	rdesc->id    = pdata->id;
+	rdesc->owner = THIS_MODULE;
+	rdesc->type  = REGULATOR_VOLTAGE;
+
+	if (config->is_real_id(pdata->id)) {
+		/*
+		 * Real regulator; do not modify pin control and pin function
+		 * values.
+		 */
+		rdesc->ops = vreg_ops[vreg->type];
+		pin_ctrl = vreg->pdata.pin_ctrl;
+		pin_fn = vreg->pdata.pin_fn;
+		memcpy(&(vreg->pdata), pdata,
+			sizeof(struct rpm_regulator_init_data));
+		vreg->pdata.pin_ctrl = pin_ctrl;
+		vreg->pdata.pin_fn = pin_fn;
+
+		vreg->save_uV = vreg->pdata.default_uV;
+		if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
+			vreg->mode = config->mode_hpm;
+		else
+			vreg->mode = config->mode_lpm;
+
+		/* Initialize the RPM request. */
+		SET_PART(vreg, ip,
+		 MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
+		SET_PART(vreg, fm, vreg->pdata.force_mode);
+		SET_PART(vreg, pm, vreg->pdata.power_mode);
+		SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
+		SET_PART(vreg, ia,
+		   MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
+		SET_PART(vreg, freq, vreg->pdata.freq);
+		SET_PART(vreg, freq_clk_src, 0);
+		SET_PART(vreg, comp_mode, 0);
+		SET_PART(vreg, hpm, 0);
+		if (!vreg->is_enabled_pc) {
+			SET_PART(vreg, pf, config->pin_func_none);
+			SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+		}
+	} else {
+		if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
+		      == RPM_VREG_PIN_CTRL_NONE
+		    && pdata->pin_fn != config->pin_func_sleep_b) {
+			pr_err("%s: no pin control input specified\n",
+				vreg->rdesc.name);
+			mutex_unlock(&vreg->pc_lock);
+			return -EINVAL;
+		}
+		rdesc->ops = &pin_control_ops;
+		vreg->pdata.pin_ctrl = pdata->pin_ctrl;
+		vreg->pdata.pin_fn = pdata->pin_fn;
+
+		/* Initialize the RPM request. */
+		pin_fn = config->pin_func_none;
+		/* Allow pf=sleep_b to be specified by platform data. */
+		if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+			pin_fn = config->pin_func_sleep_b;
+		SET_PART(vreg, pf, pin_fn);
+		SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+	}
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		goto bail;
+
+	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		pr_err("regulator_register failed: %s, rc=%d\n",
+			vreg->rdesc.name, rc);
+		return rc;
+	} else {
+		if (config->is_real_id(pdata->id))
+			vreg->rdev = rdev;
+		else
+			vreg->rdev_pc = rdev;
+	}
+
+bail:
+	if (rc)
+		pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
+
+	return rc;
+}
+
+static void rpm_vreg_set_point_init(void)
+{
+	struct vreg_set_points **set_points;
+	int i, j, temp;
+
+	set_points = config->set_points;
+
+	/* Calculate the number of set points available for each regulator. */
+	for (i = 0; i < config->set_points_len; i++) {
+		temp = 0;
+		for (j = 0; j < set_points[i]->count; j++) {
+			set_points[i]->range[j].n_voltages
+				= (set_points[i]->range[j].max_uV
+					- set_points[i]->range[j].min_uV)
+				   / set_points[i]->range[j].step_uV + 1;
+			temp += set_points[i]->range[j].n_voltages;
+		}
+		set_points[i]->n_voltages = temp;
+	}
 }
 
 static int __devinit rpm_vreg_probe(struct platform_device *pdev)
 {
-	struct regulator_desc *rdesc;
-	struct regulator_dev *rdev;
-	struct vreg *vreg;
-	int rc;
+	struct rpm_regulator_platform_data *platform_data;
+	int rc = 0;
+	int i, id;
 
-	if (pdev == NULL)
+	platform_data = pdev->dev.platform_data;
+	if (!platform_data) {
+		pr_err("rpm-regulator requires platform data\n");
 		return -EINVAL;
-
-	if (pdev->id < 0 || pdev->id >= RPM_VREG_ID_MAX)
-		return -ENODEV;
-
-	vreg = &vregs[pdev->id];
-	vreg->pdata = pdev->dev.platform_data;
-	vreg->id = pdev->id;
-	rdesc = &vreg_descrip[pdev->id];
-
-	rc = vreg_init(pdev->id, vreg);
-	if (rc) {
-		pr_err("%s: vreg_init failed, rc=%d\n", __func__, rc);
-		return rc;
 	}
 
-	/* Disallow idle and normal modes if pin control isn't set. */
-	if ((vreg->pdata->pin_ctrl == RPM_VREG_PIN_CTRL_NONE)
-	    && ((vreg->pdata->pin_fn == RPM_VREG_PIN_FN_ENABLE)
-		    || (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_MODE)))
-		vreg->pdata->init_data.constraints.valid_modes_mask
-			&= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
-
-	rdev = regulator_register(rdesc, &pdev->dev,
-			&vreg->pdata->init_data, vreg);
-	if (IS_ERR(rdev)) {
-		rc = PTR_ERR(rdev);
-		pr_err("%s: id=%d, rc=%d\n", __func__,
-				pdev->id, rc);
-		return rc;
+	if (rpm_version >= 0 && rpm_version <= RPM_VREG_VERSION_MAX
+	    && platform_data->version != rpm_version) {
+		pr_err("rpm version %d does not match previous version %d\n",
+			platform_data->version, rpm_version);
+		return -EINVAL;
 	}
 
-	platform_set_drvdata(pdev, rdev);
+	if (platform_data->version < 0
+		|| platform_data->version > RPM_VREG_VERSION_MAX) {
+		pr_err("rpm version %d is invalid\n", platform_data->version);
+		return -EINVAL;
+	}
+
+	if (rpm_version < 0 || rpm_version > RPM_VREG_VERSION_MAX) {
+		rpm_version = platform_data->version;
+		config = get_config[platform_data->version]();
+		vreg_id_vdd_mem = platform_data->vreg_id_vdd_mem;
+		vreg_id_vdd_dig = platform_data->vreg_id_vdd_dig;
+		if (!config) {
+			pr_err("rpm version %d is not available\n",
+				platform_data->version);
+			return -ENODEV;
+		}
+		if (config->use_legacy_optimum_mode)
+			for (i = 0; i < ARRAY_SIZE(vreg_ops); i++)
+				vreg_ops[i]->get_optimum_mode
+					= vreg_legacy_get_optimum_mode;
+		rpm_vreg_set_point_init();
+		/* First time probed; initialize pin control mutexes. */
+		for (i = 0; i < config->vregs_len; i++)
+			mutex_init(&config->vregs[i].pc_lock);
+	}
+
+	/* Initialize all of the regulators listed in the platform data. */
+	for (i = 0; i < platform_data->num_regulators; i++) {
+		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
+			&pdev->dev);
+		if (rc) {
+			pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
+			goto remove_regulators;
+		}
+	}
+
+	platform_set_drvdata(pdev, platform_data);
+
+	return rc;
+
+remove_regulators:
+	/* Unregister all regulators added before the erroring one. */
+	for (; i >= 0; i--) {
+		id = platform_data->init_data[i].id;
+		if (config->is_real_id(id)) {
+			regulator_unregister(config->vregs[id].rdev);
+			config->vregs[id].rdev = NULL;
+		} else {
+			regulator_unregister(config->vregs[
+				config->pc_id_to_real_id(id)].rdev_pc);
+			config->vregs[id].rdev_pc = NULL;
+		}
+	}
 
 	return rc;
 }
 
 static int __devexit rpm_vreg_remove(struct platform_device *pdev)
 {
-	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct rpm_regulator_platform_data *platform_data;
+	int i, id;
 
+	platform_data = platform_get_drvdata(pdev);
 	platform_set_drvdata(pdev, NULL);
-	regulator_unregister(rdev);
+
+	if (platform_data) {
+		for (i = 0; i < platform_data->num_regulators; i++) {
+			id = platform_data->init_data[i].id;
+			if (config->is_real_id(id)) {
+				regulator_unregister(config->vregs[id].rdev);
+				config->vregs[id].rdev = NULL;
+			} else {
+				regulator_unregister(config->vregs[
+					config->pc_id_to_real_id(id)].rdev_pc);
+				config->vregs[id].rdev_pc = NULL;
+			}
+		}
+	}
 
 	return 0;
 }
@@ -1467,7 +1391,7 @@
 	.probe = rpm_vreg_probe,
 	.remove = __devexit_p(rpm_vreg_remove),
 	.driver = {
-		.name = "rpm-regulator",
+		.name = RPM_REGULATOR_DEV_NAME,
 		.owner = THIS_MODULE,
 	},
 };
@@ -1479,189 +1403,18 @@
 
 static void __exit rpm_vreg_exit(void)
 {
+	int i;
+
 	platform_driver_unregister(&rpm_vreg_driver);
+
+	for (i = 0; i < config->vregs_len; i++)
+		mutex_destroy(&config->vregs[i].pc_lock);
 }
 
 postcore_initcall(rpm_vreg_init);
 module_exit(rpm_vreg_exit);
 
-#define VREG_ID_IS_8058_S0_OR_S1(id) \
-	((id == RPM_VREG_ID_PM8058_S0) || (id == RPM_VREG_ID_PM8058_S1))
-
-static void print_rpm_request(struct vreg *vreg, int set)
-{
-	int v, ip, fm, pc, pf, pd, ia, freq, clk, state;
-
-	/* Suppress 8058_s0 and 8058_s1 printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
-	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
-		return;
-
-	if (IS_LDO(vreg->id)) {
-		v = (vreg->req[0].value & LDO_VOLTAGE) >> LDO_VOLTAGE_SHIFT;
-		ip = (vreg->req[0].value & LDO_PEAK_CURRENT)
-			>> LDO_PEAK_CURRENT_SHIFT;
-		fm = (vreg->req[0].value & LDO_MODE) >> LDO_MODE_SHIFT;
-		pc = (vreg->req[0].value & LDO_PIN_CTRL) >> LDO_PIN_CTRL_SHIFT;
-		pf = (vreg->req[0].value & LDO_PIN_FN) >> LDO_PIN_FN_SHIFT;
-		pd = (vreg->req[1].value & LDO_PULL_DOWN_ENABLE)
-			>> LDO_PULL_DOWN_ENABLE_SHIFT;
-		ia = (vreg->req[1].value & LDO_AVG_CURRENT)
-				>> LDO_AVG_CURRENT_SHIFT;
-
-		pr_info("rpm-regulator: %s %-9s: s=%c, v=%4d mV, ip=%4d "
-			"mA, fm=%s (%d), pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s "
-			"(%d), ia=%4d mA; req[0]={%d, 0x%08X}, "
-			"req[1]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg_descrip[vreg->id].name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), v, ip,
-			(fm == RPM_VREG_MODE_NONE ? "none" :
-				(fm == RPM_VREG_MODE_LPM ? "LPM" :
-				       (fm == RPM_VREG_MODE_HPM ? "HPM" : ""))),
-			fm,
-			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
-			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
-			(pf == RPM_VREG_PIN_FN_NONE ?
-				"none" :
-				(pf == RPM_VREG_PIN_FN_ENABLE ?
-					"on/off" :
-					(pf == RPM_VREG_PIN_FN_MODE ?
-						"HPM/LPM" :
-						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
-							"sleep_b" : "")))),
-			pf, (pd == 1 ? "Y" : "N"), pd, ia,
-			vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-
-	} else if (IS_SMPS(vreg->id)) {
-		v = (vreg->req[0].value & SMPS_VOLTAGE) >> SMPS_VOLTAGE_SHIFT;
-		ip = (vreg->req[0].value & SMPS_PEAK_CURRENT)
-			>> SMPS_PEAK_CURRENT_SHIFT;
-		fm = (vreg->req[0].value & SMPS_MODE) >> SMPS_MODE_SHIFT;
-		pc = (vreg->req[0].value & SMPS_PIN_CTRL)
-			>> SMPS_PIN_CTRL_SHIFT;
-		pf = (vreg->req[0].value & SMPS_PIN_FN) >> SMPS_PIN_FN_SHIFT;
-		pd = (vreg->req[1].value & SMPS_PULL_DOWN_ENABLE)
-			>> SMPS_PULL_DOWN_ENABLE_SHIFT;
-		ia = (vreg->req[1].value & SMPS_AVG_CURRENT)
-			>> SMPS_AVG_CURRENT_SHIFT;
-		freq = (vreg->req[1].value & SMPS_FREQ) >> SMPS_FREQ_SHIFT;
-		clk = (vreg->req[1].value & SMPS_CLK_SRC) >> SMPS_CLK_SRC_SHIFT;
-
-		pr_info("rpm-regulator: %s %-9s: s=%c, v=%4d mV, ip=%4d "
-			"mA, fm=%s (%d), pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s "
-			"(%d), ia=%4d mA, freq=%2d, clk=%d; "
-			"req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg_descrip[vreg->id].name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), v, ip,
-			(fm == RPM_VREG_MODE_NONE ? "none" :
-				(fm == RPM_VREG_MODE_LPM ? "LPM" :
-				       (fm == RPM_VREG_MODE_HPM ? "HPM" : ""))),
-			fm,
-			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
-			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
-			(pf == RPM_VREG_PIN_FN_NONE ?
-				"none" :
-				(pf == RPM_VREG_PIN_FN_ENABLE ?
-					"on/off" :
-					(pf == RPM_VREG_PIN_FN_MODE ?
-						"HPM/LPM" :
-						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
-							"sleep_b" : "")))),
-			pf, (pd == 1 ? "Y" : "N"), pd, ia, freq, clk,
-			vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-
-	} else if (IS_SWITCH(vreg->id)) {
-		state = (vreg->req[0].value & SWITCH_STATE)
-			>> SWITCH_STATE_SHIFT;
-		pd = (vreg->req[0].value & SWITCH_PULL_DOWN_ENABLE)
-			>> SWITCH_PULL_DOWN_ENABLE_SHIFT;
-		pc = (vreg->req[0].value & SWITCH_PIN_CTRL)
-			>> SWITCH_PIN_CTRL_SHIFT;
-		pf = (vreg->req[0].value & SWITCH_PIN_FN)
-			>> SWITCH_PIN_FN_SHIFT;
-
-		pr_info("rpm-regulator: %s %-9s: s=%c, state=%s (%d), "
-			"pd=%s (%d), pc =%s%s%s%s%s (%d), pf=%s (%d); "
-			"req[0]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg_descrip[vreg->id].name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
-			(state == 1 ? "on" : "off"), state,
-			(pd == 1 ? "Y" : "N"), pd,
-			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
-			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
-			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
-			(pf == RPM_VREG_PIN_FN_NONE ?
-				"none" :
-				(pf == RPM_VREG_PIN_FN_ENABLE ?
-					"on/off" :
-					(pf == RPM_VREG_PIN_FN_MODE ?
-						"HPM/LPM" :
-						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
-							"sleep_b" : "")))),
-			pf, vreg->req[0].id, vreg->req[0].value);
-
-	} else if (IS_NCP(vreg->id)) {
-		v = (vreg->req[0].value & NCP_VOLTAGE) >> NCP_VOLTAGE_SHIFT;
-		state = (vreg->req[0].value & NCP_STATE) >> NCP_STATE_SHIFT;
-
-		pr_info("rpm-regulator: %s %-9s: s=%c, v=-%4d mV, "
-			"state=%s (%d); req[0]={%d, 0x%08X}\n",
-			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
-			vreg_descrip[vreg->id].name,
-			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
-			v, (state == 1 ? "on" : "off"), state,
-			vreg->req[0].id, vreg->req[0].value);
-	}
-}
-
-static void print_rpm_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
-			int set, int voter_mV, int aggregate_mV)
-{
-	/* Suppress 8058_s0 and 8058_s1 printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
-	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
-		return;
-
-	pr_info("rpm-regulator: vote received %-9s: voter=%d, set=%c, "
-		"v_voter=%4d mV, v_aggregate=%4d mV\n",
-		vreg_descrip[vreg->id].name, voter, (set == 0 ? 'A' : 'S'),
-		voter_mV, aggregate_mV);
-}
-
-static void print_rpm_duplicate(struct vreg *vreg, int set, int cnt)
-{
-	/* Suppress 8058_s0 and 8058_s1 printing. */
-	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
-	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
-		return;
-
-	if (cnt == 2)
-		pr_info("rpm-regulator: ignored duplicate request %-9s: set=%c;"
-			" req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
-			vreg_descrip[vreg->id].name, (set == 0 ? 'A' : 'S'),
-			vreg->req[0].id, vreg->req[0].value,
-			vreg->req[1].id, vreg->req[1].value);
-	else if (cnt == 1)
-		pr_info("rpm-regulator: ignored duplicate request %-9s: set=%c;"
-			" req[0]={%d, 0x%08X}\n",
-			vreg_descrip[vreg->id].name, (set == 0 ? 'A' : 'S'),
-			vreg->req[0].id, vreg->req[0].value);
-}
-
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("rpm regulator driver");
+MODULE_DESCRIPTION("MSM RPM regulator driver");
 MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:rpm-regulator");
+MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
index d71313d..9653b9a 100644
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ b/arch/arm/mach-msm/sdio_al_test.c
@@ -58,6 +58,7 @@
 #define MAX_XFER_SIZE (16*1024)
 #define SMEM_MAX_XFER_SIZE 0xBC000
 #define A2_MIN_PACKET_SIZE 5
+#define RMNT_PACKET_SIZE (4*1024)
 #define DUN_PACKET_SIZE (2*1024)
 
 #define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
@@ -72,6 +73,12 @@
 
 #define A2_HEADER_OVERHEAD 8
 
+enum rx_process_state {
+	RX_PROCESS_PACKET_INIT,
+	RX_PROCESS_A2_HEADER,
+	RX_PROCESS_PACKET_DATA,
+};
+
 enum sdio_test_case_type {
 	SDIO_TEST_LOOPBACK_HOST,
 	SDIO_TEST_LOOPBACK_CLIENT,
@@ -80,6 +87,7 @@
 	SDIO_TEST_LPM_RANDOM,
 	SDIO_TEST_HOST_SENDER_NO_LP,
 	SDIO_TEST_CLOSE_CHANNEL,
+	SDIO_TEST_A2_VALIDATION,
 	/* The following tests are not part of the 9k tests and should be
 	 * kept last in case new tests are added
 	 */
@@ -228,6 +236,8 @@
 	struct dentry *rpc_qmi_diag_sender_test;
 	struct dentry *smem_test;
 	struct dentry *smem_rpc_test;
+	struct dentry *rmnet_a2_validation_test;
+	struct dentry *dun_a2_validation_test;
 	struct dentry *rmnet_a2_perf_test;
 	struct dentry *dun_a2_perf_test;
 	struct dentry *rmnet_dun_a2_perf_test;
@@ -280,6 +290,8 @@
 	u8 *smem_buf;
 	uint32_t smem_counter;
 
+	struct platform_device *ciq_app_pdev;
+
 	wait_queue_head_t   wait_q;
 	int test_completed;
 	int test_result;
@@ -293,6 +305,7 @@
 /* FORWARD DECLARATIONS */
 static int set_params_loopback_9k(struct test_channel *tch);
 static int set_params_smem_test(struct test_channel *tch);
+static int set_params_a2_validation(struct test_channel *tch);
 static int set_params_a2_perf(struct test_channel *tch);
 static int set_params_8k_sender_no_lp(struct test_channel *tch);
 static int set_params_a2_small_pkts(struct test_channel *tch);
@@ -662,6 +675,140 @@
 	.read = smem_rpc_test_read,
 };
 
+/* RMNET A2 VALIDATION TEST */
+static ssize_t rmnet_a2_validation_test_write(struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_a2_validation_test_read(struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_A2_VALIDATION_TEST\n"
+		 "=========================\n"
+		 "Description:\n"
+		 "In this test, the HOST sends multiple packets to the\n"
+		 "CLIENT and validates the packets loop backed from A2\n"
+		 "for the RMNET channel.\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_a2_validation_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_a2_validation_test_write,
+	.read = rmnet_a2_validation_test_read,
+};
+
+/* DUN A2 VALIDATION TEST */
+static ssize_t dun_a2_validation_test_write(struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t dun_a2_validation_test_read(struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		"\nDUN_A2_VALIDATION_TEST\n"
+		"=========================\n"
+		"Description:\n"
+		"In this test, the HOST sends multiple packets to the\n"
+		"CLIENT and validates the packets loop backed from A2\n"
+		"for the DUN channel.\n\n"
+		"END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations dun_a2_validation_test_ops = {
+	.open = sdio_al_test_open,
+	.write = dun_a2_validation_test_write,
+	.read = dun_a2_validation_test_read,
+};
+
 /* RMNET A2 PERFORMANCE TEST */
 static ssize_t rmnet_a2_perf_test_write(struct file *file,
 					 const char __user *buf,
@@ -2170,50 +2317,64 @@
 				    NULL,
 				    &rpc_qmi_diag_sender_test_ops);
 
-	test_ctx->debug.smem_test =
-		debugfs_create_file("40_smem_test",
+	test_ctx->debug.rmnet_a2_validation_test =
+		debugfs_create_file("30_rmnet_a2_validation_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
-				    &smem_test_ops);
+				    &rmnet_a2_validation_test_ops);
 
-	test_ctx->debug.smem_rpc_test =
-		debugfs_create_file("50_smem_rpc_test",
+	test_ctx->debug.dun_a2_validation_test =
+		debugfs_create_file("40_dun_a2_validation_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
-				    &smem_rpc_test_ops);
+				    &dun_a2_validation_test_ops);
 
 	test_ctx->debug.rmnet_a2_perf_test =
-		debugfs_create_file("60_rmnet_a2_perf_test",
+		debugfs_create_file("50_rmnet_a2_perf_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
 				    &rmnet_a2_perf_test_ops);
 
 	test_ctx->debug.dun_a2_perf_test =
-		debugfs_create_file("70_dun_a2_perf_test",
+		debugfs_create_file("60_dun_a2_perf_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
 				    &dun_a2_perf_test_ops);
 
 	test_ctx->debug.rmnet_dun_a2_perf_test =
-		debugfs_create_file("80_rmnet_dun_a2_perf_test",
+		debugfs_create_file("70_rmnet_dun_a2_perf_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
 				    &rmnet_dun_a2_perf_test_ops);
 
 	test_ctx->debug.rpc_sender_rmnet_a2_perf_test =
-		debugfs_create_file("90_rpc_sender_rmnet_a2_perf_test",
+		debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
 				    &rpc_sender_rmnet_a2_perf_test_ops);
 
+	test_ctx->debug.smem_test =
+		debugfs_create_file("90_smem_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &smem_test_ops);
+
+	test_ctx->debug.smem_rpc_test =
+		debugfs_create_file("100_smem_rpc_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &smem_rpc_test_ops);
+
 	test_ctx->debug.all_channels_test =
-		debugfs_create_file("100_all_channels_test",
+		debugfs_create_file("150_all_channels_test",
 				    S_IRUGO | S_IWUGO,
 				    test_ctx->debug.debug_root,
 				    NULL,
@@ -3019,7 +3180,6 @@
 	if (test_dev->open_channels_counter_to_recv != 0 ||
 	    test_dev->open_channels_counter_to_send != 0) {
 		test_ch->test_completed = 1;
-		test_ch->next_index_in_sent_msg_per_chan = 0;
 		return 0;
 	} else {
 		test_ctx->number_of_active_devices--;
@@ -3056,9 +3216,6 @@
 			test_dev->final_result_per_dev = 0; /* FAILED */
 		}
 
-		test_dev->next_avail_entry_in_array = 0;
-		test_ch->next_index_in_sent_msg_per_chan = 0;
-
 		check_test_completion();
 
 		kfree(test_ch->test_device->lpm_arr);
@@ -3142,8 +3299,7 @@
 		       "thread", __func__);
 	}
 
-	while (test_ch->next_index_in_sent_msg_per_chan <=
-	       test_ch->config_msg.num_packets - 1) {
+	while (1) {
 
 		struct lpm_msg msg;
 		u32 ret = 0;
@@ -3201,6 +3357,14 @@
 
 			test_ch->next_index_in_sent_msg_per_chan++;
 
+			if (test_ch->next_index_in_sent_msg_per_chan ==
+			    test_ch->config_msg.num_packets) {
+				spin_unlock_irqrestore(
+				    &test_dev->lpm_array_lock,
+				    test_dev->lpm_array_lock_flags);
+				break;
+			}
+
 			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
 					       test_dev->lpm_array_lock_flags);
 		}
@@ -4189,6 +4353,285 @@
 
 
 /**
+ * Process Rx Data - Helper for A2 Validation Test
+ * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
+ *
+ * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer.
+ *
+ * @rx_process_packet_state(in/out) :
+ * Current processing state (used to identify what to process
+ * next in a partial packet)
+ *
+ * @rx_packet_size(in/out) :
+ * Number of bytes remaining in the packet to be processed.
+ *
+ * @rx_packet_count(in/out) :
+ * Number of packets processed.
+ */
+static int process_rx_data(struct test_channel *test_ch,
+			   u32 rx_unprocessed_bytes,
+			   int *rx_process_packet_state,
+			   u16 *rx_packet_size,
+			   int *rx_packet_count)
+{
+	u8 *buf = (u8 *)test_ch->buf;
+	int eop = 0;
+	int i = 0;
+	int ret = 0;
+	u32 *ptr = 0;
+	u16 size = 0;
+
+	/* process rx data */
+	while (rx_unprocessed_bytes) {
+		TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n",
+			rx_unprocessed_bytes);
+
+		switch (*rx_process_packet_state) {
+		case RX_PROCESS_PACKET_INIT:
+			/* process the A2 header */
+			TEST_DBG(TEST_MODULE_NAME ": "
+				"RX_PROCESS_PACKET_INIT\n");
+			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+			if (rx_unprocessed_bytes < 4)
+				break;
+
+			i += 4;
+			rx_unprocessed_bytes -= 4;
+
+		case RX_PROCESS_A2_HEADER:
+			/* process the rest of A2 header */
+			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n");
+			*rx_process_packet_state = RX_PROCESS_A2_HEADER;
+			if (rx_unprocessed_bytes < 4)
+				break;
+
+			ptr = (u32 *)&buf[i];
+			/*
+			 * upper 2 bytes of the last 4 bytes of A2 header
+			 * contains the size of the packet
+			 */
+			*rx_packet_size = *ptr >> 0x10;
+
+			i += 4;
+			rx_unprocessed_bytes -= 4;
+
+		case RX_PROCESS_PACKET_DATA:
+			/* process the2_2_ packet data */
+			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA "
+				 "- packet size - %u\n", *rx_packet_size);
+			*rx_process_packet_state = RX_PROCESS_PACKET_DATA;
+
+			size = *rx_packet_size;
+			if (*rx_packet_size <= rx_unprocessed_bytes) {
+				eop = *rx_packet_size;
+				*rx_packet_size = 0;
+			} else {
+				eop = rx_unprocessed_bytes;
+				*rx_packet_size = *rx_packet_size -
+						  rx_unprocessed_bytes;
+			}
+
+			/* no more bytes available to process */
+			if (!eop)
+				break;
+			/*
+			 * end of packet is starting from
+			 * the current position
+			 */
+			eop = eop + i;
+			TEST_DBG(TEST_MODULE_NAME ": size - %u, "
+				 "packet size - %u eop - %d\n",
+				 size, *rx_packet_size, eop);
+
+			/* validate the data */
+			for (; i < eop; i++) {
+				if (buf[i] != (test_ch->rx_bytes % 256)) {
+					pr_err(TEST_MODULE_NAME ": "
+					       "Corrupt data. buf:%u, "
+					       "data:%u\n", buf[i],
+					       test_ch->rx_bytes % 256);
+					ret = -EINVAL;
+					goto err;
+				}
+				rx_unprocessed_bytes--;
+				test_ch->rx_bytes++;
+			}
+
+			/* have more data to be processed */
+			if (*rx_packet_size)
+				break;
+
+			/*
+			 * A2 sends data in 4 byte alignment,
+			 * skip the padding
+			 */
+			if (size % 4) {
+				i += 4 - (size % 4);
+				rx_unprocessed_bytes -= 4 - (size % 4);
+			}
+			*rx_packet_count = *rx_packet_count + 1;
+
+			/* re init the state to process new packet */
+			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+			break;
+		default:
+			pr_err(TEST_MODULE_NAME ": Invalid case: %d\n",
+			       *rx_process_packet_state);
+			ret = -EINVAL;
+			goto err;
+		}
+		TEST_DBG(TEST_MODULE_NAME ": Continue processing "
+			"if more data is available\n");
+	}
+
+err:
+	return ret;
+}
+
+/**
+ * A2 Validation Test
+ * Send packets and validate the returned packets.
+ * Transmit one packet at a time, while process multiple rx
+ * packets in a single transaction.
+ * A transaction is of size min(random number, write_avail).
+ * A packet consists of a min of 1 byte to channel supported max.
+ */
+static void a2_validation_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int tx_packet_count = 0;
+	int rx_packet_count = 0;
+	int initial_rx_packet_count = 0;
+	u32 size = 0;
+	u8 *buf8 = (u8 *)test_ch->buf;
+	int i = 0;
+	int max_packets = test_ch->config_msg.num_packets;
+	u16 tx_packet_size = 0;
+	u16 rx_packet_size = 0;
+	u32 random_num = 0;
+	int rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+
+	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n",
+		test_ch->name);
+
+	/* Wait for the initial rx messages before starting the test. */
+	rx_cleanup(test_ch, &initial_rx_packet_count);
+
+	test_ch->tx_bytes = 0;
+	test_ch->rx_bytes = 0;
+
+	/* Continue till we have transmitted and received all packets */
+	while ((tx_packet_count < max_packets) ||
+	       (rx_packet_count < max_packets)) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		random_num = get_random_int();
+		size = (random_num % test_ch->packet_length) + 1;
+		TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size);
+
+		/*
+		 * wait for data ready event
+		 * use a func to avoid compiler optimizations
+		 */
+		write_avail = sdio_write_avail(test_ch->ch);
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, "
+			"read_avail=%d for chan %s\n",
+			write_avail, read_avail, test_ch->name);
+
+		if ((write_avail == 0) && (read_avail == 0)) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->any_notify_count));
+			atomic_set(&test_ch->any_notify_count, 0);
+		}
+
+		/* Transmit data */
+		write_avail = sdio_write_avail(test_ch->ch);
+		if ((tx_packet_count < max_packets) && (write_avail > 0)) {
+			tx_packet_size = min(size, write_avail) ;
+			TEST_DBG(TEST_MODULE_NAME ": tx size = %u, "
+				"write_avail = %u tx_packet# = %d\n",
+				tx_packet_size, write_avail,
+				tx_packet_count);
+			memset(test_ch->buf, 0, test_ch->buf_size);
+			/* populate the buffer */
+			for (i = 0; i < tx_packet_size; i++) {
+				buf8[i] = test_ch->tx_bytes % 256;
+				test_ch->tx_bytes++;
+			}
+
+			ret = sdio_write(test_ch->ch, test_ch->buf,
+					  tx_packet_size);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
+					" for chan %s\n",
+					-ret, test_ch->name);
+				goto exit_err;
+			}
+			tx_packet_count++;
+		}
+
+		/* Receive data */
+		read_avail = sdio_read_avail(test_ch->ch);
+		if (read_avail > 0) {
+			TEST_DBG(TEST_MODULE_NAME ": rx size = %u, "
+				"rx_packet#=%d.\n",
+				read_avail, rx_packet_count);
+			memset(test_ch->buf, 0, test_ch->buf_size);
+
+			ret = sdio_read(test_ch->ch, test_ch->buf,
+					read_avail);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ": sdio_read "
+					"size %d err=%d for chan %s\n",
+					size, -ret, test_ch->name);
+				goto exit_err;
+			}
+
+			/* Process data */
+			ret = process_rx_data(test_ch, read_avail,
+					      &rx_process_packet_state,
+					      &rx_packet_size,
+					      &rx_packet_count);
+
+			if (ret != 0)
+				goto exit_err;
+		}
+		TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n");
+	}
+
+	if (test_ch->tx_bytes != test_ch->rx_bytes) {
+		pr_err(TEST_MODULE_NAME ": Total number of bytes "
+			"transmitted (%u) does not match the total "
+			"number of bytes received (%u).", test_ch->tx_bytes,
+			test_ch->rx_bytes);
+		goto exit_err;
+	}
+
+	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n",
+		test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
  * sender No loopback Test
  */
 static void sender_no_loopback_test(struct test_channel *test_ch)
@@ -4509,6 +4952,9 @@
 	case SDIO_TEST_MODEM_RESET:
 		modem_reset_test(test_ch);
 		break;
+	case SDIO_TEST_A2_VALIDATION:
+		a2_validation_test(test_ch);
+		break;
 	default:
 		pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n",
 			(int) test_type);
@@ -4847,6 +5293,7 @@
 			LPM_ARRAY_SIZE;
 		test_dev->modem_result_per_dev = 1;
 		tch->modem_result_per_chan = 0;
+		test_dev->next_avail_entry_in_array = 0;
 
 		spin_lock_init(&test_dev->
 			       lpm_array_lock);
@@ -4978,6 +5425,7 @@
 
 		/* in case there are values left from previous tests */
 		tch->notify_counter_per_chan = 0;
+		tch->next_index_in_sent_msg_per_chan = 0;
 
 		memset(tch->buf, 0x00, tch->buf_size);
 		tch->test_result = TEST_NO_RESULT;
@@ -5234,6 +5682,31 @@
 	return 0;
 }
 
+static int set_params_a2_validation(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_A2_VALIDATION;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+
+	if (tch->ch_id == SDIO_RMNT)
+		tch->packet_length = RMNT_PACKET_SIZE;
+	else if (tch->ch_id == SDIO_DUN)
+		tch->packet_length = DUN_PACKET_SIZE;
+	else
+		tch->packet_length = MAX_XFER_SIZE;
+
+	tch->config_msg.num_packets = 10000;
+	tch->config_msg.num_iterations = 1;
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
 static int set_params_smem_test(struct test_channel *tch)
 {
 	if (!tch) {
@@ -5544,6 +6017,34 @@
 
 }
 
+static int sdio_test_channel_ciq_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	if (!pdev)
+		return -ENODEV;
+
+	test_ctx->ciq_app_pdev = platform_device_alloc("SDIO_CIQ_TEST_APP", -1);
+	ret = platform_device_add(test_ctx->ciq_app_pdev);
+		if (ret) {
+			pr_err(MODULE_NAME ":platform_device_add failed, "
+					   "ret=%d\n", ret);
+			return ret;
+		}
+
+	return sdio_test_channel_probe(pdev);
+}
+
+static int sdio_test_channel_ciq_remove(struct platform_device *pdev)
+{
+	if (!pdev)
+		return -ENODEV;
+
+	platform_device_unregister(test_ctx->ciq_app_pdev);
+
+	return sdio_test_channel_remove(pdev);
+}
+
 static struct platform_driver sdio_rpc_drv = {
 	.probe		= sdio_test_channel_probe,
 	.remove		= sdio_test_channel_remove,
@@ -5599,8 +6100,8 @@
 };
 
 static struct platform_driver sdio_ciq_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
+	.probe		= sdio_test_channel_ciq_probe,
+	.remove		= sdio_test_channel_ciq_remove,
 	.driver		= {
 		.name	= "SDIO_CIQ_TEST",
 		.owner	= THIS_MODULE,
diff --git a/arch/arm/mach-msm/sdio_tty_ciq.c b/arch/arm/mach-msm/sdio_tty_ciq.c
index 8f3d776..64b772d 100644
--- a/arch/arm/mach-msm/sdio_tty_ciq.c
+++ b/arch/arm/mach-msm/sdio_tty_ciq.c
@@ -96,7 +96,7 @@
 	.probe		= sdio_tty_test_probe,
 	.remove		= sdio_tty_remove,
 	.driver		= {
-		.name	= "SDIO_CIQ_TEST",
+		.name	= "SDIO_CIQ_TEST_APP",
 		.owner	= THIS_MODULE,
 	},
 };
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 3db19b6..7dec32a 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -591,6 +591,16 @@
 	return ret;
 }
 
+static void smd_reset_edge(struct smd_half_channel *ch, unsigned new_state)
+{
+	if (ch->state != SMD_SS_CLOSED) {
+		ch->state = new_state;
+		ch->fDSR = 0;
+		ch->fCTS = 0;
+		ch->fCD = 0;
+		ch->fSTATE = 1;
+	}
+}
 
 static void smd_channel_reset_state(struct smd_alloc_elm *shared,
 		unsigned new_state, unsigned pid)
@@ -612,20 +622,17 @@
 		if (!shared2)
 			continue;
 
-		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch) ||
-			(pid == SMSM_MODEM &&
-			 pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
-				 &local_ch, &remote_ch))) {
+		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch))
+			smd_reset_edge(local_ch, new_state);
 
-			/* force remote state for processor being restarted */
-			if (local_ch->state != SMD_SS_CLOSED) {
-				local_ch->state = new_state;
-				local_ch->fDSR = 0;
-				local_ch->fCTS = 0;
-				local_ch->fCD = 0;
-				local_ch->fSTATE = 1;
-			}
-		}
+		/*
+		 * ModemFW is in the same subsystem as ModemSW, but has
+		 * separate SMD edges that need to be reset.
+		 */
+		if (pid == SMSM_MODEM &&
+				pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
+				 &local_ch, &remote_ch))
+			smd_reset_edge(local_ch, new_state);
 	}
 }
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 118c90b..8e4d98c 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1071,7 +1071,7 @@
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
 	unsigned long flags;
-	static bool first_boot = true;
+	static DEFINE_PER_CPU(bool, first_boot) = true;
 	struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
 
 	/* Use existing clock_event for cpu 0 */
@@ -1081,11 +1081,11 @@
 	global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
 	__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 
-	if (first_boot) {
+	if (__get_cpu_var(first_boot)) {
 		__raw_writel(0, clock->regbase  + TIMER_ENABLE);
 		__raw_writel(0, clock->regbase + TIMER_CLEAR);
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
-		first_boot = false;
+		__get_cpu_var(first_boot) = false;
 	}
 	evt->irq = clock->irq.irq;
 	evt->name = "local_timer";
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 25a4260..95a7079 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -28,6 +28,7 @@
 
 static void __iomem *l2x0_base;
 static uint32_t aux_ctrl_save;
+static uint32_t data_latency_ctrl;
 static DEFINE_SPINLOCK(l2x0_lock);
 static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
 static uint32_t l2x0_size;
@@ -413,6 +414,7 @@
 {
 	/* Save aux control register value */
 	aux_ctrl_save = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+	data_latency_ctrl = readl_relaxed(l2x0_base + L2X0_DATA_LATENCY_CTRL);
 	/* Flush all cache */
 	l2x0_flush_all();
 	/* Disable the cache */
@@ -430,6 +432,8 @@
 
 		/* Restore aux control register value */
 		writel_relaxed(aux_ctrl_save, l2x0_base + L2X0_AUX_CTRL);
+		writel_relaxed(data_latency_ctrl, l2x0_base +
+				L2X0_DATA_LATENCY_CTRL);
 
 		/* Invalidate the cache */
 		l2x0_inv_all();
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 4b5e6be..ca501ef 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -658,7 +658,14 @@
 			else if (!page_count(page))
 				free_pages++;
 			page++;
+#ifdef CONFIG_SPARSEMEM
+			pfn1++;
+			if (!(pfn1 % PAGES_PER_SECTION))
+				page = pfn_to_page(pfn1);
+		} while (pfn1 < pfn2);
+#else
 		} while (page < end);
+#endif
 	}
 
 	/*
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 2719891..8f8ba03 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -42,6 +42,8 @@
 	struct wake_lock wake_lock_tx;
 	struct wake_lock wake_lock_rx;
 	struct timer_list rx_q_timer;
+	struct tasklet_struct hci_event_task;
+	struct tasklet_struct hci_data_task;
 };
 struct hci_smd_data hs;
 
@@ -306,7 +308,7 @@
 
 	switch (event) {
 	case SMD_EVENT_DATA:
-		hci_smd_recv_event(event);
+		tasklet_hi_schedule(&hs.hci_event_task);
 		break;
 	case SMD_EVENT_OPEN:
 		hci_smd_open(hdev);
@@ -329,7 +331,7 @@
 
 	switch (event) {
 	case SMD_EVENT_DATA:
-		hci_smd_recv_data(event);
+		tasklet_hi_schedule(&hs.hci_data_task);
 		break;
 	case SMD_EVENT_OPEN:
 		hci_smd_open(hdev);
@@ -364,6 +366,11 @@
 	hdev->destruct = hci_smd_destruct;
 	hdev->owner = THIS_MODULE;
 
+	tasklet_init(&hsmd->hci_event_task,
+			hci_smd_recv_event, (unsigned long) hsmd);
+	tasklet_init(&hsmd->hci_data_task,
+			hci_smd_recv_data, (unsigned long) hsmd);
+
 	wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND, "msm_smd_Rx");
 	wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND, "msm_smd_Tx");
 	/*
@@ -414,6 +421,8 @@
 
 	/*Destroy the timer used to monitor the Rx queue for emptiness */
 	del_timer_sync(&hs.rx_q_timer);
+	tasklet_kill(&hs.hci_event_task);
+	tasklet_kill(&hs.hci_data_task);
 }
 
 static int hci_smd_init(void)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 5c685c3..292fbc3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -46,6 +46,7 @@
 #define MSG_MASK_SIZE 8000
 #define LOG_MASK_SIZE 8000
 #define EVENT_MASK_SIZE 1000
+#define USER_SPACE_DATA 8000
 #define PKT_SIZE 4096
 #define MAX_EQUIP_ID 12
 
@@ -157,6 +158,7 @@
 	unsigned char *buf_in_wcnss_cntl;
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
+	unsigned char *user_space_data;
 	smd_channel_t *ch;
 	smd_channel_t *ch_cntl;
 	smd_channel_t *chqdsp;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c9a9d57..6fa043c 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -355,6 +355,8 @@
 		mutex_lock(&driver->diagchar_mutex);
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
+		if (driver->logging_mode == UART_MODE)
+			driver->logging_mode = MEMORY_DEVICE_MODE;
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -363,12 +365,14 @@
 			driver->in_busy_2 = 1;
 			driver->in_busy_qdsp_1 = 1;
 			driver->in_busy_qdsp_2 = 1;
+			driver->in_busy_wcnss = 1;
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
 			driver->in_busy_1 = 0;
 			driver->in_busy_2 = 0;
 			driver->in_busy_qdsp_1 = 0;
 			driver->in_busy_qdsp_2 = 0;
+			driver->in_busy_wcnss = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -376,6 +380,9 @@
 			if (driver->chqdsp)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_qdsp_work));
+			if (driver->ch_wcnss)
+				queue_work(driver->diag_wq,
+					&(driver->diag_read_smd_wcnss_work));
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
@@ -391,6 +398,7 @@
 			driver->in_busy_2 = 0;
 			driver->in_busy_qdsp_2 = 0;
 			driver->in_busy_qdsp_2 = 0;
+			driver->in_busy_wcnss = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -398,6 +406,9 @@
 			if (driver->chqdsp)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_qdsp_work));
+			if (driver->ch_wcnss)
+				queue_work(driver->diag_wq,
+					&(driver->diag_read_smd_wcnss_work));
 		} else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
 								== USB_MODE)
 			diagfwd_connect();
@@ -426,10 +437,10 @@
 				  driver->data_ready[index]);
 	mutex_lock(&driver->diagchar_mutex);
 
-	if ((driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE) && (driver->
+	if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
 					logging_mode == MEMORY_DEVICE_MODE)) {
 		/*Copy the type of data being passed*/
-		data_type = driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE;
+		data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
 		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
 		/* place holder for number of data field */
 		ret += 4;
@@ -496,8 +507,7 @@
 					 driver->write_ptr_2->length);
 			driver->in_busy_2 = 0;
 		}
-
-		/* copy q6 data */
+		/* copy lpass data */
 		if (driver->in_busy_qdsp_1 == 1) {
 			num_data++;
 			/*Copy the length of data being passed*/
@@ -520,23 +530,37 @@
 					write_ptr_qdsp_2->length);
 			driver->in_busy_qdsp_2 = 0;
 		}
-
+		/* copy wncss data */
+		if (driver->in_busy_wcnss == 1) {
+			num_data++;
+			/*Copy the length of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+				 (driver->write_ptr_wcnss->length), 4);
+			/*Copy the actual data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
+							buf_in_wcnss),
+					 driver->write_ptr_wcnss->length);
+			driver->in_busy_wcnss = 0;
+		}
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
-		driver->data_ready[index] ^= MEMORY_DEVICE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
 		if (driver->ch)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_work));
 		if (driver->chqdsp)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_qdsp_work));
+		if (driver->ch_wcnss)
+			queue_work(driver->diag_wq,
+					 &(driver->diag_read_smd_wcnss_work));
 		APPEND_DEBUG('n');
 		goto exit;
-	} else if (driver->data_ready[index] & MEMORY_DEVICE_LOG_TYPE) {
+	} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
 		/* In case, the thread wakes up and the logging mode is
 		not memory device any more, the condition needs to be cleared */
-		driver->data_ready[index] ^= MEMORY_DEVICE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
 	}
 
 	if (driver->data_ready[index] & DEINIT_TYPE) {
@@ -612,21 +636,27 @@
 #endif /* DIAG over USB */
 	/* Get the packet type F3/log/event/Pkt response */
 	err = copy_from_user((&pkt_type), buf, 4);
-	/*First 4 bytes indicate the type of payload - ignore these */
+	/* First 4 bytes indicate the type of payload - ignore these */
 	payload_size = count - 4;
 
-	if (pkt_type == MEMORY_DEVICE_LOG_TYPE) {
-		if (!mask_request_validate((unsigned char *)buf)) {
-			printk(KERN_ALERT "mask request Invalid ..cannot send to modem \n");
-			return -EFAULT;
+	if (pkt_type == USER_SPACE_LOG_TYPE) {
+		err = copy_from_user(driver->user_space_data, buf + 4,
+							 payload_size);
+		/* Check masks for On-Device logging */
+		if (pkt_type == USER_SPACE_LOG_TYPE) {
+			if (!mask_request_validate((unsigned char *)buf)) {
+				pr_alert("diag: mask request Invalid\n");
+				return -EFAULT;
+			}
 		}
 		buf = buf + 4;
 #ifdef DIAG_DEBUG
-		pr_debug("diag: masks: %d\n", payload_size);
+		pr_debug("diag: user space data %d\n", payload_size);
 		for (i = 0; i < payload_size; i++)
 			printk(KERN_DEBUG "\t %x", *(((unsigned char *)buf)+i));
 #endif
-		diag_process_hdlc((void *)buf, payload_size);
+		diag_process_hdlc((void *)(driver->user_space_data),
+							 payload_size);
 		return 0;
 	}
 
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f9664c4..e49d57c 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -61,7 +61,8 @@
 		driver->write_ptr_1->length = (int)(enc.dest - \
 						(void *)(driver->buf_in_1)); \
 		driver->in_busy_1 = 1;					\
-		usb_diag_write(driver->legacy_ch, driver->write_ptr_1);	\
+		diag_device_write(driver->buf_in_1, MODEM_DATA, \
+						 driver->write_ptr_1); \
 		memset(driver->apps_rsp_buf, '\0', 500);		\
 	}								\
 } while (0)
@@ -153,7 +154,7 @@
 						 driver->logging_process_id)
 				break;
 		if (i < driver->num_clients) {
-			driver->data_ready[i] |= MEMORY_DEVICE_LOG_TYPE;
+			driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
 			wake_up_interruptible(&driver->wait_q);
 		} else
 			return -EINVAL;
@@ -982,13 +983,15 @@
 {
 	printk(KERN_DEBUG "diag: USB disconnected\n");
 	driver->usb_connected = 0;
-	driver->in_busy_1 = 1;
-	driver->in_busy_2 = 1;
-	driver->in_busy_qdsp_1 = 1;
-	driver->in_busy_qdsp_2 = 1;
-	driver->in_busy_wcnss = 1;
 	driver->debug_flag = 1;
 	usb_diag_free_req(driver->legacy_ch);
+	if (driver->logging_mode == USB_MODE) {
+		driver->in_busy_1 = 1;
+		driver->in_busy_2 = 1;
+		driver->in_busy_qdsp_1 = 1;
+		driver->in_busy_qdsp_2 = 1;
+		driver->in_busy_wcnss = 1;
+	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
 		if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
@@ -1235,6 +1238,10 @@
 	if (driver->hdlc_buf == NULL
 	    && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
 		goto err;
+	if (driver->user_space_data == NULL)
+		driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
+		if (driver->user_space_data == NULL)
+			goto err;
 	if (driver->msg_masks == NULL
 	    && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
 					     GFP_KERNEL)) == NULL)
@@ -1350,6 +1357,7 @@
 		kfree(driver->write_ptr_wcnss);
 		kfree(driver->usb_read_ptr);
 		kfree(driver->apps_rsp_buf);
+		kfree(driver->user_space_data);
 		if (driver->diag_wq)
 			destroy_workqueue(driver->diag_wq);
 }
@@ -1391,5 +1399,6 @@
 	kfree(driver->write_ptr_wcnss);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
+	kfree(driver->user_space_data);
 	destroy_workqueue(driver->diag_wq);
 }
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index 8be9f46..f3873aa 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -124,10 +124,11 @@
 
 int diagfwd_disconnect_sdio(void)
 {
-	driver->in_busy_sdio = 1;
 	usb_diag_free_req(driver->mdm_ch);
-	if (driver->sdio_ch && (driver->logging_mode == USB_MODE))
+	if (driver->sdio_ch && (driver->logging_mode == USB_MODE)) {
+		driver->in_busy_sdio = 1;
 		diag_sdio_close();
+	}
 	return 0;
 }
 
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index de75935..a9dfc60 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -587,6 +587,80 @@
 	return handle;
 }
 
+static int check_vaddr_bounds(unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = current->active_mm;
+	struct vm_area_struct *vma;
+	int ret = 1;
+
+	if (end < start)
+		goto out;
+
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, start);
+	if (vma && vma->vm_start < end) {
+		if (start < vma->vm_start)
+			goto out_up;
+		if (end > vma->vm_end)
+			goto out_up;
+		ret = 0;
+	}
+
+out_up:
+	up_read(&mm->mmap_sem);
+out:
+	return ret;
+}
+
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+			void *uaddr, unsigned long offset, unsigned long len,
+			unsigned int cmd)
+{
+	struct ion_buffer *buffer;
+	unsigned long start, end;
+	int ret = -EINVAL;
+
+	mutex_lock(&client->lock);
+	if (!ion_handle_validate(client, handle)) {
+		pr_err("%s: invalid handle passed to do_cache_op.\n",
+		       __func__);
+		mutex_unlock(&client->lock);
+		return -EINVAL;
+	}
+	buffer = handle->buffer;
+	mutex_lock(&buffer->lock);
+
+	if (ION_IS_CACHED(buffer->flags)) {
+		ret = 0;
+		goto out;
+	}
+
+	if (!handle->buffer->heap->ops->cache_op) {
+		pr_err("%s: cache_op is not implemented by this heap.\n",
+		       __func__);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	start = (unsigned long) uaddr;
+	end = (unsigned long) uaddr + len;
+
+	if (check_vaddr_bounds(start, end)) {
+		pr_err("%s: virtual address %p is out of bounds\n",
+			__func__, uaddr);
+		goto out;
+	}
+
+	ret = buffer->heap->ops->cache_op(buffer->heap, buffer, uaddr,
+						offset, len, cmd);
+
+out:
+	mutex_unlock(&buffer->lock);
+	mutex_unlock(&client->lock);
+	return ret;
+
+}
+
 static const struct file_operations ion_share_fops;
 
 struct ion_handle *ion_import_fd(struct ion_client *client, int fd)
@@ -1075,6 +1149,20 @@
 			return -EFAULT;
 		return dev->custom_ioctl(client, data.cmd, data.arg);
 	}
+	case ION_IOC_CLEAN_CACHES:
+	case ION_IOC_INV_CACHES:
+	case ION_IOC_CLEAN_INV_CACHES:
+	{
+		struct ion_flush_data data;
+
+		if (copy_from_user(&data, (void __user *)arg,
+				sizeof(struct ion_flush_data)))
+			return -EFAULT;
+
+		return ion_do_cache_op(client, data.handle, data.vaddr,
+					data.offset, data.length, cmd);
+
+	}
 	default:
 		return -ENOTTY;
 	}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ed9b9b5..44536c8 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -100,7 +100,7 @@
 				   struct ion_buffer *buffer,
 				   unsigned long flags)
 {
-	if (flags & ION_SET_CACHE(CACHED))
+	if (ION_IS_CACHED(flags))
 		return ioremap_cached(buffer->priv_phys, buffer->size);
 	else
 		return ioremap(buffer->priv_phys, buffer->size);
@@ -117,7 +117,7 @@
 int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			       struct vm_area_struct *vma, unsigned long flags)
 {
-	if (flags & ION_SET_CACHE(CACHED))
+	if (ION_IS_CACHED(flags))
 		return remap_pfn_range(vma, vma->vm_start,
 			       __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
 			       buffer->size,
@@ -129,6 +129,32 @@
 					pgprot_noncached(vma->vm_page_prot));
 }
 
+int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
+			void *vaddr, unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	unsigned long vstart, pstart;
+
+	pstart = buffer->priv_phys + offset;
+	vstart = (unsigned long)vaddr;
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		clean_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_INV_CACHES:
+		invalidate_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		clean_and_invalidate_caches(vstart, length, pstart);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static struct ion_heap_ops carveout_heap_ops = {
 	.allocate = ion_carveout_heap_allocate,
 	.free = ion_carveout_heap_free,
@@ -136,6 +162,7 @@
 	.map_user = ion_carveout_heap_map_user,
 	.map_kernel = ion_carveout_heap_map_kernel,
 	.unmap_kernel = ion_carveout_heap_unmap_kernel,
+	.cache_op = ion_carveout_cache_ops,
 };
 
 struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 581abe5..fd5c125 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -101,6 +101,9 @@
 	void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
 	int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
 			 struct vm_area_struct *vma, unsigned long flags);
+	int (*cache_op)(struct ion_heap *heap, struct ion_buffer *buffer,
+			void *vaddr, unsigned int offset,
+			unsigned int length, unsigned int cmd);
 };
 
 /**
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index b34b455..5609b72 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include "ion_priv.h"
+#include <mach/memory.h>
 
 static int ion_system_heap_allocate(struct ion_heap *heap,
 				     struct ion_buffer *buffer,
@@ -78,7 +79,7 @@
 				 struct ion_buffer *buffer,
 				 unsigned long flags)
 {
-	if (flags & ION_SET_CACHE(CACHED))
+	if (ION_IS_CACHED(flags))
 		return buffer->priv_virt;
 	else {
 		pr_err("%s: cannot map system heap uncached\n", __func__);
@@ -94,7 +95,7 @@
 int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			     struct vm_area_struct *vma, unsigned long flags)
 {
-	if (flags & ION_SET_CACHE(CACHED))
+	if (ION_IS_CACHED(flags))
 		return remap_vmalloc_range(vma, buffer->priv_virt,
 						vma->vm_pgoff);
 	else {
@@ -103,6 +104,51 @@
 	}
 }
 
+int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
+			void *vaddr, unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	unsigned long vstart, pstart;
+	void *vtemp;
+	unsigned long ln = 0;
+	void (*op)(unsigned long, unsigned long, unsigned long);
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		op = clean_caches;
+		break;
+	case ION_IOC_INV_CACHES:
+		op = invalidate_caches;
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		op = clean_and_invalidate_caches;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (vtemp = buffer->priv_virt + offset,
+	     vstart = (unsigned long) vaddr;
+			ln < length;
+			vtemp += PAGE_SIZE, ln += PAGE_SIZE,
+			vstart += PAGE_SIZE) {
+		pstart = page_to_phys(vmalloc_to_page(vtemp));
+		/*
+		 * If vmalloc -> page -> phys is returning NULL, something
+		 * has really gone wrong...
+		 */
+		if (!pstart) {
+			WARN(1, "Could not translate %p to physical address\n",
+				vtemp);
+			return -EINVAL;
+		}
+
+		op(vstart, PAGE_SIZE, pstart);
+	}
+
+	return 0;
+}
+
 static struct ion_heap_ops vmalloc_ops = {
 	.allocate = ion_system_heap_allocate,
 	.free = ion_system_heap_free,
@@ -111,6 +157,7 @@
 	.map_kernel = ion_system_heap_map_kernel,
 	.unmap_kernel = ion_system_heap_unmap_kernel,
 	.map_user = ion_system_heap_map_user,
+	.cache_op = ion_system_heap_cache_ops,
 };
 
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
@@ -176,7 +223,7 @@
 {
 	unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
 
-	if (flags & ION_SET_CACHE(CACHED))
+	if (ION_IS_CACHED(flags))
 		return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start,
 			       vma->vm_page_prot);
@@ -186,6 +233,39 @@
 	}
 }
 
+int ion_system_contig_heap_cache_ops(struct ion_heap *heap,
+			struct ion_buffer *buffer, void *vaddr,
+			unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	unsigned long vstart, pstart;
+
+	pstart = virt_to_phys(buffer->priv_virt) + offset;
+	if (!pstart) {
+		WARN(1, "Could not do virt to phys translation on %p\n",
+			buffer->priv_virt);
+		return -EINVAL;
+	}
+
+	vstart = (unsigned long) vaddr;
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		clean_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_INV_CACHES:
+		invalidate_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		clean_and_invalidate_caches(vstart, length, pstart);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static struct ion_heap_ops kmalloc_ops = {
 	.allocate = ion_system_contig_heap_allocate,
 	.free = ion_system_contig_heap_free,
@@ -195,6 +275,7 @@
 	.map_kernel = ion_system_heap_map_kernel,
 	.unmap_kernel = ion_system_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
+	.cache_op = ion_system_contig_heap_cache_ops,
 };
 
 struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 526c971..4207def 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -66,9 +66,6 @@
 	 | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)	\
 	 | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
 
-/* max msecs to wait for gpu to finish its operation(s) */
-#define MAX_WAITGPU_SECS (HZ + HZ/2)
-
 static const struct kgsl_functable adreno_functable;
 
 static struct adreno_device device_3d0 = {
@@ -429,6 +426,8 @@
 	adreno_dev = ADRENO_DEVICE(device);
 	device->parentdev = &pdev->dev;
 
+	adreno_dev->wait_timeout = 10000; /* default value in milliseconds */
+
 	init_completion(&device->recovery_gate);
 
 	status = adreno_ringbuffer_init(device);
@@ -835,7 +834,9 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 	unsigned int rbbm_status;
-	unsigned long wait_time = jiffies + MAX_WAITGPU_SECS;
+	unsigned long wait_timeout =
+		msecs_to_jiffies(adreno_dev->wait_timeout);
+	unsigned long wait_time = jiffies + wait_timeout;
 
 	kgsl_cffdump_regpoll(device->id, REG_RBBM_STATUS << 2,
 		0x00000000, 0x80000000);
@@ -855,7 +856,7 @@
 	}
 
 	/* now, wait for the GPU to finish its operations */
-	wait_time = jiffies + MAX_WAITGPU_SECS;
+	wait_time = jiffies + wait_timeout;
 	while (time_before(jiffies, wait_time)) {
 		adreno_regread(device, REG_RBBM_STATUS, &rbbm_status);
 		if (rbbm_status == 0x110)
@@ -865,7 +866,7 @@
 err:
 	KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
 	if (!adreno_dump_and_recover(device)) {
-		wait_time = jiffies + MAX_WAITGPU_SECS;
+		wait_time = jiffies + wait_timeout;
 		goto retry;
 	}
 	return -ETIMEDOUT;
@@ -1073,6 +1074,10 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
+	/* Don't wait forever, set a max value for now */
+	if (msecs == -1)
+		msecs = adreno_dev->wait_timeout;
+
 	if (timestamp != adreno_dev->ringbuffer.timestamp &&
 		timestamp_cmp(timestamp,
 		adreno_dev->ringbuffer.timestamp)) {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 94b96a1..0098045 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -64,6 +64,7 @@
 	struct adreno_ringbuffer ringbuffer;
 	unsigned int mharb;
 	struct adreno_gpudev *gpudev;
+	unsigned int wait_timeout;
 };
 
 struct adreno_gpudev {
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 8a7ab35..064b05e 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1520,6 +1520,7 @@
 
 	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
 		KGSL_CMD_WARN(rb->device, "ringbuffer ib1/rb interrupt\n");
+		queue_work(device->work_queue, &device->ts_expired_ws);
 		wake_up_interruptible_all(&device->wait_queue);
 		atomic_notifier_call_chain(&(device->ts_notifier_list),
 					   device->id,
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b917849..c878a2c 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -421,6 +421,8 @@
 
 void adreno_debugfs_init(struct kgsl_device *device)
 {
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
 	if (!device->d_debugfs || IS_ERR(device->d_debugfs))
 		return;
 
@@ -436,6 +438,8 @@
 			    &kgsl_mh_debug_fops);
 	debugfs_create_file("cff_dump", 0644, device->d_debugfs, device,
 			    &kgsl_cff_dump_enable_fops);
+	debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
+		&adreno_dev->wait_timeout);
 
 	/* Create post mortem control files */
 
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5d20d9b..165bbbf 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -180,35 +180,28 @@
 	list_add_tail(&entry->list, &device->memqueue);
 }
 
-static void kgsl_memqueue_drain(struct kgsl_device *device)
+static void kgsl_timestamp_expired(struct work_struct *work)
 {
+	struct kgsl_device *device = container_of(work, struct kgsl_device,
+		ts_expired_ws);
 	struct kgsl_mem_entry *entry, *entry_tmp;
 	uint32_t ts_processed;
 
-	BUG_ON(!mutex_is_locked(&device->mutex));
+	mutex_lock(&device->mutex);
 
 	/* get current EOP timestamp */
 	ts_processed = device->ftbl->readtimestamp(device,
 		KGSL_TIMESTAMP_RETIRED);
 
+	/* Flush the freememontimestamp queue */
 	list_for_each_entry_safe(entry, entry_tmp, &device->memqueue, list) {
-		KGSL_MEM_INFO(device,
-			"ts_processed %d ts_free %d gpuaddr %x)\n",
-			ts_processed, entry->free_timestamp,
-			entry->memdesc.gpuaddr);
 		if (!timestamp_cmp(ts_processed, entry->free_timestamp))
 			break;
 
 		list_del(&entry->list);
 		kgsl_mem_entry_put(entry);
 	}
-}
 
-static void kgsl_memqueue_drain_unlocked(struct kgsl_device *device)
-{
-	mutex_lock(&device->mutex);
-	kgsl_check_suspended(device);
-	kgsl_memqueue_drain(device);
 	mutex_unlock(&device->mutex);
 }
 
@@ -767,16 +760,10 @@
 
 	dev_priv->device->active_cnt++;
 
-	/* Don't wait forever, set a max value for now */
-	if (param->timeout == -1)
-		param->timeout = 10 * MSEC_PER_SEC;
-
 	result = dev_priv->device->ftbl->waittimestamp(dev_priv->device,
 					param->timestamp,
 					param->timeout);
 
-	kgsl_memqueue_drain(dev_priv->device);
-
 	/* Fire off any pending suspend operations that are in flight */
 
 	INIT_COMPLETION(dev_priv->device->suspend_gate);
@@ -954,7 +941,6 @@
 	if (entry) {
 		kgsl_memqueue_freememontimestamp(dev_priv->device, entry,
 					param->timestamp, param->type);
-		kgsl_memqueue_drain(dev_priv->device);
 	} else {
 		KGSL_DRV_ERR(dev_priv->device,
 			"invalid gpuaddr %08x\n", param->gpuaddr);
@@ -1066,9 +1052,6 @@
 	if (!kgsl_mmu_enabled())
 		return -ENODEV;
 
-	/* Make sure all pending freed memory is collected */
-	kgsl_memqueue_drain_unlocked(dev_priv->device);
-
 	if (!param->hostptr) {
 		KGSL_CORE_ERR("invalid hostptr %x\n", param->hostptr);
 		result = -EINVAL;
@@ -1387,8 +1370,6 @@
 	if (entry == NULL)
 		return -ENOMEM;
 
-	kgsl_memqueue_drain_unlocked(dev_priv->device);
-
 	if (_IOC_SIZE(cmd) == sizeof(struct kgsl_sharedmem_from_pmem))
 		memtype = KGSL_USER_MEM_TYPE_PMEM;
 	else
@@ -1528,9 +1509,6 @@
 	if (entry == NULL)
 		return -ENOMEM;
 
-	/* Make sure all pending freed memory is collected */
-	kgsl_memqueue_drain_unlocked(dev_priv->device);
-
 	result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
 		param->size, param->flags);
 
@@ -1918,6 +1896,7 @@
 		goto err_devlist;
 
 	INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
+	INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
 
 	INIT_LIST_HEAD(&device->memqueue);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 10e345a..2f369ed 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -165,6 +165,7 @@
 	struct kgsl_pwrscale pwrscale;
 	struct kobject pwrscale_kobj;
 	struct pm_qos_request_list pm_qos_req_dma;
+	struct work_struct ts_expired_ws;
 };
 
 struct kgsl_context {
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 37ba621..61a3edb 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -234,6 +234,7 @@
 			count &= 255;
 			z180_dev->timestamp += count;
 
+			queue_work(device->work_queue, &device->ts_expired_ws);
 			wake_up_interruptible(&device->wait_queue);
 
 			atomic_notifier_call_chain(
@@ -806,6 +807,11 @@
 				unsigned int msecs)
 {
 	int status = -EINVAL;
+
+	/* Don't wait forever, set a max (10 sec) value for now */
+	if (msecs == -1)
+		msecs = 10 * MSEC_PER_SEC;
+
 	mutex_unlock(&device->mutex);
 	status = z180_wait(device, timestamp, msecs);
 	mutex_lock(&device->mutex);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 8f2a942..00c7633 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -335,8 +335,15 @@
 			else /* 1-bit delay before we check for bus busy */
 				udelay(dev->one_bit_t);
 		}
-		if (retries++ == 1000)
-			udelay(100);
+		if (retries++ == 1000) {
+			/*
+			 * Wait for FIFO number of bytes to be absolutely sure
+			 * that I2C write state machine is not idle. Each byte
+			 * takes 9 clock cycles. (8 bits + 1 ack)
+			 */
+			usleep_range((dev->one_bit_t * (dev->out_fifo_sz * 9)),
+				(dev->one_bit_t * (dev->out_fifo_sz * 9)));
+		}
 	}
 	qup_print_status(dev);
 	return -ETIMEDOUT;
@@ -520,7 +527,7 @@
 		 */
 		if (rem > 1) {
 			struct i2c_msg *next = msg + 1;
-			if (next->addr == msg->addr && (next->flags | I2C_M_RD)
+			if (next->addr == msg->addr && (next->flags & I2C_M_RD)
 				&& *idx == ((dev->wr_sz*2) - 4)) {
 				writel_relaxed(((last_entry |
 					msg->buf[dev->pos]) |
@@ -1076,7 +1083,7 @@
 
 	platform_set_drvdata(pdev, dev);
 
-	dev->one_bit_t = USEC_PER_SEC/pdata->clk_freq;
+	dev->one_bit_t = (USEC_PER_SEC/pdata->clk_freq) + 1;
 	dev->pdata = pdata;
 	dev->clk_ctl = 0;
 	dev->pos = 0;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index d73f49c..07b6c81 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -61,7 +61,6 @@
 {
 	/* Interrupts are disabled, just acquire the lock. */
 	spin_lock(&client->buffer_lock);
-	wake_lock_timeout(&client->wake_lock, 5 * HZ);
 
 	wake_lock_timeout(&client->wake_lock, 5 * HZ);
 	client->buffer[client->head++] = *event;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b35597e..fc9d579 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -229,6 +229,7 @@
 #define MXT_MAX_FINGER		10
 
 #define MXT_BUFF_SIZE		100
+#define T7_DATA_SIZE 3
 
 struct mxt_info {
 	u8 family_id;
@@ -280,6 +281,8 @@
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 	struct early_suspend early_suspend;
 #endif
+	u8 t7_data[T7_DATA_SIZE];
+	u8 t9_ctrl;
 };
 
 static bool mxt_object_readable(unsigned int type)
@@ -839,7 +842,7 @@
 {
 	struct i2c_client *client = data->client;
 	struct mxt_info *info = &data->info;
-	int error;
+	int error, i;
 	int timeout_counter = 0;
 	u8 val;
 	u8 command_register;
@@ -866,6 +869,23 @@
 	if (error)
 		return error;
 
+	/* Store T7 and T9 locally, used in suspend/resume operations */
+	for (i = 0; i < T7_DATA_SIZE; i++) {
+		error = mxt_read_object(data, MXT_GEN_POWER, i,
+				&data->t7_data[i]);
+		if (error < 0) {
+			dev_err(&client->dev,
+				"failed to save current power state\n");
+			return error;
+		}
+	}
+	error = mxt_read_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_CTRL,
+			&data->t9_ctrl);
+	if (error < 0) {
+		dev_err(&client->dev, "failed to save current touch object\n");
+		return error;
+	}
+
 	mxt_handle_pdata(data);
 
 	/* Backup to memory */
@@ -1088,25 +1108,63 @@
 	.attrs = mxt_attrs,
 };
 
-static void mxt_start(struct mxt_data *data)
+static int mxt_start(struct mxt_data *data)
 {
-	/* Touch enable */
-	mxt_write_object(data,
-			MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83);
+	int i, error;
+	/* restore the old power state values and reenable touch */
+	for (i = 0; i < T7_DATA_SIZE; i++) {
+		error = mxt_write_object(data, MXT_GEN_POWER, i,
+			data->t7_data[i]);
+		if (error < 0) {
+			dev_err(&data->client->dev,
+				"failed to restore old power state\n");
+			return error;
+		}
+	}
+	error = mxt_write_object(data,
+			MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, data->t9_ctrl);
+	if (error < 0) {
+		dev_err(&data->client->dev, "failed to restore touch\n");
+		return error;
+	}
+
+	return 0;
 }
 
-static void mxt_stop(struct mxt_data *data)
+static int mxt_stop(struct mxt_data *data)
 {
-	/* Touch disable */
-	mxt_write_object(data,
+	int i, error;
+	/* configure deep sleep mode and disable touch */
+	for (i = 0; i < T7_DATA_SIZE; i++) {
+		error = mxt_write_object(data, MXT_GEN_POWER, i, 0);
+		if (error < 0) {
+			dev_err(&data->client->dev,
+				"failed to configure deep sleep mode\n");
+			return error;
+		}
+	}
+
+	error = mxt_write_object(data,
 			MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
+	if (error < 0) {
+		dev_err(&data->client->dev,
+			"failed to disable touch\n");
+		return error;
+	}
+
+	return 0;
 }
 
 static int mxt_input_open(struct input_dev *dev)
 {
 	struct mxt_data *data = input_get_drvdata(dev);
+	int error;
 
-	mxt_start(data);
+	error = mxt_start(data);
+	if (error < 0) {
+		dev_err(&data->client->dev, "mxt_start failed in input_open\n");
+		return error;
+	}
 
 	return 0;
 }
@@ -1114,8 +1172,12 @@
 static void mxt_input_close(struct input_dev *dev)
 {
 	struct mxt_data *data = input_get_drvdata(dev);
+	int error;
 
-	mxt_stop(data);
+	error = mxt_stop(data);
+	if (error < 0)
+		dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
+
 }
 
 static int mxt_power_on(struct mxt_data *data, bool on)
@@ -1253,11 +1315,19 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mxt_data *data = i2c_get_clientdata(client);
 	struct input_dev *input_dev = data->input_dev;
+	int error;
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		mxt_stop(data);
+	if (input_dev->users) {
+		error = mxt_stop(data);
+		if (error < 0) {
+			dev_err(&client->dev, "mxt_stop failed in suspend\n");
+			mutex_unlock(&input_dev->mutex);
+			return error;
+		}
+
+	}
 
 	mutex_unlock(&input_dev->mutex);
 
@@ -1269,7 +1339,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mxt_data *data = i2c_get_clientdata(client);
 	struct input_dev *input_dev = data->input_dev;
-
+	int error;
 	/* Soft reset */
 	mxt_write_object(data, MXT_GEN_COMMAND,
 			MXT_COMMAND_RESET, 1);
@@ -1278,8 +1348,14 @@
 
 	mutex_lock(&input_dev->mutex);
 
-	if (input_dev->users)
-		mxt_start(data);
+	if (input_dev->users) {
+		error = mxt_start(data);
+		if (error < 0) {
+			dev_err(&client->dev, "mxt_start failed in resume\n");
+			mutex_unlock(&input_dev->mutex);
+			return error;
+		}
+	}
 
 	mutex_unlock(&input_dev->mutex);
 
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
index db5c658..a3446a3 100644
--- a/drivers/input/touchscreen/cyttsp-i2c.c
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -288,6 +288,9 @@
 #define REC_DATA_OFFSET    9
 #define REC_LINE_SIZE	141
 
+#define NUM_CHAR_IN_HEX 2
+#define ID_INFO_REC_LEN 9
+
 static int cyttsp_soft_reset(struct cyttsp *ts)
 {
 	int retval = 0, tries = 0;
@@ -372,7 +375,10 @@
 	unsigned long ulval;
 	int rc;
 
-	if (!str && strlen(str) < 2)
+	if (!str)
+		return -EINVAL;
+
+	if (strnlen(str, NUM_CHAR_IN_HEX) < 2)
 		return -EINVAL;
 
 	substr[0] = str[0];
@@ -776,7 +782,8 @@
 		if ((data[i] == REC_START_CHR) && j) {
 			buf[j] = 0;
 			j = 0;
-			if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) {
+			if (!strncmp(buf, ID_INFO_REC,
+				strnlen(ID_INFO_REC, ID_INFO_REC_LEN))) {
 				cyttspfw_flash_start(ts, data, data_len,
 							buf, force);
 				break;
@@ -788,7 +795,8 @@
 	/* check in the last record of firmware */
 	if (j) {
 		buf[j] = 0;
-		if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) {
+		if (!strncmp(buf, ID_INFO_REC,
+			strnlen(ID_INFO_REC, ID_INFO_REC_LEN))) {
 			cyttspfw_flash_start(ts, data, data_len,
 						buf, force);
 		}
@@ -2808,9 +2816,8 @@
 /*
 			i2c_del_driver(&cyttsp_driver);
 */
-			retval = -ENODEV;
-		} else
-			cyttsp_openlog();
+			return -ENODEV;
+		}
 	}
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 47ac04d..94af3ce 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -54,13 +54,6 @@
 
 #define PM8XXX_LED_OFFSET(id) ((id) - PM8XXX_ID_LED_0)
 
-#define PM8XXX_GET_LED_ID(flag) (flag & PM8XXX_LED_ID_MASK >>	\
-						PM8XXX_LED_ID_SHIFT)
-#define PM8XXX_GET_LED_MODE(flag) ((flag & PM8XXX_LED_MODE_MASK) >>	\
-						PM8XXX_LED_MODE_SHIFT)
-#define PM8XXX_GET_LED_MAX_CURRENT(flag) ((flag & PM8XXX_LED_MAX_CURRENT_MASK)\
-						>> PM8XXX_LED_MAX_CURRENT_SHIFT)
-
 /**
  * struct pm8xxx_led_data - internal led data structure
  * @led_classdev - led class device
@@ -279,30 +272,38 @@
 
 static int __devinit pm8xxx_led_probe(struct platform_device *pdev)
 {
-	const struct led_platform_data *pdata = pdev->dev.platform_data;
+	const struct pm8xxx_led_platform_data *pdata = pdev->dev.platform_data;
+	const struct led_platform_data *pcore_data;
 	struct led_info *curr_led;
 	struct pm8xxx_led_data *led, *led_dat;
-	int rc, i, led_mode;
+	struct pm8xxx_led_config *led_cfg;
+	int rc, i;
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data not supplied\n");
 		return -EINVAL;
 	}
 
-	/* Let the last member of the list be zero to
-	 * mark the end of the list.
-	 */
-	led = kcalloc(pdata->num_leds + 1, sizeof(*led), GFP_KERNEL);
+	pcore_data = pdata->led_core;
+
+	if (pcore_data->num_leds != pdata->num_configs) {
+		dev_err(&pdev->dev, "#no. of led configs and #no. of led"
+				"entries are not equal\n");
+		return -EINVAL;
+	}
+
+	led = kcalloc(pcore_data->num_leds, sizeof(*led), GFP_KERNEL);
 	if (led == NULL) {
 		dev_err(&pdev->dev, "failed to alloc memory\n");
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < pdata->num_leds; i++) {
-		curr_led	= &pdata->leds[i];
+	for (i = 0; i < pcore_data->num_leds; i++) {
+		curr_led	= &pcore_data->leds[i];
 		led_dat		= &led[i];
-		/* the flags variable is used for led-id */
-		led_dat->id     = PM8XXX_GET_LED_ID(curr_led->flags);
+		led_cfg		= &pdata->configs[i];
+
+		led_dat->id     = led_cfg->id;
 
 		if (!((led_dat->id >= PM8XXX_ID_LED_KB_LIGHT) &&
 				(led_dat->id <= PM8XXX_ID_FLASH_LED_1))) {
@@ -317,17 +318,15 @@
 		led_dat->cdev.brightness_set    = pm8xxx_led_set;
 		led_dat->cdev.brightness_get    = pm8xxx_led_get;
 		led_dat->cdev.brightness	= LED_OFF;
-		led_dat->cdev.flags		= LED_CORE_SUSPENDRESUME;
+		led_dat->cdev.flags		= curr_led->flags;
 		led_dat->dev			= &pdev->dev;
 
 		rc =  get_init_value(led_dat, &led_dat->reg);
 		if (rc < 0)
 			goto fail_id_check;
 
-		led_mode = PM8XXX_GET_LED_MODE(curr_led->flags);
-
-		rc = pm8xxx_set_led_mode_and_max_brightness(led_dat, led_mode,
-				PM8XXX_GET_LED_MAX_CURRENT(curr_led->flags));
+		rc = pm8xxx_set_led_mode_and_max_brightness(led_dat,
+					led_cfg->mode, led_cfg->max_current);
 		if (rc < 0)
 			goto fail_id_check;
 
@@ -341,7 +340,7 @@
 			goto fail_id_check;
 		}
 
-		if (led_mode != PM8XXX_LED_MODE_MANUAL)
+		if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL)
 			__pm8xxx_led_work(led_dat,
 					led_dat->cdev.max_brightness);
 		else
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 2f83234..727b751 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -136,17 +136,20 @@
 	struct msm_device_queue *queue =  &server_dev->ctrl_q;
 
 	struct v4l2_event v4l2_evt;
-	struct msm_isp_stats_event_ctrl *isp_event;
+	struct msm_isp_event_ctrl *isp_event;
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
 	D("%s\n", __func__);
 
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
-
 	/* setup event object to transfer the command; */
-	isp_event = (struct msm_isp_stats_event_ctrl *)v4l2_evt.u.data;
+	*((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
 	isp_event->resptype = MSM_CAM_RESP_V4L2;
 	isp_event->isp_data.ctrl = *out;
-
-	/* now send command to config thread in usersspace,
+	/* now send command to config thread in userspace,
 	 * and wait for results */
 	v4l2_event_queue(server_dev->server_command_queue.pvdev,
 					  &v4l2_evt);
@@ -181,6 +184,7 @@
 	out->value = value;
 
 	free_qcmd(rcmd);
+	kfree(isp_event);
 	D("%s: rc %d\n", __func__, rc);
 	/* rc is the time elapsed. */
 	if (rc >= 0) {
@@ -1586,7 +1590,7 @@
 
 	if (pcam->use_count == 0) {
 		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd);
-
+		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd_vpe);
 		rc = msm_cam_server_close_session(&g_server_dev, pcam);
 		if (rc < 0)
 			pr_err("msm_cam_server_close_session fails %d\n", rc);
@@ -1739,45 +1743,80 @@
 		break;
 
 	case VIDIOC_DQEVENT: {
-		void __user *u_ctrl_value = NULL;
-		struct msm_isp_stats_event_ctrl *u_isp_event;
-		struct msm_isp_stats_event_ctrl *k_isp_event;
+		void __user *u_ctrl_value = NULL, *user_ptr = NULL;
+		struct msm_isp_event_ctrl u_isp_event;
+		struct msm_isp_event_ctrl *k_isp_event;
 
-		/* Make a copy of control value and event data pointer */
+		/* First, copy the event structure from userspace */
 		D("%s: VIDIOC_DQEVENT\n", __func__);
 		if (copy_from_user(&ev, (void __user *)arg,
-				sizeof(struct v4l2_event)))
+				sizeof(struct v4l2_event))) {
 			break;
-		u_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
-		u_ctrl_value = u_isp_event->isp_data.ctrl.value;
+		}
+		/* Next, get the pointer to event_ctrl structure
+		 * embedded inside the v4l2_event.u.data array. */
+		user_ptr = (void __user *)(*((uint32_t *)ev.u.data));
 
+		/* Next, copy the userspace event ctrl structure */
+		if (copy_from_user((void *)&u_isp_event, user_ptr,
+				sizeof(struct msm_isp_event_ctrl))) {
+			break;
+		}
+
+		/* Save the pointer of the user allocated command buffer*/
+		u_ctrl_value = u_isp_event.isp_data.ctrl.value;
+
+		/* Dequeue the event queued into the v4l2 queue*/
 		rc = v4l2_event_dequeue(
 			&g_server_dev.server_command_queue.eventHandle,
-			 &ev, fp->f_flags & O_NONBLOCK);
+			&ev, fp->f_flags & O_NONBLOCK);
 		if (rc < 0) {
 			pr_err("no pending events?");
 			break;
 		}
 
-		k_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
-		if (ev.type == V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_V4L2 &&
-				k_isp_event->isp_data.ctrl.length > 0) {
-			void *k_ctrl_value = k_isp_event->isp_data.ctrl.value;
-			if (copy_to_user(u_ctrl_value, k_ctrl_value,
-				u_isp_event->isp_data.ctrl.length)) {
+		/* Use k_isp_event to point to the event_ctrl structure
+		 * embedded inside v4l2_event.u.data */
+		k_isp_event = (struct msm_isp_event_ctrl *)
+				(*((uint32_t *)ev.u.data));
+		if (!k_isp_event) {
+			pr_err("%s Invalid event ctrl structure. ", __func__);
+			break;
+		}
+
+		/* Copy the event structure into user struct*/
+		u_isp_event = *k_isp_event;
+
+		/* Restore the saved pointer of the user
+		 * allocated command buffer. */
+		u_isp_event.isp_data.ctrl.value = u_ctrl_value;
+		if (ev.type == V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_V4L2) {
+			/* Copy the ctrl cmd, if present*/
+			if (k_isp_event->isp_data.ctrl.length > 0) {
+				void *k_ctrl_value =
+					k_isp_event->isp_data.ctrl.value;
+				if (copy_to_user(u_ctrl_value, k_ctrl_value,
+					 k_isp_event->isp_data.ctrl.length)) {
+					rc = -EINVAL;
+					break;
+				}
+			}
+			/* Copy the event ctrl structure back into
+			 * user's structure. */
+			if (copy_to_user(user_ptr, (void *)&u_isp_event,
+					 sizeof(struct msm_isp_event_ctrl))) {
 				rc = -EINVAL;
 				break;
 			}
 		}
-		k_isp_event->isp_data.ctrl.value = u_ctrl_value;
 
+		/* Copy the v4l2_event structure back to the user*/
 		if (copy_to_user((void __user *)arg, &ev,
 				sizeof(struct v4l2_event))) {
 			rc = -EINVAL;
 			break;
 		}
 		}
-
 		break;
 
 	case MSM_CAM_IOCTL_CTRL_CMD_DONE:
@@ -1900,46 +1939,77 @@
 		break;
 
 	case VIDIOC_DQEVENT: {
-		void __user *u_msg_value = NULL;
-		struct msm_isp_stats_event_ctrl *u_isp_event;
-		struct msm_isp_stats_event_ctrl *k_isp_event;
+		void __user *u_msg_value = NULL, *user_ptr = NULL;
+		struct msm_isp_event_ctrl u_isp_event;
+		struct msm_isp_event_ctrl *k_isp_event;
 
-		/* Make a copy of control value and event data pointer */
+		/* First, copy the v4l2 event structure from userspace */
 		D("%s: VIDIOC_DQEVENT\n", __func__);
 		if (copy_from_user(&ev, (void __user *)arg,
 				sizeof(struct v4l2_event)))
 			break;
-		u_isp_event =
-			(struct msm_isp_stats_event_ctrl *)ev.u.data;
-		u_msg_value = u_isp_event->isp_data.isp_msg.data;
+		/* Next, get the pointer to event_ctrl structure
+		 * embedded inside the v4l2_event.u.data array. */
+		user_ptr = (void __user *)(*((uint32_t *)ev.u.data));
 
+		/* Next, copy the userspace event ctrl structure */
+		if (copy_from_user((void *)&u_isp_event, user_ptr,
+				   sizeof(struct msm_isp_event_ctrl))) {
+			break;
+		}
+		/* Save the pointer of the user allocated command buffer*/
+		u_msg_value = u_isp_event.isp_data.isp_msg.data;
+
+		/* Dequeue the event queued into the v4l2 queue*/
 		rc = v4l2_event_dequeue(
-		&config_cam->config_stat_event_queue.eventHandle,
-			 &ev, fp->f_flags & O_NONBLOCK);
+			&config_cam->config_stat_event_queue.eventHandle,
+			&ev, fp->f_flags & O_NONBLOCK);
 		if (rc < 0) {
 			pr_err("no pending events?");
 			break;
 		}
+		/* Use k_isp_event to point to the event_ctrl structure
+		 * embedded inside v4l2_event.u.data */
+		k_isp_event = (struct msm_isp_event_ctrl *)
+				(*((uint32_t *)ev.u.data));
+		/* Copy the event structure into user struct. */
+		u_isp_event = *k_isp_event;
+
 		if (ev.type != (V4L2_EVENT_PRIVATE_START +
 				MSM_CAM_RESP_DIV_FRAME_EVT_MSG) &&
 				ev.type != (V4L2_EVENT_PRIVATE_START +
 				MSM_CAM_RESP_MCTL_PP_EVENT)) {
-			k_isp_event =
-			(struct msm_isp_stats_event_ctrl *)ev.u.data;
+
+			/* Restore the saved pointer of the
+			 * user allocated command buffer. */
+			u_isp_event.isp_data.isp_msg.data = u_msg_value;
+
 			if (ev.type == (V4L2_EVENT_PRIVATE_START +
-				MSM_CAM_RESP_STAT_EVT_MSG) &&
-				k_isp_event->isp_data.isp_msg.len > 0) {
-				void *k_msg_value =
+					MSM_CAM_RESP_STAT_EVT_MSG)) {
+				if (k_isp_event->isp_data.isp_msg.len > 0) {
+					void *k_msg_value =
 					k_isp_event->isp_data.isp_msg.data;
-				if (copy_to_user(u_msg_value, k_msg_value,
-					k_isp_event->isp_data.isp_msg.len)) {
-					rc = -EINVAL;
-					break;
+					if (copy_to_user(u_msg_value,
+							k_msg_value,
+					 k_isp_event->isp_data.isp_msg.len)) {
+						rc = -EINVAL;
+						break;
+					}
+					kfree(k_msg_value);
 				}
-				kfree(k_msg_value);
 			}
-			k_isp_event->isp_data.isp_msg.data = u_msg_value;
 		}
+		/* Copy the event ctrl structure back
+		 * into user's structure. */
+		if (copy_to_user(user_ptr,
+				(void *)&u_isp_event, sizeof(
+				struct msm_isp_event_ctrl))) {
+			rc = -EINVAL;
+			break;
+		}
+		kfree(k_isp_event);
+
+		/* Copy the v4l2_event structure back to the user*/
 		if (copy_to_user((void __user *)arg, &ev,
 				sizeof(struct v4l2_event))) {
 			rc = -EINVAL;
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 701f2d9..d914404 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -142,7 +142,7 @@
 {
 	int rc = 0;
 	struct v4l2_event v4l2_evt;
-	struct msm_isp_stats_event_ctrl *isp_event;
+	struct msm_isp_event_ctrl *isp_event;
 	struct msm_sync *sync =
 		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
 	struct msm_cam_media_controller *pmctl = &sync->pcam_sync->mctl;
@@ -157,9 +157,16 @@
 	if (notification == NOTIFY_VFE_BUF_EVT)
 		return msm_isp_notify_VFE_BUF_EVT(sd, arg);
 
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
+
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 					MSM_CAM_RESP_STAT_EVT_MSG;
-	isp_event = (struct msm_isp_stats_event_ctrl *)v4l2_evt.u.data;
+	*((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
+
 	isp_event->resptype = MSM_CAM_RESP_STAT_EVT_MSG;
 	isp_event->isp_data.isp_msg.type = MSM_CAMERA_MSG;
 	isp_event->isp_data.isp_msg.len = 0;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index a83fa00..a8554ee 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -516,8 +516,8 @@
 	idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
 		msg_type);
 	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
-	if (!pcam_inst->streamon) {
-		D("%s: stream 0x%p is off\n", __func__, pcam_inst);
+	if (!pcam_inst || !pcam_inst->streamon) {
+		D("%s: stream is turned off\n", __func__);
 		return rc;
 	}
 	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index f0c1bfa..7040c29 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -41,14 +41,22 @@
 			struct msm_cam_evt_divert_frame *div)
 {
 	struct v4l2_event v4l2_evt;
-
+	struct msm_isp_event_ctrl *isp_event;
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl),
+						GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
 	D("%s: msm_cam_evt_divert_frame=%d",
 		   __func__, sizeof(struct msm_cam_evt_divert_frame));
 	memset(&v4l2_evt, 0, sizeof(v4l2_evt));
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
-	memcpy(&v4l2_evt.u.data[0], div,
-			sizeof(struct msm_cam_evt_divert_frame));
+	*((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
+	/* Copy the divert frame struct into event ctrl struct. */
+	isp_event->isp_data.div_frame = *div;
+
 	D("%s inst=%p, img_mode=%d, frame_id=%d,phy=0x%x,len=%d\n",
 		__func__, pcam_inst, pcam_inst->image_mode, div->frame_id,
 		(uint32_t)div->phy_addr, div->length);
@@ -563,7 +571,7 @@
 				pp_frame_info->dest_frame.handle;
 			msm_mctl_buf_done_pp(
 				p_mctl, msg_type, &done_frame, 0);
-			pr_err("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x",
+			pr_info("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x",
 				__func__, done_frame.vb,
 				pp_frame_cmd->path, done_frame.ch_paddr[0]);
 		}
@@ -571,21 +579,31 @@
 			pp_frame_cmd->vpe_output_action)) {
 			struct v4l2_event v4l2_evt;
 			struct msm_mctl_pp_event_info *pp_event_info;
+			struct msm_isp_event_ctrl *isp_event;
+			isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl),
+								GFP_KERNEL);
+			if (!isp_event) {
+				pr_err("%s Insufficient memory.", __func__);
+				return -ENOMEM;
+			}
 			memset(&v4l2_evt, 0, sizeof(v4l2_evt));
-			pp_event_info =
-				(struct msm_mctl_pp_event_info *)v4l2_evt.
-					u.data;
+			*((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
+
+			/* Get hold of pp event info struct inside event ctrl.*/
+			pp_event_info = &(isp_event->isp_data.pp_event_info);
+
 			pp_event_info->event = MCTL_PP_EVENT_CMD_ACK;
 			pp_event_info->ack.cmd = pp_frame_info->user_cmd;
 			pp_event_info->ack.status = 0;
 			pp_event_info->ack.cookie = pp_frame_cmd->cookie;
 			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 						MSM_CAM_RESP_MCTL_PP_EVENT;
+
 			v4l2_event_queue(
 				p_mctl->config_device->
 					config_stat_event_queue.pvdev,
 				&v4l2_evt);
-			pr_err("%s: ack to daemon, cookie=0x%x, event = 0x%x",
+			D("%s: ack to daemon, cookie=0x%x, event = 0x%x",
 				__func__, pp_frame_info->pp_frame_cmd.cookie,
 				v4l2_evt.type);
 		}
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 1e80ef8..faf8d6d 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -678,7 +678,7 @@
 	msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
 		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
 
-	msm_io_dump(vfe32_ctrl->vfebase, 0x740);
+	msm_io_dump(vfe32_ctrl->vfebase, 0x7B4);
 
 	/* Ensure the write order while writing
 	to the command register using the barrier */
@@ -882,6 +882,23 @@
 		vfe32_ctrl->update_rolloff = false;
 	}
 
+	if (vfe32_ctrl->update_la) {
+		if (!msm_io_r(vfe32_ctrl->vfebase + V32_LA_OFF))
+			msm_io_w(1,
+				vfe32_ctrl->vfebase + V32_LA_OFF);
+		else
+			msm_io_w(0,
+				vfe32_ctrl->vfebase + V32_LA_OFF);
+		vfe32_ctrl->update_la = false;
+	}
+
+	if (vfe32_ctrl->update_gamma) {
+		value = msm_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+		value ^= V32_GAMMA_LUT_BANK_SEL_MASK;
+		msm_io_w(value, vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+		vfe32_ctrl->update_gamma = false;
+	}
+
 	spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
 	vfe32_ctrl->update_ack_pending = TRUE;
 	spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
@@ -997,6 +1014,7 @@
 	}
 	vfe32_program_dmi_cfg(NO_MEM_SELECTED);
 }
+
 static struct vfe32_output_ch *vfe32_get_ch(int path)
 {
 	struct vfe32_output_ch *ch = NULL;
@@ -1350,7 +1368,8 @@
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		/* Incrementing with 4 so as to point to the 2nd Register as
 		the 2nd register has the mce_enable bit */
-		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 4);
+		old_val = msm_io_r(vfe32_ctrl->vfebase +
+			V32_CHROMA_SUP_OFF + 4);
 		if (!cmdp) {
 			rc = -ENOMEM;
 			goto proc_general_done;
@@ -1365,15 +1384,16 @@
 		new_val = *cmdp_local;
 		old_val &= MCE_EN_MASK;
 		new_val = new_val | old_val;
-		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 4,
-					&new_val, 4);
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 4,
+			&new_val, 4);
 		cmdp_local += 1;
 
-		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 8);
+		old_val = msm_io_r(vfe32_ctrl->vfebase +
+			V32_CHROMA_SUP_OFF + 8);
 		new_val = *cmdp_local;
 		old_val &= MCE_Q_K_MASK;
 		new_val = new_val | old_val;
-		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 8,
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 8,
 		&new_val, 4);
 		cmdp_local += 1;
 		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
@@ -1421,6 +1441,26 @@
 		break;
 
 	case VFE_CMD_LA_CFG:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+			cmdp_local, (vfe32_cmd[cmd->id].length));
+
+		cmdp_local += 1;
+		vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, cmdp_local);
+		break;
+
 	case VFE_CMD_LA_UPDATE: {
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
@@ -1434,17 +1474,17 @@
 			rc = -EFAULT;
 			goto proc_general_done;
 		}
-		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
-				cmdp, (vfe32_cmd[cmd->id].length));
 
-		old_val = *cmdp;
-		cmdp += 1;
-		if (old_val == 0x0)
-			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp);
+		cmdp_local = cmdp + 1;
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_LA_OFF);
+		if (old_val != 0x0)
+			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+				cmdp_local);
 		else
-			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1 , cmdp);
-		cmdp -= 1;
+			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+				cmdp_local);
 		}
+		vfe32_ctrl->update_la = true;
 		break;
 
 	case VFE_CMD_SK_ENHAN_CFG:
@@ -1504,7 +1544,7 @@
 		}
 		cmdp_local = cmdp;
 		cmdp_local++;
-		msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1,
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1 + 4,
 			cmdp_local, (V32_LINEARIZATION_LEN1 - 4));
 		cmdp_local += 3;
 		msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2,
@@ -1664,13 +1704,14 @@
 			goto proc_general_done;
 		}
 		msm_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF,
-				cmdp, 4);
+			cmdp, 4);
 		cmdp += 1;
-		vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0 , cmdp);
-		vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0 , cmdp);
-		vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0 , cmdp);
-		cmdp -= 1;
+
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
 		}
+	    cmdp -= 1;
 		break;
 
 	case VFE_CMD_RGB_G_UPDATE: {
@@ -1685,21 +1726,20 @@
 			goto proc_general_done;
 		}
 
-		msm_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF, cmdp, 4);
-		old_val = *cmdp;
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF);
 		cmdp += 1;
-
-		if (old_val) {
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1 , cmdp);
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1 , cmdp);
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1 , cmdp);
+		if (old_val != 0x0) {
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
 		} else {
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0 , cmdp);
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0 , cmdp);
-			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0 , cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, cmdp);
 		}
+		}
+		vfe32_ctrl->update_gamma = TRUE;
 		cmdp -= 1;
-		}
 		break;
 
 	case VFE_CMD_STATS_AWB_STOP: {
@@ -1845,16 +1885,16 @@
 		msm_io_memcpy(vfe32_ctrl->vfebase + V33_PCA_ROLL_OFF_CFG_OFF2,
 			cmdp_local, V33_PCA_ROLL_OFF_CFG_LEN2);
 
+		cmdp_local += 3;
 		CDBG("%s: start writing RollOff Ram0 table\n", __func__);
 		vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
 		msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
 		for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
-			msm_io_w(*cmdp_local,
+			msm_io_w(*(cmdp_local + 1),
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI);
-			cmdp_local++;
 			msm_io_w(*cmdp_local,
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
-			cmdp_local++;
+			cmdp_local += 2;
 		}
 		CDBG("%s: end writing RollOff Ram0 table\n", __func__);
 
@@ -1862,10 +1902,9 @@
 		vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0);
 		msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
 		for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
-			cmdp_local++;
 			msm_io_w(*cmdp_local,
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
-			cmdp_local++;
+			cmdp_local += 2;
 		}
 		CDBG("%s: end writing RollOff Ram1 table\n", __func__);
 
@@ -1901,12 +1940,11 @@
 
 		msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
 		for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
-			msm_io_w(*cmdp_local,
+			msm_io_w(*(cmdp_local + 1),
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI);
-			cmdp_local++;
 			msm_io_w(*cmdp_local,
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
-			cmdp_local++;
+			cmdp_local += 2;
 		}
 		CDBG("%s: end writing RollOff Ram0 table\n", __func__);
 
@@ -1918,10 +1956,9 @@
 
 		msm_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
 		for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
-			cmdp_local++;
 			msm_io_w(*cmdp_local,
 				vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
-			cmdp_local++;
+			cmdp_local += 2;
 		}
 		CDBG("%s: end writing RollOff Ram1 table\n", __func__);
 
@@ -3035,6 +3072,8 @@
 	vfe32_ctrl->vfeio  = vfeio;
 	vfe32_ctrl->update_linear = false;
 	vfe32_ctrl->update_rolloff = false;
+	vfe32_ctrl->update_la = false;
+	vfe32_ctrl->update_gamma = false;
 	return 0;
 
 cmd_init_failed3:
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index 000beb2..d3ed0e6 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -253,6 +253,7 @@
 #define V32_MESH_ROLL_OFF_INIT_TABLE_SIZE     13
 #define V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE    208
 #define V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET  32
+#define V32_GAMMA_LUT_BANK_SEL_MASK           0x00000007
 
 #define V33_PCA_ROLL_OFF_CFG_LEN1             16
 #define V33_PCA_ROLL_OFF_CFG_OFF1             0x00000274
@@ -279,7 +280,7 @@
 #define V32_CHROMA_SUP_OFF 0x000003E8
 #define V32_CHROMA_SUP_LEN 12
 
-#define V32_MCE_OFF 0x000003E8
+#define V32_MCE_OFF 0x000003F4
 #define V32_MCE_LEN 36
 #define V32_STATS_AF_OFF 0x0000053c
 #define V32_STATS_AF_LEN 16
@@ -894,6 +895,8 @@
 	enum vfe_recording_state recording_state;
 	int8_t update_linear;
 	int8_t update_rolloff;
+	int8_t update_la;
+	int8_t update_gamma;
 
 	spinlock_t  tasklet_lock;
 	struct list_head tasklet_q;
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index be15b779..d50ea43 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -83,10 +83,10 @@
 	{0x4005, 0x08},
 	{0x404f, 0x84},
 	{0x4051, 0x00},
-	{0x5000, 0xff},
+	{0x5000, 0xcf},
 	{0x3a18, 0x00},
 	{0x3a19, 0x80},
-	{0x3503, 0x13},
+	{0x3503, 0x03},
 	{0x4521, 0x00},
 	{0x5183, 0xb0},
 	{0x5184, 0xb0},
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index fa07d6b..f05fb8e 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -529,7 +529,7 @@
 
 	if (pdata->leds_pdata) {
 		leds_cell.platform_data = pdata->leds_pdata;
-		leds_cell.pdata_size = sizeof(struct led_platform_data);
+		leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
 		ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
 		if (ret) {
 			pr_err("Failed to add leds subdevice ret=%d\n", ret);
diff --git a/drivers/mfd/pm8xxx-debug.c b/drivers/mfd/pm8xxx-debug.c
index 3b69121..7115726 100644
--- a/drivers/mfd/pm8xxx-debug.c
+++ b/drivers/mfd/pm8xxx-debug.c
@@ -132,8 +132,6 @@
 		return -ENOMEM;
 	}
 
-	mutex_init(&debugdev->debug_mutex);
-
 	debugdev->parent = pdev->dev.parent;
 	debugdev->addr = -1;
 
@@ -160,6 +158,8 @@
 		goto file_error;
 	}
 
+	mutex_init(&debugdev->debug_mutex);
+
 	debugdev->dir = dir;
 	platform_set_drvdata(pdev, debugdev);
 
@@ -179,6 +179,7 @@
 
 	if (debugdev) {
 		debugfs_remove_recursive(debugdev->dir);
+		mutex_destroy(&debugdev->debug_mutex);
 		kfree(debugdev);
 	}
 
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index ff22339..7f433db 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -1205,6 +1205,7 @@
 	struct pm8058_dbg_device *dbgdev;
 	struct dentry *dent;
 	struct dentry *temp;
+	int rc;
 
 	if (chip == NULL) {
 		pr_err("%s: no parent data passed in.\n", __func__);
@@ -1217,8 +1218,6 @@
 		return -ENOMEM;
 	}
 
-	mutex_init(&dbgdev->dbg_mutex);
-
 	dbgdev->pm_chip = chip;
 	dbgdev->addr = -1;
 
@@ -1226,7 +1225,8 @@
 	if (dent == NULL || IS_ERR(dent)) {
 		pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
 					__func__, (unsigned)dent);
-		return -ENOMEM;
+		rc = PTR_ERR(dent);
+		goto dir_error;
 	}
 
 	temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dent,
@@ -1234,6 +1234,7 @@
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
 					__func__, (unsigned)temp);
+		rc = PTR_ERR(temp);
 		goto debug_error;
 	}
 
@@ -1242,9 +1243,12 @@
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
 					__func__, (unsigned)temp);
+		rc = PTR_ERR(temp);
 		goto debug_error;
 	}
 
+	mutex_init(&dbgdev->dbg_mutex);
+
 	dbgdev->dent = dent;
 
 	pmic_dbg_device = dbgdev;
@@ -1253,13 +1257,17 @@
 
 debug_error:
 	debugfs_remove_recursive(dent);
-	return -ENOMEM;
+dir_error:
+	kfree(dbgdev);
+
+	return rc;
 }
 
 static int __devexit pmic8058_dbg_remove(void)
 {
 	if (pmic_dbg_device) {
 		debugfs_remove_recursive(pmic_dbg_device->dent);
+		mutex_destroy(&pmic_dbg_device->dbg_mutex);
 		kfree(pmic_dbg_device);
 	}
 	return 0;
diff --git a/drivers/mfd/pmic8901.c b/drivers/mfd/pmic8901.c
index da46656..390de33 100644
--- a/drivers/mfd/pmic8901.c
+++ b/drivers/mfd/pmic8901.c
@@ -679,6 +679,7 @@
 	struct pm8901_dbg_device *dbgdev;
 	struct dentry *dent;
 	struct dentry *temp;
+	int rc;
 
 	if (chip == NULL) {
 		pr_err("%s: no parent data passed in.\n", __func__);
@@ -691,8 +692,6 @@
 		return -ENOMEM;
 	}
 
-	mutex_init(&dbgdev->dbg_mutex);
-
 	dbgdev->pm_chip = chip;
 	dbgdev->addr = -1;
 
@@ -700,7 +699,8 @@
 	if (dent == NULL || IS_ERR(dent)) {
 		pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
 					__func__, (unsigned)dent);
-		return -ENOMEM;
+		rc = PTR_ERR(dent);
+		goto dir_error;
 	}
 
 	temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dent,
@@ -708,6 +708,7 @@
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
 					__func__, (unsigned)temp);
+		rc = PTR_ERR(temp);
 		goto debug_error;
 	}
 
@@ -716,9 +717,12 @@
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
 					__func__, (unsigned)temp);
+		rc = PTR_ERR(temp);
 		goto debug_error;
 	}
 
+	mutex_init(&dbgdev->dbg_mutex);
+
 	dbgdev->dent = dent;
 
 	pmic_dbg_device = dbgdev;
@@ -727,13 +731,17 @@
 
 debug_error:
 	debugfs_remove_recursive(dent);
-	return -ENOMEM;
+dir_error:
+	kfree(dbgdev);
+
+	return rc;
 }
 
 static int __devexit pmic8901_dbg_remove(void)
 {
 	if (pmic_dbg_device) {
 		debugfs_remove_recursive(pmic_dbg_device->dent);
+		mutex_destroy(&pmic_dbg_device->dbg_mutex);
 		kfree(pmic_dbg_device);
 	}
 	return 0;
diff --git a/drivers/misc/pmic8058-xoadc.c b/drivers/misc/pmic8058-xoadc.c
index d2d8cba..f21668a 100644
--- a/drivers/misc/pmic8058-xoadc.c
+++ b/drivers/misc/pmic8058-xoadc.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
 #include <linux/delay.h>
+#include <linux/wakelock.h>
 
 #include <mach/mpp.h>
 #include <mach/msm_xo.h>
@@ -65,6 +66,9 @@
 	struct adc_conv_slot conv_queue_elements[MAX_QUEUE_LENGTH];
 	int xoadc_num;
 	struct msm_xo_voter *adc_voter;
+	struct wake_lock adc_wakelock;
+	/* flag to warn/bug if wakelocks are taken after suspend_noirq */
+	int msm_suspend_check;
 };
 
 static struct pmic8058_adc *pmic_adc[XOADC_PMIC_0 + 1];
@@ -117,7 +121,7 @@
 EXPORT_SYMBOL(pm8058_xoadc_slot_request);
 
 static int32_t pm8058_xoadc_arb_cntrl(uint32_t arb_cntrl,
-					uint32_t adc_instance)
+				uint32_t adc_instance, uint32_t channel)
 {
 	struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
 	int i, rc;
@@ -128,9 +132,13 @@
 			ADC_ARB_USRP_CNTRL_RSV4;
 
 	if (arb_cntrl) {
+		if (adc_pmic->msm_suspend_check)
+			pr_err("XOADC request being made after suspend irq "
+				 "with channel id:%d\n", channel);
 		data_arb_cntrl |= ADC_ARB_USRP_CNTRL_EN_ARB;
 		msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
 		adc_pmic->pdata->xoadc_mpp_config();
+		wake_lock(&adc_pmic->adc_wakelock);
 	}
 
 	/* Write twice to the CNTRL register for the arbiter settings
@@ -144,8 +152,10 @@
 		}
 	}
 
-	if (!arb_cntrl)
+	if (!arb_cntrl) {
 		msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
+		wake_unlock(&adc_pmic->adc_wakelock);
+	}
 
 	return 0;
 }
@@ -159,7 +169,7 @@
 	u8 data_dig_param, data_ana_param2;
 	int rc;
 
-	rc = pm8058_xoadc_arb_cntrl(1, adc_instance);
+	rc = pm8058_xoadc_arb_cntrl(1, adc_instance, slot->chan_path);
 	if (rc < 0) {
 		pr_debug("%s: Configuring ADC Arbiter"
 				"enable failed\n", __func__);
@@ -461,7 +471,7 @@
 	/* Default value for switching off the arbiter after reading
 	   the ADC value. Bit 0 set to 0. */
 	if (adc_pmic->xoadc_queue_count == 0) {
-		rc = pm8058_xoadc_arb_cntrl(0, adc_instance);
+		rc = pm8058_xoadc_arb_cntrl(0, adc_instance, CHANNEL_MUXOFF);
 		if (rc < 0) {
 			pr_debug("%s: Configuring ADC Arbiter disable"
 						"failed\n", __func__);
@@ -607,6 +617,37 @@
 }
 EXPORT_SYMBOL(pm8058_xoadc_calibrate);
 
+#ifdef CONFIG_PM
+static int pm8058_xoadc_suspend_noirq(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
+
+	adc_pmic->msm_suspend_check = 1;
+
+	return 0;
+}
+
+static int pm8058_xoadc_resume_noirq(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
+
+	adc_pmic->msm_suspend_check = 0;
+
+	return 0;
+}
+
+static const struct dev_pm_ops pm8058_xoadc_dev_pm_ops = {
+	.suspend_noirq = pm8058_xoadc_suspend_noirq,
+	.resume_noirq = pm8058_xoadc_resume_noirq,
+};
+
+#define PM8058_XOADC_DEV_PM_OPS	(&pm8058_xoadc_dev_pm_ops)
+#else
+#define PM8058_XOADC_DEV_PM_OPS NULL
+#endif
+
 static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
 {
 	struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
@@ -614,6 +655,7 @@
 	if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
 		adc_pmic->pdata->xoadc_vreg_shutdown();
 
+	wake_lock_destroy(&adc_pmic->adc_wakelock);
 	msm_xo_put(adc_pmic->adc_voter);
 	platform_set_drvdata(pdev, adc_pmic->pm_chip);
 	device_init_wakeup(&pdev->dev, 0);
@@ -728,6 +770,9 @@
 		}
 	}
 
+	wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
+					"pmic8058_xoadc_wakelock");
+
 	pmic_adc[adc_pmic->xoadc_num] = adc_pmic;
 
 	if (pdata->xoadc_vreg_setup != NULL)
@@ -750,6 +795,7 @@
 	.driver = {
 		.name = "pm8058-xoadc",
 		.owner = THIS_MODULE,
+		.pm = PM8058_XOADC_DEV_PM_OPS,
 	},
 };
 
diff --git a/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c b/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c
index 51dd125..5da7a42 100644
--- a/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c
@@ -65,19 +65,11 @@
 		goto out;
 	}
 
-	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
-	if (rc) {
-		pr_err("%s: could not set voltages: %d\n", __func__, rc);
-		goto reg_free;
-	}
-
 	for (i = 0; i < ARRAY_SIZE(regs); i++)
 		vreg_info[i].reg = regs[i].consumer;
 
 	return 0;
 
-reg_free:
-	regulator_bulk_free(ARRAY_SIZE(regs), regs);
 out:
 	return rc;
 }
@@ -134,6 +126,25 @@
 
 	for (index = 0; index < ARRAY_SIZE(vreg_info); index++) {
 		if (on) {
+
+			rc = regulator_set_voltage(vreg_info[index].reg,
+						vreg_info[index].vreg_level,
+						vreg_info[index].vreg_level);
+			if (rc) {
+				pr_err("%s:%s set voltage failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
+
+				goto vreg_fail;
+			}
+
+			rc = regulator_enable(vreg_info[index].reg);
+			if (rc) {
+				pr_err("%s:%s vreg enable failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
+
+				goto vreg_fail;
+			}
+
 			if (vreg_info[index].is_vreg_pin_controlled) {
 				rc = pmapp_vreg_lpm_pincntrl_vote(id,
 					 vreg_info[index].pmapp_id,
@@ -143,17 +154,10 @@
 						" for enable failed %d\n",
 						__func__,
 						vreg_info[index].vreg_id, rc);
-					goto vreg_fail;
-				}
-			} else {
-				rc = regulator_enable(vreg_info[index].reg);
-				if (rc) {
-					pr_err("%s:%s vreg enable failed %d\n",
-						__func__,
-						vreg_info[index].vreg_id, rc);
-					goto vreg_fail;
+					goto vreg_clock_vote_fail;
 				}
 			}
+
 			/*At this point CLK_PWR_REQ is high*/
 			if (WLAN_VREG_L6 == index) {
 				/*
@@ -182,13 +186,11 @@
 						__func__,
 						vreg_info[index].vreg_id, rc);
 				}
-			} else {
-				rc = regulator_disable(vreg_info[index].reg);
-				if (rc) {
-					pr_err("%s:%s vreg disable failed %d\n",
-						__func__,
-						vreg_info[index].vreg_id, rc);
-				}
+			}
+			rc = regulator_disable(vreg_info[index].reg);
+			if (rc) {
+				pr_err("%s:%s vreg disable failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
 			}
 		}
 	}
@@ -196,7 +198,7 @@
 vreg_fail:
 	index--;
 vreg_clock_vote_fail:
-	while (index > 0) {
+	while (index >= 0) {
 		rc = regulator_disable(vreg_info[index].reg);
 		if (rc) {
 			pr_err("%s:%s vreg disable failed %d\n",
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 721e9c3..de8b918 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -42,6 +42,15 @@
 		"8058_s2",
 		"8058_s1",
 	};
+	static const char *vregs_qwlan_pc_name[] = {
+		"8058_l20_pc",
+		"8058_l8_pc",
+		NULL,
+		NULL,
+		"8901_l0_pc",
+		"8058_s2_pc",
+		NULL,
+	};
 	static const int vregs_qwlan_val_min[] = {
 		1800000,
 		3050000,
@@ -80,6 +89,7 @@
 	};
 	bool const *vregs_is_pin_controlled;
 	static struct regulator *vregs_qwlan[ARRAY_SIZE(vregs_qwlan_name)];
+	static struct regulator *vregs_pc_qwlan[ARRAY_SIZE(vregs_qwlan_name)];
 	static struct msm_xo_voter *wlan_clock;
 	int ret, i, rc = 0;
 	unsigned wlan_gpio_deep_sleep = GPIO_WLAN_DEEP_SLEEP_N;
@@ -157,11 +167,14 @@
 			}
 			/* vote for pin control (if needed) */
 			if (vregs_is_pin_controlled[i]) {
-				rc = regulator_set_mode(vregs_qwlan[i],
-						REGULATOR_MODE_IDLE);
-				if (rc) {
-					pr_err("regulator_set_mode(%s) failed\n",
-							vregs_qwlan_name[i]);
+				vregs_pc_qwlan[i] = regulator_get(NULL,
+							vregs_qwlan_pc_name[i]);
+				if (IS_ERR(vregs_pc_qwlan[i])) {
+					pr_err("regulator get of %s failed "
+						"(%ld)\n",
+						vregs_qwlan_pc_name[i],
+						PTR_ERR(vregs_pc_qwlan[i]));
+					rc = PTR_ERR(vregs_pc_qwlan[i]);
 					goto vreg_fail;
 				}
 			}
@@ -173,7 +186,23 @@
 						vregs_qwlan_name[i], rc);
 				goto vreg_fail;
 			}
+			if (vregs_is_pin_controlled[i]) {
+				rc = regulator_enable(vregs_pc_qwlan[i]);
+				if (rc < 0) {
+					pr_err("vreg %s enable failed (%d)\n",
+						vregs_qwlan_pc_name[i], rc);
+					goto vreg_fail;
+				}
+			}
 		} else if (!on && wlan_on) {
+			if (vregs_is_pin_controlled[i]) {
+				rc = regulator_disable(vregs_pc_qwlan[i]);
+				if (rc < 0) {
+					pr_err("vreg %s disable failed (%d)\n",
+						vregs_qwlan_pc_name[i], rc);
+					goto vreg_fail;
+				}
+			}
 			rc = regulator_disable(vregs_qwlan[i]);
 			if (rc < 0) {
 				pr_err("vreg %s disable failed (%d)\n",
@@ -192,6 +221,8 @@
 
 vreg_fail:
 	regulator_put(vregs_qwlan[i]);
+	if (vregs_is_pin_controlled[i])
+		regulator_put(vregs_pc_qwlan[i]);
 vreg_get_fail:
 	i--;
 	while (i >= 0) {
@@ -202,7 +233,18 @@
 					vregs_qwlan_name[i],
 					!on ? "enable" : "disable", ret);
 		}
+		if (vregs_is_pin_controlled[i]) {
+			ret = !on ? regulator_enable(vregs_pc_qwlan[i]) :
+				regulator_disable(vregs_pc_qwlan[i]);
+			if (ret < 0) {
+				pr_err("vreg %s %s failed (%d) in err path\n",
+					vregs_qwlan_pc_name[i],
+					!on ? "enable" : "disable", ret);
+			}
+		}
 		regulator_put(vregs_qwlan[i]);
+		if (vregs_is_pin_controlled[i])
+			regulator_put(vregs_pc_qwlan[i]);
 		i--;
 	}
 	if (!on)
diff --git a/drivers/power/msm_charger.c b/drivers/power/msm_charger.c
index 207572e..0cd7967 100644
--- a/drivers/power/msm_charger.c
+++ b/drivers/power/msm_charger.c
@@ -993,8 +993,6 @@
 
 static int __init determine_initial_batt_status(void)
 {
-	int rc;
-
 	if (is_battery_present())
 		if (is_battery_id_valid())
 			if (is_battery_temp_within_range())
@@ -1010,13 +1008,6 @@
 	if (is_batt_status_capable_of_charging())
 		handle_battery_inserted();
 
-	rc = power_supply_register(msm_chg.dev, &msm_psy_batt);
-	if (rc < 0) {
-		dev_err(msm_chg.dev, "%s: power_supply_register failed"
-			" rc=%d\n", __func__, rc);
-		return rc;
-	}
-
 	/* start updaing the battery powersupply every msm_chg.update_time
 	 * milliseconds */
 	queue_delayed_work(msm_chg.event_wq_thread,
@@ -1156,11 +1147,20 @@
 
 void msm_battery_gauge_register(struct msm_battery_gauge *batt_gauge)
 {
+	int rc;
+
 	if (msm_batt_gauge) {
 		msm_batt_gauge = batt_gauge;
 		pr_err("msm-charger %s multiple battery gauge called\n",
 								__func__);
 	} else {
+		rc = power_supply_register(msm_chg.dev, &msm_psy_batt);
+		if (rc < 0) {
+			dev_err(msm_chg.dev, "%s: power_supply_register failed"
+					" rc=%d\n", __func__, rc);
+			return;
+		}
+
 		msm_batt_gauge = batt_gauge;
 		determine_initial_batt_status();
 	}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 4896556..aaeb790 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -172,11 +172,17 @@
 
 static char const * const spi_rsrcs[] = {
 	"spi_clk",
-	"spi_cs",
 	"spi_miso",
 	"spi_mosi"
 };
 
+static char const * const spi_cs_rsrcs[] = {
+	"spi_cs",
+	"spi_cs1",
+	"spi_cs2",
+	"spi_cs3",
+};
+
 enum msm_spi_mode {
 	SPI_FIFO_MODE  = 0x0,  /* 00 */
 	SPI_BLOCK_MODE = 0x1,  /* 01 */
@@ -184,6 +190,12 @@
 	SPI_MODE_NONE  = 0xFF, /* invalid value */
 };
 
+/* Structure for SPI CS GPIOs */
+struct spi_cs_gpio {
+	int  gpio_num;
+	bool valid;
+};
+
 /* Structures for Data Mover */
 struct spi_dmov_cmd {
 	dmov_box box;      /* data aligned to max(dm_burst_size, block_size)
@@ -330,8 +342,10 @@
 	struct spi_transfer     *cur_rx_transfer;
 	/* Temporary buffer used for WR-WR or WR-RD transfers */
 	u8                      *temp_buf;
-	/* GPIO pin numbers for SPI clk, cs, miso and mosi */
+	/* GPIO pin numbers for SPI clk, miso and mosi */
 	int                      spi_gpios[ARRAY_SIZE(spi_rsrcs)];
+	/* SPI CS GPIOs for each slave */
+	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
 };
 
 /* Forward declaration */
@@ -635,8 +649,8 @@
 		if (dd->spi_gpios[i] >= 0) {
 			result = gpio_request(dd->spi_gpios[i], spi_rsrcs[i]);
 			if (result) {
-				pr_err("%s: gpio_request for pin %d failed\
-					with error%d\n", __func__,
+				dev_err(dd->dev, "%s: gpio_request for pin %d "
+					"failed with error %d\n", __func__,
 					dd->spi_gpios[i], result);
 				goto error;
 			}
@@ -660,6 +674,13 @@
 		if (dd->spi_gpios[i] >= 0)
 			gpio_free(dd->spi_gpios[i]);
 	}
+
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+		if (dd->cs_gpios[i].valid) {
+			gpio_free(dd->cs_gpios[i].gpio_num);
+			dd->cs_gpios[i].valid = 0;
+		}
+	}
 }
 
 static void msm_spi_clock_set(struct msm_spi *dd, int speed)
@@ -1652,7 +1673,24 @@
 static void msm_spi_process_message(struct msm_spi *dd)
 {
 	int xfrs_grped = 0;
+	int cs_num;
+	int rc;
+
 	dd->write_xfr_cnt = dd->read_xfr_cnt = 0;
+	cs_num = dd->cur_msg->spi->chip_select;
+	if ((!(dd->cur_msg->spi->mode & SPI_LOOP)) &&
+		(!(dd->cs_gpios[cs_num].valid)) &&
+		(dd->cs_gpios[cs_num].gpio_num >= 0)) {
+		rc = gpio_request(dd->cs_gpios[cs_num].gpio_num,
+				spi_cs_rsrcs[cs_num]);
+		if (rc) {
+			dev_err(dd->dev, "gpio_request for pin %d failed with "
+				"error %d\n", dd->cs_gpios[cs_num].gpio_num,
+				rc);
+			return;
+		}
+		dd->cs_gpios[cs_num].valid = 1;
+	}
 
 	dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
 					    struct spi_transfer,
@@ -1664,7 +1702,7 @@
 				    &dd->cur_msg->transfers,
 				    transfer_list) {
 			if (!dd->cur_transfer->len)
-				return;
+				goto error;
 			if (xfrs_grped) {
 				xfrs_grped--;
 				continue;
@@ -1686,12 +1724,20 @@
 			int ret = msm_spi_map_dma_buffers(dd);
 			if (ret < 0) {
 				dd->cur_msg->status = ret;
-				return;
+				goto error;
 			}
 		}
 		dd->cur_tx_transfer = dd->cur_rx_transfer = dd->cur_transfer;
 		msm_spi_process_transfer(dd);
 	}
+
+	return;
+
+error:
+	if (dd->cs_gpios[cs_num].valid) {
+		gpio_free(dd->cs_gpios[cs_num].gpio_num);
+		dd->cs_gpios[cs_num].valid = 0;
+	}
 }
 
 /* workqueue - pull messages from queue & process */
@@ -2257,9 +2303,17 @@
 		dd->spi_gpios[i] = resource ? resource->start : -1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+		resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							spi_cs_rsrcs[i]);
+		dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
+		dd->cs_gpios[i].valid = 0;
+	}
+
 	rc = msm_spi_request_gpios(dd);
 	if (rc)
 		goto err_probe_gpio;
+
 	spin_lock_init(&dd->queue_lock);
 	mutex_init(&dd->core_lock);
 	INIT_LIST_HEAD(&dd->queue);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 7cf888c..9017706 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2074,6 +2074,7 @@
 			continue;   /* not configured */
 
 		if (hw_test_and_clear_complete(i)) {
+			udelay(200);
 			err = isr_tr_complete_low(mEp);
 			if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
 				if (err > 0)   /* needs status phase */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index dc06da6..4c33695 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -37,7 +37,7 @@
  */
 
 /* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ	1024
+#define USB_BUFSIZ	4096
 
 static struct usb_composite_driver *composite;
 static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
@@ -859,6 +859,10 @@
 	struct usb_function		*f = NULL;
 	u8				endp;
 
+
+	if (w_length > USB_BUFSIZ)
+		return value;
+
 	/* partial re-init of the response message; the function or the
 	 * gadget might need to intercept e.g. a control-OUT completion
 	 * when we delegate to it.
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index ecade02..55d9a307 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2649,7 +2649,6 @@
 		 */
 		if (!fsg_is_set(common))
 			break;
-		common->ep0req->length = 0;
 		if (test_and_clear_bit(IGNORE_BULK_OUT,
 				       &common->fsg->atomic_bitflags))
 			usb_ep_clear_halt(common->fsg->bulk_in);
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 0bb50de..ebbd1d8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -41,6 +41,7 @@
 	int				ifc_id;
 	u8				port_num;
 	atomic_t			online;
+	atomic_t			ctrl_online;
 	struct usb_composite_dev	*cdev;
 
 	spinlock_t			lock;
@@ -297,6 +298,8 @@
 static void frmnet_disable(struct usb_function *f)
 {
 	struct f_rmnet *dev = func_to_rmnet(f);
+	unsigned long flags;
+	struct rmnet_ctrl_pkt *cpkt;
 
 	pr_debug("%s: port#%d\n", __func__, dev->port_num);
 
@@ -304,6 +307,17 @@
 
 	atomic_set(&dev->online, 0);
 
+	spin_lock_irqsave(&dev->lock, flags);
+	while (!list_empty(&dev->cpkt_resp_q)) {
+		cpkt = list_first_entry(&dev->cpkt_resp_q,
+				struct rmnet_ctrl_pkt, list);
+
+		list_del(&cpkt->list);
+		rmnet_free_ctrl_pkt(cpkt);
+	}
+	atomic_set(&dev->notify_count, 0);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	gport_rmnet_disconnect(dev);
 }
 
@@ -384,6 +398,73 @@
 	}
 }
 
+static void frmnet_connect(struct grmnet *gr)
+{
+	struct f_rmnet			*dev;
+
+	if (!gr) {
+		pr_err("%s: Invalid grmnet:%p\n", __func__, gr);
+		return;
+	}
+
+	dev = port_to_rmnet(gr);
+
+	atomic_set(&dev->ctrl_online, 1);
+}
+
+static void frmnet_disconnect(struct grmnet *gr)
+{
+	struct f_rmnet			*dev;
+	unsigned long			flags;
+	struct usb_cdc_notification	*event;
+	int				status;
+	struct rmnet_ctrl_pkt		*cpkt;
+
+	if (!gr) {
+		pr_err("%s: Invalid grmnet:%p\n", __func__, gr);
+		return;
+	}
+
+	dev = port_to_rmnet(gr);
+
+	atomic_set(&dev->ctrl_online, 0);
+
+	if (!atomic_read(&dev->online)) {
+		pr_debug("%s: nothing to do\n", __func__);
+		return;
+	}
+
+	usb_ep_fifo_flush(dev->notify);
+
+	event = dev->notify_req->buf;
+	event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+			| USB_RECIP_INTERFACE;
+	event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+	event->wValue = cpu_to_le16(0);
+	event->wIndex = cpu_to_le16(dev->ifc_id);
+	event->wLength = cpu_to_le16(0);
+
+	status = usb_ep_queue(dev->notify, dev->notify_req, GFP_KERNEL);
+	if (status < 0) {
+		if (!atomic_read(&dev->online))
+			return;
+		pr_err("%s: rmnet notify ep enqueue error %d\n",
+				__func__, status);
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	while (!list_empty(&dev->cpkt_resp_q)) {
+		cpkt = list_first_entry(&dev->cpkt_resp_q,
+				struct rmnet_ctrl_pkt, list);
+
+		list_del(&cpkt->list);
+		rmnet_free_ctrl_pkt(cpkt);
+	}
+	atomic_set(&dev->notify_count, 0);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+}
+
 static int
 frmnet_send_cpkt_response(struct grmnet *gr, struct rmnet_ctrl_pkt *cpkt)
 {
@@ -400,7 +481,7 @@
 
 	pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
 
-	if (!atomic_read(&dev->online)) {
+	if (!atomic_read(&dev->online) || !atomic_read(&dev->ctrl_online)) {
 		rmnet_free_ctrl_pkt(cpkt);
 		return 0;
 	}
@@ -459,6 +540,9 @@
 		pr_err("rmnet notify ep error %d\n", status);
 		/* FALLTHROUGH */
 	case 0:
+		if (!atomic_read(&dev->ctrl_online))
+			break;
+
 		if (atomic_dec_and_test(&dev->notify_count))
 			break;
 
@@ -493,8 +577,6 @@
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
-		if (w_length > req->length)
-			goto invalid;
 		ret = w_length;
 		req->complete = frmnet_cmd_complete;
 		req->context = dev;
@@ -708,6 +790,8 @@
 	f->set_alt = frmnet_set_alt;
 	f->setup = frmnet_setup;
 	dev->port.send_cpkt_response = frmnet_send_cpkt_response;
+	dev->port.disconnect = frmnet_disconnect;
+	dev->port.connect = frmnet_connect;
 
 	status = usb_add_function(c, f);
 	if (status) {
diff --git a/drivers/usb/gadget/f_rmnet_sdio.c b/drivers/usb/gadget/f_rmnet_sdio.c
index 61a67bb..b15c221 100644
--- a/drivers/usb/gadget/f_rmnet_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_sdio.c
@@ -534,8 +534,6 @@
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
-		if (w_length > req->length)
-			goto invalid;
 		ret = w_length;
 		req->complete = rmnet_sdio_command_complete;
 		req->context = dev;
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index 08a6799..b8dd3a5 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -534,8 +534,6 @@
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
-		if (w_length > req->length)
-			goto invalid;
 		ret = w_length;
 		req->complete = rmnet_smd_command_complete;
 		req->context = dev;
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index b9120ca..eda547a 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -1110,8 +1110,6 @@
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
-		if (w_length > req->length)
-			goto invalid;
 		ret = w_length;
 		req->complete = rmnet_mux_command_complete;
 		req->context = dev;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index aeaddee..3c21316 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,6 +48,9 @@
 	void (*send_cbits_tomodem)(struct grmnet *g,
 				u8 port_num,
 				int cbits);
+
+	void (*disconnect)(struct grmnet *g);
+	void (*connect)(struct grmnet *g);
 };
 
 int gbam_setup(unsigned int count);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index b4d2828..fc159cc 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -273,6 +273,8 @@
 {
 	struct rmnet_ctrl_port	*port = p;
 	struct smd_ch_info	*c = &port->ctrl_ch;
+	struct rmnet_ctrl_pkt	*cpkt;
+	unsigned long		flags;
 
 	pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));
 
@@ -285,10 +287,27 @@
 		break;
 	case SMD_EVENT_OPEN:
 		set_bit(CH_OPENED, &c->flags);
-		wake_up(&c->wait);
+
+		if (port && port->port_usb && port->port_usb->connect)
+			port->port_usb->connect(port->port_usb);
+
 		break;
 	case SMD_EVENT_CLOSE:
 		clear_bit(CH_OPENED, &c->flags);
+
+		if (port && port->port_usb && port->port_usb->disconnect)
+			port->port_usb->disconnect(port->port_usb);
+
+		spin_lock_irqsave(&port->port_lock, flags);
+		while (!list_empty(&c->tx_q)) {
+			cpkt = list_first_entry(&c->tx_q,
+					struct rmnet_ctrl_pkt, list);
+
+			list_del(&cpkt->list);
+			free_rmnet_ctrl_pkt(cpkt);
+		}
+		spin_unlock_irqrestore(&port->port_lock, flags);
+
 		break;
 	}
 }
@@ -357,6 +376,7 @@
 	struct rmnet_ctrl_port	*port;
 	unsigned long		flags;
 	struct smd_ch_info	*c;
+	struct rmnet_ctrl_pkt	*cpkt;
 
 	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
 
@@ -378,6 +398,14 @@
 	gr->send_cpkt_request = 0;
 	gr->send_cbits_tomodem = 0;
 	c->cbits_tomodem = 0;
+
+	while (!list_empty(&c->tx_q)) {
+		cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
+
+		list_del(&cpkt->list);
+		free_rmnet_ctrl_pkt(cpkt);
+	}
+
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
 	if (test_bit(CH_OPENED, &c->flags)) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 3c130e9..4658469 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2144,7 +2144,6 @@
 static int msm_otg_pm_resume(struct device *dev)
 {
 	struct msm_otg *motg = dev_get_drvdata(dev);
-	int ret = 0;
 
 	dev_dbg(dev, "OTG PM resume\n");
 
@@ -2153,7 +2152,7 @@
 	 * Do not resume hardware as part of system resume,
 	 * rather, wait for the ASYNC INT from the h/w
 	 */
-	return ret;
+	return 0;
 #endif
 
 	return msm_otg_resume(motg);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index ddc26b1..d3059d1 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -386,6 +386,7 @@
 
 config FB_MSM_MIPI_PANEL_DETECT
 	bool "MIPI Panel Detect"
+	select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
 	select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT
 	select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
 	select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT
@@ -412,6 +413,24 @@
 	---help---
 	  Support for LCDC panel auto detect
 
+config FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT
+	bool "LCDC + MIPI Panel Auto Detect"
+	select FB_MSM_LCDC_AUTO_DETECT
+	select FB_MSM_LCDC_SAMSUNG_WSVGA
+	select FB_MSM_LCDC_AUO_WVGA
+	select FB_MSM_LCDC_SAMSUNG_OLED_PT
+	select FB_MSM_LCDC_NT35582_WVGA
+	select FB_MSM_LCDC_TOSHIBA_FWVGA_PT
+	select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
+	select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT
+	select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
+	select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT
+	select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT
+	select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
+	select FB_MSM_MIPI_SIMULATOR_VIDEO
+	---help---
+	  Support for LCDC + MIPI panel auto detect
+
 config FB_MSM_MDDI_PRISM_WVGA
 	bool "MDDI Prism WVGA Panel"
 	select FB_MSM_MDDI
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index dffde1b..3e89f0b 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -107,12 +107,6 @@
 obj-$(CONFIG_FB_MSM_MDDI_QUICKVX) += mddi_quickvx.o
 endif
 
-ifeq ($(CONFIG_FB_MSM_MIPI_PANEL_DETECT),y)
-obj-y += mipi_toshiba_video_wvga_pt.o mipi_toshiba_video_wsvga_pt.o
-obj-y += mipi_novatek_video_qhd_pt.o mipi_novatek_cmd_qhd_pt.o
-obj-y += mipi_renesas_video_fwvga_pt.o mipi_renesas_cmd_fwvga_pt.o
-obj-y += mipi_chimei_wxga_pt.o
-else
 obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT) += mipi_toshiba_video_wvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT) += mipi_toshiba_video_wsvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT) += mipi_novatek_video_qhd_pt.o
@@ -121,7 +115,6 @@
 obj-$(CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT) += mipi_renesas_cmd_fwvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO) += mipi_simulator_video.o
 obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WXGA) += mipi_chimei_wxga_pt.o
-endif
 
 obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
 obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index b9d8171..7eca334 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -276,17 +276,18 @@
 	} else {
 		hdmi_msm_state->hpd_cable_chg_detected = FALSE;
 		mutex_unlock(&hdmi_msm_state_mutex);
+		/* QDSP OFF preceding the HPD event notification */
+		envp[0] = "HDCP_STATE=FAIL";
+		envp[1] = NULL;
+		DEV_INFO("HDMI HPD: QDSP OFF\n");
+		kobject_uevent_env(external_common_state->uevent_kobj,
+				   KOBJ_CHANGE, envp);
 		if (hpd_state) {
 			hdmi_msm_read_edid();
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 			hdmi_msm_state->reauth = FALSE ;
 #endif
 			/* Build EDID table */
-			envp[0] = "HDCP_STATE=FAIL";
-			envp[1] = NULL;
-			DEV_INFO("HDMI HPD: QDSP OFF\n");
-			kobject_uevent_env(external_common_state->uevent_kobj,
-				KOBJ_CHANGE, envp);
 			hdmi_msm_turn_on();
 			DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
 			kobject_uevent(external_common_state->uevent_kobj,
@@ -3351,7 +3352,7 @@
 	hdmi_msm_hpd_off();
 	hdmi_msm_powerdown_phy();
 	hdmi_msm_dump_regs("HDMI-OFF: ");
-	hdmi_msm_hpd_on(false);
+	hdmi_msm_hpd_on(true);
 
 	mutex_lock(&external_common_state_hpd_mutex);
 	if (!external_common_state->hpd_feature_on)
@@ -3668,6 +3669,9 @@
 {
 	int rc;
 
+	if (msm_fb_detect_client("hdmi_msm"))
+		return 0;
+
 	hdmi_msm_setup_video_mode_lut();
 	hdmi_msm_state = kzalloc(sizeof(*hdmi_msm_state), GFP_KERNEL);
 	if (!hdmi_msm_state) {
diff --git a/drivers/video/msm/lcdc_auo_wvga.c b/drivers/video/msm/lcdc_auo_wvga.c
index b1c3af0..6b0733f 100644
--- a/drivers/video/msm/lcdc_auo_wvga.c
+++ b/drivers/video/msm/lcdc_auo_wvga.c
@@ -335,12 +335,10 @@
 	int ret;
 	struct msm_panel_info *pinfo;
 
-#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT
 	if (msm_fb_detect_client(LCDC_AUO_PANEL_NAME)) {
 		pr_err("%s: detect failed\n", __func__);
 		return 0;
 	}
-#endif
 
 	ret = platform_driver_register(&this_driver);
 	if (ret) {
diff --git a/drivers/video/msm/lcdc_chimei_wxga.c b/drivers/video/msm/lcdc_chimei_wxga.c
index b5cce2c..7453ecb 100644
--- a/drivers/video/msm/lcdc_chimei_wxga.c
+++ b/drivers/video/msm/lcdc_chimei_wxga.c
@@ -187,10 +187,8 @@
 	int ret;
 	struct msm_panel_info *pinfo;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
-	if (msm_fb_detect_client("lcdc_chimei_lvds_wxga"))
+	if (msm_fb_detect_client("lcdc_chimei_wxga"))
 		return 0;
-#endif
 
 	ret = platform_driver_register(&this_driver);
 	if (ret)
diff --git a/drivers/video/msm/lcdc_samsung_oled_pt.c b/drivers/video/msm/lcdc_samsung_oled_pt.c
index dccc997..16790f3 100644
--- a/drivers/video/msm/lcdc_samsung_oled_pt.c
+++ b/drivers/video/msm/lcdc_samsung_oled_pt.c
@@ -551,12 +551,10 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT
 	if (msm_fb_detect_client("lcdc_samsung_oled")) {
 		pr_err("%s: detect failed\n", __func__);
 		return 0;
 	}
-#endif
 
 	ret = platform_driver_register(&this_driver);
 	if (ret) {
diff --git a/drivers/video/msm/lcdc_samsung_wsvga.c b/drivers/video/msm/lcdc_samsung_wsvga.c
index b4bf8cf..6b35e52 100644
--- a/drivers/video/msm/lcdc_samsung_wsvga.c
+++ b/drivers/video/msm/lcdc_samsung_wsvga.c
@@ -48,12 +48,12 @@
 
 static void lcdc_samsung_panel_set_backlight(struct msm_fb_data_type *mfd)
 {
+#ifdef CONFIG_PMIC8058_PWM
 	int bl_level;
 	int ret;
 
 	bl_level = mfd->bl_level;
 
-#ifdef CONFIG_PMIC8058_PWM
 	if (bl_pwm0) {
 		ret = pwm_config(bl_pwm0, PWM_DUTY_LEVEL * bl_level,
 			PWM_PERIOD_USEC);
@@ -222,10 +222,8 @@
 	int ret;
 	struct msm_panel_info *pinfo;
 
-#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT
 	if (msm_fb_detect_client("lcdc_samsung_wsvga"))
 		return 0;
-#endif
 
 	ret = platform_driver_register(&this_driver);
 	if (ret)
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 313814e..c522b0f 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -541,7 +541,7 @@
 #ifdef CONFIG_FB_MSM_MDP303
 
 #ifdef CONFIG_FB_MSM_MIPI_DSI
-		mipi_dsi_cmd_mdp_sw_trigger();
+		mipi_dsi_cmd_mdp_start();
 #endif
 
 #endif
@@ -1085,6 +1085,18 @@
 				__func__, mdp_hw_revision);
 }
 
+int mdp4_writeback_offset(void)
+{
+	int off = 0;
+
+	if (mdp_pdata->writeback_offset)
+		off = mdp_pdata->writeback_offset();
+
+	pr_debug("%s: writeback_offset=%d %x\n", __func__, off, off);
+
+	return off;
+}
+
 #ifdef CONFIG_FB_MSM_MDP40
 static void configure_mdp_core_clk_table(uint32 min_clk_rate)
 {
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 39d69f8..0740f42 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -343,32 +343,6 @@
 	ulong err_format;
 };
 
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
-static inline int mdp4_overlay_writeback_setup(struct fb_info *fbi,
-		struct mdp4_overlay_pipe *pipe, uint8 *buf, int bpp)
-{
-	struct msm_fb_data_type *mfd = fbi->par;
-	int off;
-
-	pipe->blt_base = (ulong) buf;
-	off = ALIGN(fbi->var.xres, 32) * fbi->var.yres * bpp * mfd->fb_page;
-	off += (1920 * 1080 * 2 * 1); /* hdmi */
-	pipe->blt_base += off;
-
-	pr_info("%s: base=%x offset=%x\n",
-			__func__, (int) pipe->blt_base, (int)off);
-
-	return off;
-
-}
-#else
-static inline int mdp4_overlay_writeback_setup(struct fb_info *fbi,
-		struct mdp4_overlay_pipe *pipe, uint8 *buf, int bpp)
-{
-	return 0;
-}
-#endif
-
 void mdp4_sw_reset(unsigned long bits);
 void mdp4_display_intf_sel(int output, unsigned long intf);
 void mdp4_overlay_cfg(int layer, int blt_mode, int refresh, int direct_out);
@@ -624,6 +598,7 @@
 			 struct msmfb_overlay_3d *r3d);
 
 int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info);
+int mdp4_writeback_offset(void);
 
 void mdp_dmap_vsync_set(int enable);
 int mdp_dmap_vsync_get(void);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 3870afd..ecefdc3 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -507,7 +507,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
-	int pnum;
+	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
 	vg_base = MDP_BASE + MDP4_VIDEO_BASE;
@@ -519,16 +519,16 @@
 	dst_size = ((pipe->dst_h << 16) | pipe->dst_w);
 	dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);
 
+	ptype = mdp4_overlay_format2type(pipe->src_format);
 	format = mdp4_overlay_format(pipe);
 	pattern = mdp4_overlay_unpack_pattern(pipe);
 
 	/* not RGB use VG pipe, pure VG pipe */
-	if (pipe->pipe_type != OVERLAY_TYPE_RGB)
-#ifdef MDP4_IGC_LUT_ENABLE
-		pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR |
-				MDP4_OP_IGC_LUT_EN);
-#else
+	if (ptype != OVERLAY_TYPE_RGB)
 		pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR);
+
+#ifdef MDP4_IGC_LUT_ENABLE
+	pipe->op_mode |= MDP4_OP_IGC_LUT_EN;
 #endif
 
 	mdp4_scale_setup(pipe);
@@ -548,8 +548,14 @@
 	 * present before the offset. This is required for video
 	 * frames coming with unused green pixels along the left margin
 	 */
-	mdp4_overlay_vg_get_src_offset(pipe, vg_base, &luma_offset,
-		&chroma_offset);
+	/* not RGB use VG pipe, pure VG pipe */
+	if (ptype != OVERLAY_TYPE_RGB) {
+		mdp4_overlay_vg_get_src_offset(pipe, vg_base, &luma_offset,
+			&chroma_offset);
+	} else {
+		luma_offset = 0;
+		chroma_offset = 0;
+	}
 
 	/* luma component plane */
 	outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
@@ -1158,6 +1164,14 @@
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
 {
 	uint32 data, mask, snum, stage, mixer, pnum;
+	struct mdp4_overlay_pipe *spipe;
+
+	spipe = mdp4_overlay_stage_pipe(pipe->mixer_num, pipe->mixer_stage);
+	if ((spipe != NULL) && (spipe != pipe)) {
+		pr_err("%s: unable to stage pipe=%d at mixer_stage=%d\n",
+				__func__, pipe->pipe_ndx, pipe->mixer_stage);
+		return;
+	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 0b28c8b..0020fd5 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -115,7 +115,7 @@
 void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
 {
 	MDPIBUF *iBuf = &mfd->ibuf;
-	struct fb_info *fbi;
+	struct fb_info *fbi = mfd->fbi;
 	uint8 *src;
 	int ptype;
 	struct mdp4_overlay_pipe *pipe;
@@ -155,11 +155,14 @@
 
 		dsi_pipe = pipe; /* keep it */
 
-		fbi = mfd->fbi;
-		bpp = fbi->var.bits_per_pixel / 8;
-		src = (uint8 *) iBuf->buf;
-		writeback_offset = mdp4_overlay_writeback_setup(
-						fbi, pipe, src, bpp);
+		writeback_offset = mdp4_writeback_offset();
+
+		if (writeback_offset > 0) {
+			pipe->blt_base = (ulong)fbi->fix.smem_start;
+			pipe->blt_base += writeback_offset;
+		} else {
+			pipe->blt_base  = 0;
+		}
 	} else {
 		pipe = dsi_pipe;
 	}
@@ -168,8 +171,8 @@
 	 * dma_p = 0, dma_s = 1
 	 */
 	MDP_OUTP(MDP_BASE + 0x000a0, 0x10);
-	/* enable dsi trigger on dma_p */
-	MDP_OUTP(MDP_BASE + 0x000a4, 0x01);
+	/* disable dsi trigger */
+	MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
 	/* whole screen for base layer */
 	src = (uint8 *) iBuf->buf;
 
@@ -304,6 +307,11 @@
 	pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
 	__func__, dsi_pipe->blt_end, (int)dsi_pipe->blt_addr, current->pid);
 
+	if (dsi_pipe->blt_base == 0) {
+		pr_info("%s: no blt_base assigned\n", __func__);
+		return -EBUSY;
+	}
+
 	if (dsi_pipe->blt_addr == 0) {
 		mdp4_dsi_cmd_dma_busy_wait(mfd);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -453,7 +461,7 @@
 	/* kick off dmap */
 	outpdw(MDP_BASE + 0x000c, 0x0);
 	/* trigger dsi cmd engine */
-	mipi_dsi_cmd_mdp_sw_trigger();
+	mipi_dsi_cmd_mdp_start();
 
 	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
 }
@@ -513,7 +521,7 @@
 	/* kick off dmap */
 	outpdw(MDP_BASE + 0x000c, 0x0);
 	/* trigger dsi cmd engine */
-	mipi_dsi_cmd_mdp_sw_trigger();
+	mipi_dsi_cmd_mdp_start();
 	mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
 }
 
@@ -630,6 +638,11 @@
 	/* change mdp clk */
 	mdp4_set_perf_level();
 
+	mipi_dsi_mdp_busy_wait(mfd);
+
+	if (dsi_pipe->blt_addr == 0)
+		mipi_dsi_cmd_mdp_start();
+
 	mdp4_overlay_dsi_state_set(ST_DSI_PLAYING);
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -640,11 +653,6 @@
 	/* start OVERLAY pipe */
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
-
-	if (dsi_pipe->blt_addr == 0) {
-		/* trigger dsi cmd engine */
-		mipi_dsi_cmd_mdp_sw_trigger();
-	}
 }
 
 void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 5ec271ec..93933f3 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -141,8 +141,14 @@
 		dsi_pipe = pipe; /* keep it */
 		init_completion(&dsi_video_comp);
 
-		writeback_offset = mdp4_overlay_writeback_setup(
-						fbi, pipe, buf, bpp);
+		writeback_offset = mdp4_writeback_offset();
+
+		if (writeback_offset > 0) {
+			pipe->blt_base = (ulong)fbi->fix.smem_start;
+			pipe->blt_base += writeback_offset;
+		} else {
+			pipe->blt_base  = 0;
+		}
 	} else {
 		pipe = dsi_pipe;
 	}
@@ -568,6 +574,11 @@
 	int data;
 	int change = 0;
 
+	if (dsi_pipe->blt_base == 0) {
+		pr_info("%s: no blt_base assigned\n", __func__);
+		return;
+	}
+
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	if (enable && dsi_pipe->blt_addr == 0) {
 		dsi_pipe->blt_addr = dsi_pipe->blt_base;
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 470c677..e840230 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -128,8 +128,14 @@
 		lcdc_pipe = pipe; /* keep it */
 		init_completion(&lcdc_comp);
 
-		writeback_offset = mdp4_overlay_writeback_setup(
-						fbi, pipe, buf, bpp);
+		writeback_offset = mdp4_writeback_offset();
+
+		if (writeback_offset > 0) {
+			pipe->blt_base = (ulong)fbi->fix.smem_start;
+			pipe->blt_base += writeback_offset;
+		} else {
+			pipe->blt_base  = 0;
+		}
 	} else {
 		pipe = lcdc_pipe;
 	}
@@ -463,6 +469,11 @@
 	unsigned long flag;
 	int change = 0;
 
+	if (lcdc_pipe->blt_base == 0) {
+		pr_debug("%s: no blt_base assigned\n", __func__);
+		return;
+	}
+
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	if (enable && lcdc_pipe->blt_addr == 0) {
 		lcdc_pipe->blt_addr = lcdc_pipe->blt_base;
diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c
index f070466..fe7035a 100644
--- a/drivers/video/msm/mipi_chimei_wxga_pt.c
+++ b/drivers/video/msm/mipi_chimei_wxga_pt.c
@@ -33,6 +33,7 @@
 #include "msm_fb.h"
 #include "msm_fb_panel.h"
 #include "mipi_dsi.h"
+#include "mipi_tc358764_dsi2lvds.h"
 
 #define MHZ (1000*1000)
 
@@ -40,7 +41,7 @@
  * Panel info parameters.
  * The panel info is passed to the mipi framebuffer driver.
  */
-static struct msm_panel_info chimei_waga_pinfo;
+static struct msm_panel_info chimei_wxga_pinfo;
 
 /**
  * The mipi_dsi_phy_ctrl is calculated according to the
@@ -70,45 +71,6 @@
 };
 
 /**
- * Register the panel device.
- *
- * @param pinfo
- * @param channel_id
- * @param panel_id
- *
- * @return int
- */
-static int mipi_chimei_wxga_register_panel(struct msm_panel_info *pinfo,
-					   u32 channel_id, u32 panel_id)
-{
-	struct platform_device *pdev = NULL;
-	int ret;
-	/* Use DSI-to-LVDS bridge */
-	const char driver_name[] = "mipi_tc358764";
-
-	pr_debug("%s.\n", __func__);
-
-	/* Note: the device id should be non-zero */
-	pdev = platform_device_alloc(driver_name, (panel_id << 8)|channel_id);
-	if (pdev == NULL)
-		return -ENOMEM;
-
-	pdev->dev.platform_data = pinfo;
-
-	ret = platform_device_add(pdev);
-	if (ret) {
-		pr_err("%s: platform_device_register failed!\n", __func__);
-		goto err_device_put;
-	}
-
-	return 0;
-
-err_device_put:
-	platform_device_put(pdev);
-	return ret;
-}
-
-/**
  * Module init.
  *
  * Register the panel-info.
@@ -122,15 +84,12 @@
 static int __init mipi_chimei_wxga_init(void)
 {
 	int ret;
-	struct msm_panel_info *pinfo = &chimei_waga_pinfo;
+	struct msm_panel_info *pinfo = &chimei_wxga_pinfo;
 
-	pr_info("mipi-dsi chimei wxga (1366x768) driver ver 1.0.\n");
-
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
-	if (msm_fb_detect_client("mipi_chimei_wxga"))
+	if (msm_fb_detect_client("mipi_video_chimei_wxga"))
 		return 0;
-#endif
 
+	pr_debug("mipi-dsi chimei wxga (1366x768) driver ver 1.0.\n");
 	/* Landscape */
 	pinfo->xres = 1366;
 	pinfo->yres = 768;
@@ -212,7 +171,7 @@
 	pinfo->mipi.fixed_packet_size = 4;
 	pinfo->mipi.force_clk_lane_hs = 1;
 
-	ret = mipi_chimei_wxga_register_panel(pinfo, MIPI_DSI_PRIM,
+	ret = mipi_tc358764_dsi2lvds_register(pinfo, MIPI_DSI_PRIM,
 					      MIPI_DSI_PANEL_WXGA);
 	if (ret)
 		pr_err("%s: failed to register device!\n", __func__);
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index c18f2a0..00256e6 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -87,6 +87,7 @@
 		if (mdp_rev >= MDP_REV_41) {
 			mdp4_dsi_cmd_dma_busy_wait(mfd);
 			mdp4_dsi_blt_dmap_busy_wait(mfd);
+			mipi_dsi_mdp_busy_wait(mfd);
 		} else {
 			mdp3_dsi_cmd_dma_busy_wait(mfd);
 		}
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 9f6ea7d..9907109 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -47,9 +47,10 @@
 #define MIPI_DSI_PANEL_WVGA	1
 #define MIPI_DSI_PANEL_WVGA_PT	2
 #define MIPI_DSI_PANEL_FWVGA_PT	3
-#define MIPI_DSI_PANEL_WXGA	4
-
-#define DSI_PANEL_MAX	4
+#define MIPI_DSI_PANEL_WSVGA_PT	4
+#define MIPI_DSI_PANEL_QHD_PT 5
+#define MIPI_DSI_PANEL_WXGA	6
+#define DSI_PANEL_MAX	6
 
 enum {		/* mipi dsi panel */
 	DSI_VIDEO_MODE,
@@ -221,6 +222,17 @@
 #define DTYPE_PERIPHERAL_OFF	0x22
 #define DTYPE_PERIPHERAL_ON	0x32
 
+/*
+ * dcs response
+ */
+#define DTYPE_ACK_ERR_RESP      0x02
+#define DTYPE_EOT_RESP          0x08    /* end of tx */
+#define DTYPE_GEN_READ1_RESP    0x11    /* 1 parameter, short */
+#define DTYPE_GEN_READ2_RESP    0x12    /* 2 parameter, short */
+#define DTYPE_GEN_LREAD_RESP    0x1a
+#define DTYPE_DCS_LREAD_RESP    0x1c
+#define DTYPE_DCS_READ1_RESP    0x21    /* 1 parameter, short */
+#define DTYPE_DCS_READ2_RESP    0x22    /* 2 parameter, short */
 
 struct dsi_cmd_desc {
 	int dtype;
@@ -260,7 +272,7 @@
 void mipi_dsi_op_mode_config(int mode);
 void mipi_dsi_cmd_mode_ctrl(int enable);
 void mdp4_dsi_cmd_trigger(void);
-void mipi_dsi_cmd_mdp_sw_trigger(void);
+void mipi_dsi_cmd_mdp_start(void);
 void mipi_dsi_cmd_bta_sw_trigger(void);
 void mipi_dsi_ack_err_status(void);
 void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd);
@@ -275,6 +287,7 @@
 void mipi_dsi_post_kickoff_del(struct dsi_kickoff_action *act);
 void mipi_dsi_controller_cfg(int enable);
 void mipi_dsi_sw_reset(void);
+void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd);
 
 irqreturn_t mipi_dsi_isr(int irq, void *ptr);
 
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 0697aac..9caa154 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -41,10 +41,12 @@
 
 int mipi_dsi_clk_on;
 static struct completion dsi_dma_comp;
+static struct completion dsi_mdp_comp;
 static struct dsi_buf dsi_tx_buf;
 static int dsi_irq_enabled;
-static int dsi_cmd_trigger;
-static spinlock_t dsi_lock;
+static spinlock_t dsi_irq_lock;
+static spinlock_t dsi_mdp_lock;
+static int dsi_mdp_busy;
 
 static struct list_head pre_kickoff_list;
 static struct list_head post_kickoff_list;
@@ -52,54 +54,44 @@
 void mipi_dsi_init(void)
 {
 	init_completion(&dsi_dma_comp);
+	init_completion(&dsi_mdp_comp);
 	mipi_dsi_buf_alloc(&dsi_tx_buf, DSI_BUF_SIZE);
-	spin_lock_init(&dsi_lock);
+	spin_lock_init(&dsi_irq_lock);
+	spin_lock_init(&dsi_mdp_lock);
 
 	INIT_LIST_HEAD(&pre_kickoff_list);
 	INIT_LIST_HEAD(&post_kickoff_list);
 }
 
-void mipi_dsi_enable_irq(enum dsi_trigger_type type)
+void mipi_dsi_enable_irq(void)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&dsi_lock, flags);
-	if (type == DSI_CMD_MODE_DMA)
-		dsi_cmd_trigger = 1;
-
-	pr_debug("%s(): dsi_irq_enabled %u, dsi_cmd_trigger %u\n",
-		   __func__, dsi_irq_enabled, dsi_cmd_trigger);
-
+	spin_lock_irqsave(&dsi_irq_lock, flags);
 	if (dsi_irq_enabled) {
 		pr_debug("%s: IRQ aleady enabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_lock, flags);
+		spin_unlock_irqrestore(&dsi_irq_lock, flags);
 		return;
 	}
 	dsi_irq_enabled = 1;
 	enable_irq(dsi_irq);
-	spin_unlock_irqrestore(&dsi_lock, flags);
+	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
-void mipi_dsi_disable_irq(enum dsi_trigger_type type)
+void mipi_dsi_disable_irq(void)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&dsi_lock, flags);
-	if (type == DSI_CMD_MODE_DMA)
-		dsi_cmd_trigger = 0;
-
-	pr_debug("%s(): dsi_irq_enabled %u, dsi_cmd_trigger %u\n",
-		   __func__, dsi_irq_enabled, dsi_cmd_trigger);
-
+	spin_lock_irqsave(&dsi_irq_lock, flags);
 	if (dsi_irq_enabled == 0) {
 		pr_debug("%s: IRQ already disabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_lock, flags);
+		spin_unlock_irqrestore(&dsi_irq_lock, flags);
 		return;
 	}
 
 	dsi_irq_enabled = 0;
 	disable_irq(dsi_irq);
-	spin_unlock_irqrestore(&dsi_lock, flags);
+	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
 /*
@@ -108,19 +100,16 @@
  */
  void mipi_dsi_disable_irq_nosync(void)
 {
-	spin_lock(&dsi_lock);
-	pr_debug("%s(): dsi_irq_enabled %u, dsi_cmd_trigger %u\n",
-		   __func__, dsi_irq_enabled, dsi_cmd_trigger);
-
-	if (dsi_irq_enabled == 0 || dsi_cmd_trigger == 1) {
+	spin_lock(&dsi_irq_lock);
+	if (dsi_irq_enabled == 0) {
 		pr_debug("%s: IRQ cannot be disabled\n", __func__);
-		spin_unlock(&dsi_lock);
+		spin_unlock(&dsi_irq_lock);
 		return;
 	}
 
 	dsi_irq_enabled = 0;
 	disable_irq_nosync(dsi_irq);
-	spin_unlock(&dsi_lock);
+	spin_unlock(&dsi_irq_lock);
 }
 
 void mipi_dsi_turn_on_clks(void)
@@ -728,6 +717,43 @@
 	return len;
 }
 
+/*
+ * mipi_dsi_short_read1_resp: 1 parameter
+ */
+static int mipi_dsi_short_read1_resp(struct dsi_buf *rp)
+{
+	/* strip out dcs type */
+	rp->data++;
+	rp->len = 1;
+	return rp->len;
+}
+
+/*
+ * mipi_dsi_short_read2_resp: 2 parameter
+ */
+static int mipi_dsi_short_read2_resp(struct dsi_buf *rp)
+{
+	/* strip out dcs type */
+	rp->data++;
+	rp->len = 2;
+	return rp->len;
+}
+
+static int mipi_dsi_long_read_resp(struct dsi_buf *rp)
+{
+	short len;
+
+	len = rp->data[2];
+	len <<= 8;
+	len |= rp->data[1];
+	/* strip out dcs header */
+	rp->data += 4;
+	rp->len -= 4;
+	/* strip out 2 bytes of checksum */
+	rp->len -= 2;
+	return len;
+}
+
 void mipi_dsi_host_init(struct mipi_panel_info *pinfo)
 {
 	uint32 dsi_ctrl, intr_ctrl;
@@ -936,12 +962,42 @@
 	wmb();
 }
 
-void mipi_dsi_cmd_mdp_sw_trigger(void)
+void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd)
 {
-	mipi_dsi_pre_kickoff_action();
-	mipi_dsi_enable_irq(DSI_CMD_MODE_MDP);
-	MIPI_OUTP(MIPI_DSI_BASE + 0x090, 0x01);	/* trigger */
-	wmb();
+	unsigned long flag;
+	int need_wait = 0;
+
+	pr_debug("%s: start pid=%d\n",
+				__func__, current->pid);
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	if (dsi_mdp_busy == TRUE) {
+		INIT_COMPLETION(dsi_mdp_comp);
+		need_wait++;
+	}
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (need_wait) {
+		/* wait until DMA finishes the current job */
+		pr_debug("%s: pending pid=%d\n",
+				__func__, current->pid);
+		wait_for_completion(&dsi_mdp_comp);
+	}
+	pr_debug("%s: done pid=%d\n",
+				__func__, current->pid);
+}
+
+void mipi_dsi_cmd_mdp_start(void)
+{
+	unsigned long flag;
+
+
+	if (!in_interrupt())
+		mipi_dsi_pre_kickoff_action();
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mipi_dsi_enable_irq();
+	dsi_mdp_busy = TRUE;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 }
 
 
@@ -1024,6 +1080,7 @@
 	struct dsi_cmd_desc *cm;
 	uint32 dsi_ctrl, ctrl;
 	int i, video_mode;
+	unsigned long flag;
 
 	/* turn on cmd mode
 	* for video mode, do not send cmds more than
@@ -1050,7 +1107,11 @@
 		}
 	}
 
-	mipi_dsi_enable_irq(DSI_CMD_MODE_DMA);
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mipi_dsi_enable_irq();
+	dsi_mdp_busy = TRUE;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
 	cm = cmds;
 	mipi_dsi_buf_init(tp);
 	for (i = 0; i < cnt; i++) {
@@ -1061,7 +1122,12 @@
 			msleep(cm->wait);
 		cm++;
 	}
-	mipi_dsi_disable_irq(DSI_CMD_MODE_DMA);
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	dsi_mdp_busy = FALSE;
+	mipi_dsi_disable_irq();
+	complete(&dsi_mdp_comp);
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (video_mode)
 		MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); /* restore */
@@ -1091,10 +1157,14 @@
  */
 int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd,
 			struct dsi_buf *tp, struct dsi_buf *rp,
-			struct dsi_cmd_desc *cmds, int len)
+			struct dsi_cmd_desc *cmds, int rlen)
 {
-	int cnt;
-	static int pkt_size;
+	int cnt, len, diff, pkt_size;
+	unsigned long flag;
+	char cmd;
+
+	len = rlen;
+	diff = 0;
 
 	if (len <= 2)
 		cnt = 4;	/* short read */
@@ -1108,6 +1178,7 @@
 			len = MIPI_DSI_LEN;	/* 8 bytes at most */
 
 		len = (len + 3) & ~0x03; /* len 4 bytes align */
+		diff = len - rlen;
 		/*
 		 * add extra 2 bytes to len to have overall
 		 * packet size is multipe by 4. This also make
@@ -1128,16 +1199,17 @@
 #endif
 	}
 
-	mipi_dsi_enable_irq(DSI_CMD_MODE_DMA);
-	if (pkt_size != len) {
-		/* set new max pkt size */
-		pkt_size = len;
-		max_pktsize[0] = pkt_size;
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mipi_dsi_enable_irq();
+	dsi_mdp_busy = TRUE;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
-		mipi_dsi_buf_init(tp);
-		mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
-		mipi_dsi_cmd_dma_tx(tp);
-	}
+	/* packet size need to be set at every read */
+	pkt_size = len;
+	max_pktsize[0] = pkt_size;
+	mipi_dsi_buf_init(tp);
+	mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
+	mipi_dsi_cmd_dma_tx(tp);
 
 	mipi_dsi_buf_init(tp);
 	mipi_dsi_cmd_dma_add(tp, cmds);
@@ -1149,21 +1221,36 @@
 	 * return data from client is ready and stored
 	 * at RDBK_DATA register already
 	 */
+	mipi_dsi_buf_init(rp);
 	mipi_dsi_cmd_dma_rx(rp, cnt);
 
-	mipi_dsi_disable_irq(DSI_CMD_MODE_DMA);
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	dsi_mdp_busy = FALSE;
+	mipi_dsi_disable_irq();
+	complete(&dsi_mdp_comp);
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
-	/* strip off dcs header & crc */
-	if (cnt > 4) { /* long response */
-		if (mfd->panel_info.mipi.fixed_packet_size)
-			rp->data += (cnt - len - 6); /* skip padding */
-
-		rp->data += 4; /* skip dcs header */
-		rp->len -= 6; /* deduct 4 bytes header + 2 bytes crc */
+	cmd = rp->data[0];
+	switch (cmd) {
+	case DTYPE_ACK_ERR_RESP:
+		pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+		break;
+	case DTYPE_GEN_READ1_RESP:
+	case DTYPE_DCS_READ1_RESP:
+		mipi_dsi_short_read1_resp(rp);
+		break;
+	case DTYPE_GEN_READ2_RESP:
+	case DTYPE_DCS_READ2_RESP:
+		mipi_dsi_short_read2_resp(rp);
+		break;
+	case DTYPE_GEN_LREAD_RESP:
+	case DTYPE_DCS_LREAD_RESP:
+		mipi_dsi_long_read_resp(rp);
 		rp->len -= 2; /* extra 2 bytes added */
-	} else {
-		rp->data += 1; /* skip dcs short header */
-		rp->len -= 2; /* deduct 1 byte header + 1 byte ecc */
+		rp->len -= diff; /* align bytes */
+		break;
+	default:
+		break;
 	}
 
 	return rp->len;
@@ -1343,6 +1430,10 @@
 	}
 
 	if (isr & DSI_INTR_CMD_MDP_DONE) {
+		spin_lock(&dsi_mdp_lock);
+		dsi_mdp_busy = FALSE;
+		spin_unlock(&dsi_mdp_lock);
+		complete(&dsi_mdp_comp);
 		mipi_dsi_disable_irq_nosync();
 		mipi_dsi_post_kickoff_action();
 	}
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index d467581..1ff950d 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -24,7 +24,7 @@
 
 static struct dsi_buf novatek_tx_buf;
 static struct dsi_buf novatek_rx_buf;
-
+static int mipi_novatek_lcd_init(void);
 
 #define MIPI_DSI_NOVATEK_SPI_DEVICE_NAME	"dsi_novatek_3d_panel_spi"
 #define HPCI_FPGA_READ_CMD	0x84
@@ -312,9 +312,6 @@
 
 	tp = &novatek_tx_buf;
 	rp = &novatek_rx_buf;
-	mipi_dsi_buf_init(rp);
-	mipi_dsi_buf_init(tp);
-
 	cmd = &novatek_manufacture_id_cmd;
 	mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 3);
 	lp = (uint32 *)rp->data;
@@ -445,6 +442,7 @@
 	/* mdp4_dsi_cmd_busy_wait: will turn on dsi clock also */
 	mdp4_dsi_cmd_dma_busy_wait(mfd);
 	mdp4_dsi_blt_dmap_busy_wait(mfd);
+	mipi_dsi_mdp_busy_wait(mfd);
 
 	led_pwm1[1] = (unsigned char)(mfd->bl_level);
 	mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_cmd_backlight_cmds,
@@ -585,6 +583,12 @@
 
 	ch_used[channel] = TRUE;
 
+	ret = mipi_novatek_lcd_init();
+	if (ret) {
+		pr_err("mipi_novatek_lcd_init() failed with ret %u\n", ret);
+		return ret;
+	}
+
 	pdev = platform_device_alloc("mipi_novatek", (panel << 8)|channel);
 	if (!pdev)
 		return -ENOMEM;
@@ -613,7 +617,7 @@
 	return ret;
 }
 
-static int __init mipi_novatek_lcd_init(void)
+static int mipi_novatek_lcd_init(void)
 {
 #ifdef CONFIG_SPI_QUP
 	int ret;
@@ -631,5 +635,3 @@
 
 	return platform_driver_register(&this_driver);
 }
-
-module_init(mipi_novatek_lcd_init);
diff --git a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
index aaf86ae..fbd2495 100644
--- a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
@@ -39,10 +39,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_cmd_novatek_qhd"))
 		return 0;
-#endif
 
 	pinfo.xres = 540;
 	pinfo.yres = 960;
@@ -81,7 +79,7 @@
 	pinfo.mipi.t_clk_post = 0x22;
 	pinfo.mipi.t_clk_pre = 0x3f;
 	pinfo.mipi.stream = 0;	/* dma_p */
-	pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW;
+	pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE;
 	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
 	pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */
 	pinfo.mipi.interleave_max = 1;
@@ -91,7 +89,7 @@
 	pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db;
 
 	ret = mipi_novatek_device_register(&pinfo, MIPI_DSI_PRIM,
-						MIPI_DSI_PANEL_WVGA_PT);
+						MIPI_DSI_PANEL_QHD_PT);
 	if (ret)
 		pr_err("%s: failed to register device!\n", __func__);
 
diff --git a/drivers/video/msm/mipi_novatek_video_qhd_pt.c b/drivers/video/msm/mipi_novatek_video_qhd_pt.c
index 635b66e..42ddfbe 100644
--- a/drivers/video/msm/mipi_novatek_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_novatek_video_qhd_pt.c
@@ -39,10 +39,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_video_novatek_qhd"))
 		return 0;
-#endif
 
 	pinfo.xres = 540;
 	pinfo.yres = 960;
@@ -88,7 +86,7 @@
 	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
 
 	ret = mipi_novatek_device_register(&pinfo, MIPI_DSI_PRIM,
-						MIPI_DSI_PANEL_WVGA_PT);
+						MIPI_DSI_PANEL_QHD_PT);
 	if (ret)
 		pr_err("%s: failed to register device!\n", __func__);
 
diff --git a/drivers/video/msm/mipi_renesas.c b/drivers/video/msm/mipi_renesas.c
index f0d424f..6a7027a 100644
--- a/drivers/video/msm/mipi_renesas.c
+++ b/drivers/video/msm/mipi_renesas.c
@@ -22,6 +22,8 @@
 static struct dsi_buf renesas_tx_buf;
 static struct dsi_buf renesas_rx_buf;
 
+static int mipi_renesas_lcd_init(void);
+
 static char config_sleep_out[2] = {0x11, 0x00};
 static char config_CMD_MODE[2] = {0x40, 0x01};
 static char config_WRTXHT[7] = {0x92, 0x16, 0x08, 0x08, 0x00, 0x01, 0xe0};
@@ -1219,6 +1221,12 @@
 
 	ch_used[channel] = TRUE;
 
+	ret = mipi_renesas_lcd_init();
+	if (ret) {
+		pr_err("mipi_renesas_lcd_init() failed with ret %u\n", ret);
+		return ret;
+	}
+
 	pdev = platform_device_alloc("mipi_renesas", (panel << 8)|channel);
 	if (!pdev)
 		return -ENOMEM;
@@ -1245,12 +1253,10 @@
 	return ret;
 }
 
-static int __init mipi_renesas_lcd_init(void)
+static int mipi_renesas_lcd_init(void)
 {
 	mipi_dsi_buf_alloc(&renesas_tx_buf, DSI_BUF_SIZE);
 	mipi_dsi_buf_alloc(&renesas_rx_buf, DSI_BUF_SIZE);
 
 	return platform_driver_register(&this_driver);
 }
-
-module_init(mipi_renesas_lcd_init);
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 796fbd2..7f5ac70 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
@@ -57,10 +57,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_cmd_renesas_fwvga"))
 		return 0;
-#endif
 
 	pinfo.xres = 480;
 	pinfo.yres = 864;
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index 0e49011..e826773 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
@@ -59,10 +59,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_video_renesas_fwvga"))
 		return 0;
-#endif
 
 	pinfo.xres = 480;
 	pinfo.yres = 864;
diff --git a/drivers/video/msm/mipi_simulator.c b/drivers/video/msm/mipi_simulator.c
index da697b5..c6bf534 100644
--- a/drivers/video/msm/mipi_simulator.c
+++ b/drivers/video/msm/mipi_simulator.c
@@ -18,6 +18,8 @@
 static struct dsi_buf simulator_rx_buf;
 static struct msm_panel_common_pdata *mipi_simulator_pdata;
 
+static int mipi_simulator_lcd_init(void);
+
 static char display_on[2]  = {0x00, 0x00};
 static char display_off[2] = {0x00, 0x00};
 
@@ -122,6 +124,11 @@
 	ch_used[channel] = TRUE;
 
 	pr_debug("%s:%d, debug info", __func__, __LINE__);
+	ret = mipi_simulator_lcd_init();
+	if (ret) {
+		pr_err("mipi_simulator_lcd_init() failed with ret %u\n", ret);
+		return ret;
+	}
 
 	pdev = platform_device_alloc("mipi_simulator", (panel << 8)|channel);
 	if (!pdev)
@@ -151,12 +158,10 @@
 	return ret;
 }
 
-static int __init mipi_simulator_lcd_init(void)
+static int mipi_simulator_lcd_init(void)
 {
 	mipi_dsi_buf_alloc(&simulator_tx_buf, DSI_BUF_SIZE);
 	mipi_dsi_buf_alloc(&simulator_rx_buf, DSI_BUF_SIZE);
 
 	return platform_driver_register(&this_driver);
 }
-
-module_init(mipi_simulator_lcd_init);
diff --git a/drivers/video/msm/mipi_simulator_video.c b/drivers/video/msm/mipi_simulator_video.c
index 8795554..845df75 100644
--- a/drivers/video/msm/mipi_simulator_video.c
+++ b/drivers/video/msm/mipi_simulator_video.c
@@ -31,10 +31,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
-	if (msm_fb_detect_client("mipi_video_simulator"))
+	if (msm_fb_detect_client("mipi_video_simulator_vga"))
 		return 0;
-#endif
 	pinfo.xres = 640;
 	pinfo.yres = 480;
 	pinfo.type = MIPI_VIDEO_PANEL;
@@ -78,7 +76,7 @@
 	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
 
 	ret = mipi_simulator_device_register(&pinfo, MIPI_DSI_PRIM,
-		MIPI_DSI_PANEL_FWVGA_PT);
+		MIPI_DSI_PANEL_VGA);
 	if (ret)
 		pr_err("%s: failed to register device!\n", __func__);
 
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index 491afad..b1cdf78 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -70,6 +70,7 @@
 #include <linux/pwm.h>
 #include "msm_fb.h"
 #include "mipi_dsi.h"
+#include "mipi_tc358764_dsi2lvds.h"
 
 /* Registers definition */
 
@@ -215,6 +216,7 @@
 static int bl_level;
 static u32 d2l_gpio_out_mask;
 static u32 d2l_gpio_out_val;
+static int mipi_d2l_init(void);
 
 /**
  * Read a bridge register
@@ -607,6 +609,50 @@
 	return 0;
 }
 
+/**
+ * Register the panel device.
+ *
+ * @param pinfo
+ * @param channel_id
+ * @param panel_id
+ *
+ * @return int
+ */
+int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo,
+					   u32 channel_id, u32 panel_id)
+{
+	struct platform_device *pdev = NULL;
+	int ret;
+	/* Use DSI-to-LVDS bridge */
+	const char driver_name[] = "mipi_tc358764";
+
+	pr_debug("%s.\n", __func__);
+	ret = mipi_d2l_init();
+	if (ret) {
+		pr_err("mipi_d2l_init() failed with ret %u\n", ret);
+		return ret;
+	}
+
+	/* Note: the device id should be non-zero */
+	pdev = platform_device_alloc(driver_name, (panel_id << 8)|channel_id);
+	if (pdev == NULL)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pinfo;
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		pr_err("%s: platform_device_register failed!\n", __func__);
+		goto err_device_put;
+	}
+
+	return 0;
+
+err_device_put:
+	platform_device_put(pdev);
+	return ret;
+}
+
 static struct platform_driver d2l_driver = {
 	.probe  = mipi_d2l_probe,
 	.remove = __devexit_p(mipi_d2l_remove),
@@ -620,29 +666,12 @@
  *
  * @return int
  */
-static int __init mipi_d2l_init(void)
+static int mipi_d2l_init(void)
 {
 	pr_debug("%s.\n", __func__);
-
-	d2l_common_pdata = NULL;
-
 	return platform_driver_register(&d2l_driver);
 }
 
-/**
- * Module Exit.
- *
- */
-static void __exit mipi_d2l_exit(void)
-{
-	pr_debug("%s.\n", __func__);
-
-	platform_driver_unregister(&d2l_driver);
-}
-
-module_init(mipi_d2l_init);
-module_exit(mipi_d2l_exit);
-
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Toshiba MIPI-DSI-to-LVDS bridge driver");
 MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.h b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
new file mode 100644
index 0000000..072d1f4
--- /dev/null
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MIPI_TC358764_DSI2LVDS_H
+#define MIPI_TC358764_DSI2LVDS_H
+
+int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo,
+	u32 channel_id, u32 panel_id);
+#endif  /* MIPI_TC358764_DSI2LVDS_H */
diff --git a/drivers/video/msm/mipi_toshiba.c b/drivers/video/msm/mipi_toshiba.c
index 9e5d06a..5788f27 100644
--- a/drivers/video/msm/mipi_toshiba.c
+++ b/drivers/video/msm/mipi_toshiba.c
@@ -18,9 +18,11 @@
 static struct pwm_device *bl_lpm;
 static struct mipi_dsi_panel_platform_data *mipi_toshiba_pdata;
 
+#define TM_GET_PID(id) (((id) & 0xff00)>>8)
 
 static struct dsi_buf toshiba_tx_buf;
 static struct dsi_buf toshiba_rx_buf;
+static int mipi_toshiba_lcd_init(void);
 
 #ifdef TOSHIBA_CMDS_UNUSED
 static char one_lane[3] = {0xEF, 0x60, 0x62};
@@ -37,7 +39,6 @@
 static char display_off[2] = {0x28, 0x00};
 static char enter_sleep[2] = {0x10, 0x00};
 
-#ifdef CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
 static char mcap_off[2] = {0xb2, 0x00};
 static char ena_test_reg[3] = {0xEF, 0x01, 0x01};
 static char two_lane[3] = {0xEF, 0x60, 0x63};
@@ -49,7 +50,7 @@
 static char hor_addr_2B_wvga[5] = {0x2B, 0x00, 0x00, 0x03, 0x55};
 static char if_sel_video[2] = {0x53, 0x01};
 
-static struct dsi_cmd_desc toshiba_display_on_cmds[] = {
+static struct dsi_cmd_desc toshiba_wvga_display_on_cmds[] = {
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(mcap_off), mcap_off},
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(ena_test_reg), ena_test_reg},
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(two_lane), two_lane},
@@ -69,9 +70,6 @@
 	{DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(display_on), display_on}
 };
 
-#endif
-
-#ifdef CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT
 static char mcap_start[2] = {0xb0, 0x04};
 static char num_out_pixelform[3] = {0xb3, 0x00, 0x87};
 static char dsi_ctrl[3] = {0xb6, 0x30, 0x83};
@@ -135,7 +133,7 @@
 static char set_pixel_format[2] = {0x3a, 0x70};
 
 
-static struct dsi_cmd_desc toshiba_display_on_cmds[] = {
+static struct dsi_cmd_desc toshiba_wsvga_display_on_cmds[] = {
 	{DTYPE_GEN_WRITE2, 1, 0, 0, 10, sizeof(mcap_start), mcap_start},
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 10, sizeof(num_out_pixelform),
 		num_out_pixelform},
@@ -177,7 +175,6 @@
 	{DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(exit_sleep), exit_sleep},
 	{DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_on), display_on}
 };
-#endif
 
 static struct dsi_cmd_desc toshiba_display_off_cmds[] = {
 	{DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_off), display_off},
@@ -195,8 +192,16 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf, toshiba_display_on_cmds,
-			ARRAY_SIZE(toshiba_display_on_cmds));
+	if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WVGA_PT)
+		mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf,
+			toshiba_wvga_display_on_cmds,
+			ARRAY_SIZE(toshiba_wvga_display_on_cmds));
+	else if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WSVGA_PT)
+		mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf,
+			toshiba_wsvga_display_on_cmds,
+			ARRAY_SIZE(toshiba_wsvga_display_on_cmds));
+	else
+		return -EINVAL;
 
 	return 0;
 }
@@ -296,6 +301,12 @@
 
 	ch_used[channel] = TRUE;
 
+	ret = mipi_toshiba_lcd_init();
+	if (ret) {
+		pr_err("mipi_toshiba_lcd_init() failed with ret %u\n", ret);
+		return ret;
+	}
+
 	pdev = platform_device_alloc("mipi_toshiba", (panel << 8)|channel);
 	if (!pdev)
 		return -ENOMEM;
@@ -324,12 +335,10 @@
 	return ret;
 }
 
-static int __init mipi_toshiba_lcd_init(void)
+static int mipi_toshiba_lcd_init(void)
 {
 	mipi_dsi_buf_alloc(&toshiba_tx_buf, DSI_BUF_SIZE);
 	mipi_dsi_buf_alloc(&toshiba_rx_buf, DSI_BUF_SIZE);
 
 	return platform_driver_register(&this_driver);
 }
-
-module_init(mipi_toshiba_lcd_init);
diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
index 3602e75..ed34aa7 100644
--- a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
@@ -38,10 +38,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_video_toshiba_wsvga"))
 		return 0;
-#endif
 
 	pinfo.xres = 600;
 	pinfo.yres = 1024;
@@ -96,7 +94,7 @@
 	pinfo.mipi.tx_eot_append = TRUE;
 
 	ret = mipi_toshiba_device_register(&pinfo, MIPI_DSI_PRIM,
-						MIPI_DSI_PANEL_WVGA_PT);
+						MIPI_DSI_PANEL_WSVGA_PT);
 	if (ret)
 		printk(KERN_ERR "%s: failed to register device!\n", __func__);
 
diff --git a/drivers/video/msm/mipi_toshiba_video_wvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wvga_pt.c
index 1913513..d6cabfc 100644
--- a/drivers/video/msm/mipi_toshiba_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wvga_pt.c
@@ -52,10 +52,8 @@
 {
 	int ret;
 
-#ifdef CONFIG_FB_MSM_MIPI_PANEL_DETECT
 	if (msm_fb_detect_client("mipi_video_toshiba_wvga"))
 		return 0;
-#endif
 
 	pinfo.xres = 480;
 	pinfo.yres = 864; /* 856 for V1 surf */
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 542eea4..bde0573 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -188,25 +188,42 @@
 };
 #endif
 
+#define PANEL_NAME_MAX_LEN 30
 static struct msm_fb_platform_data *msm_fb_pdata;
-static char panel_name[128];
-module_param_string(panel_name, panel_name, sizeof(panel_name) , 0);
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+module_param_string(prim_display, prim_panel_name, sizeof(prim_panel_name) , 0);
+module_param_string(ext_display, ext_panel_name, sizeof(ext_panel_name) , 0);
 
 int msm_fb_detect_client(const char *name)
 {
-	int ret = -EPERM;
+	int ret = 0;
+	u32 len;
 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
 	u32 id;
 #endif
-
-	MSM_FB_DEBUG("\n name = %s, panel_name = %s", name, panel_name);
-	if (strlen(panel_name)) {
-		if (!strcmp((char *)panel_name, name))
+	len = strnlen(name, PANEL_NAME_MAX_LEN);
+	if (strnlen(prim_panel_name, PANEL_NAME_MAX_LEN)) {
+		MSM_FB_DEBUG("\n name = %s, prim_display = %s",
+			name, prim_panel_name);
+		if (!strncmp((char *)prim_panel_name, name, len))
 			return 0;
 		else
-			return -EPERM;
+			ret = -EPERM;
+	}
+	if (strnlen(ext_panel_name, PANEL_NAME_MAX_LEN)) {
+		MSM_FB_DEBUG("\n name = %s, ext_display = %s",
+			name, ext_panel_name);
+		if (!strncmp((char *)ext_panel_name, name, len))
+			return 0;
+		else
+			ret = -EPERM;
 	}
 
+	if (ret)
+		return ret;
+
+	ret = -EPERM;
 	if (msm_fb_pdata && msm_fb_pdata->detect_client) {
 		ret = msm_fb_pdata->detect_client(name);
 
diff --git a/drivers/video/msm/tvout_msm.c b/drivers/video/msm/tvout_msm.c
index 6912961..9ee55cc 100644
--- a/drivers/video/msm/tvout_msm.c
+++ b/drivers/video/msm/tvout_msm.c
@@ -601,6 +601,10 @@
 static int __init tvout_init(void)
 {
 	int ret;
+
+	if (msm_fb_detect_client("tvout_msm"))
+		return 0;
+
 	tvout_msm_state = kzalloc(sizeof(*tvout_msm_state), GFP_KERNEL);
 	if (!tvout_msm_state) {
 		DEV_ERR("tvout_msm_init FAILED: out of memory\n");
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index abe2216..bb26c51 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1660,8 +1660,11 @@
 
 	if (!decoder->codec.codec)
 		return false;
-	min_dpb = ddl_decoder_min_num_dpb(decoder);
 	if (estimate) {
+		if (!decoder->cont_mode)
+			min_dpb = ddl_decoder_min_num_dpb(decoder);
+		else
+			min_dpb = 5;
 		frame_size = &decoder->client_frame_size;
 		output_buf_req = &decoder->client_output_buf_req;
 		input_buf_req = &decoder->client_input_buf_req;
@@ -1678,7 +1681,7 @@
 	}
 	memset(output_buf_req, 0,
 		sizeof(struct vcd_buffer_requirement));
-	if ((!estimate && !decoder->idr_only_decoding) || (decoder->cont_mode))
+	if (!estimate && !decoder->idr_only_decoding && !decoder->cont_mode)
 		output_buf_req->actual_count = min_dpb + 4;
 	else
 		output_buf_req->actual_count = min_dpb;
@@ -1699,7 +1702,7 @@
 	input_buf_req->min_count = 1;
 	input_buf_req->actual_count = input_buf_req->min_count + 1;
 	input_buf_req->max_count = DDL_MAX_BUFFER_COUNT;
-	input_buf_req->sz = (1024 * 1024);
+	input_buf_req->sz = (1024 * 1024 * 2);
 	input_buf_req->align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
 	decoder->min_input_buf_req = *input_buf_req;
 	return true;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 501a4592..8f745ec 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -47,16 +47,16 @@
 		goto bail_out;
 	}
 	resource_context.vcodec_clk = clk_get(resource_context.device,
-		"vcodec_clk");
+		"core_clk");
 	if (IS_ERR(resource_context.vcodec_clk)) {
-		VCDRES_MSG_ERROR("%s(): vcodec_clk get failed\n",
+		VCDRES_MSG_ERROR("%s(): core_clk get failed\n",
 						__func__);
 		goto bail_out;
 	}
 	 resource_context.vcodec_pclk = clk_get(resource_context.device,
-			"vcodec_pclk");
+		"iface_clk");
 	if (IS_ERR(resource_context.vcodec_pclk)) {
-		VCDRES_MSG_ERROR("%s(): vcodec_pclk get failed\n",
+		VCDRES_MSG_ERROR("%s(): iface_clk get failed\n",
 						__func__);
 		goto release_vcodec_clk;
 	}
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index fe3bfaa..54d48b8 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -277,29 +277,29 @@
 							__func__, rc);
 
 		resource_context.pclk = clk_get(resource_context.device,
-			"mfc_pclk");
+			"iface_clk");
 
 		if (IS_ERR(resource_context.pclk)) {
-			VCDRES_MSG_ERROR("%s(): mfc_pclk get failed\n"
+			VCDRES_MSG_ERROR("%s(): iface_clk get failed\n"
 							 , __func__);
 			goto disable_regulator;
 		}
 
 		resource_context.hclk = clk_get(resource_context.device,
-			"mfc_clk");
+			"core_clk");
 
 		if (IS_ERR(resource_context.hclk)) {
-			VCDRES_MSG_ERROR("%s(): mfc_clk get failed\n"
+			VCDRES_MSG_ERROR("%s(): core_clk get failed\n"
 							 , __func__);
 
 			goto release_pclk;
 		}
 
 		resource_context.hclk_div2 =
-			clk_get(resource_context.device, "mfc_div2_clk");
+			clk_get(resource_context.device, "core_div2_clk");
 
 		if (IS_ERR(resource_context.hclk_div2)) {
-			VCDRES_MSG_ERROR("%s(): mfc_div2_clk get failed\n"
+			VCDRES_MSG_ERROR("%s(): core_div2_clk get failed\n"
 							 , __func__);
 			goto release_hclk_pclk;
 		}
@@ -407,7 +407,7 @@
 {
 	VCDRES_MSG_MED("\n res_trk_power_up():: "
 		"Calling AXI add requirement\n");
-	ebi1_clk = clk_get(NULL, "ebi1_vcd_clk");
+	ebi1_clk = clk_get(NULL, "mem_clk");
 	if (IS_ERR(ebi1_clk)) {
 		VCDRES_MSG_ERROR("Request AXI bus QOS fails.");
 		return false;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index a69b810..0d8fcc2 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -411,21 +411,24 @@
 	return !islist_empty;
 }
 
-static u32 vid_enc_get_next_msg(struct video_client_ctx *client_ctx,
+static int vid_enc_get_next_msg(struct video_client_ctx *client_ctx,
 		struct venc_msg *venc_msg_info)
 {
 	int rc;
 	struct vid_enc_msg *vid_enc_msg = NULL;
 
 	if (!client_ctx)
-		return false;
+		return -EIO;
 
 	rc = wait_event_interruptible(client_ctx->msg_wait,
 		vid_enc_msg_pending(client_ctx));
 
-	if (rc < 0 || client_ctx->stop_msg) {
-		DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
-		return false;
+	if (rc < 0) {
+		DBG("rc = %d,stop_msg= %u\n", rc, client_ctx->stop_msg);
+		return rc;
+	} else if (client_ctx->stop_msg) {
+		DBG("stopped stop_msg = %u\n", client_ctx->stop_msg);
+		return -EIO;
 	}
 
 	mutex_lock(&client_ctx->msg_queue_lock);
@@ -440,7 +443,7 @@
 		kfree(vid_enc_msg);
 	}
 	mutex_unlock(&client_ctx->msg_queue_lock);
-	return true;
+	return 0;
 }
 
 static u32 vid_enc_close_client(struct video_client_ctx *client_ctx)
@@ -727,6 +730,7 @@
 	struct venc_ioctl_msg venc_msg;
 	void __user *arg = (void __user *)u_arg;
 	u32 result = true;
+	int result_read = -1;
 
 	DBG("%s\n", __func__);
 
@@ -743,9 +747,9 @@
 		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
 			return -EFAULT;
 		DBG("VEN_IOCTL_CMD_READ_NEXT_MSG\n");
-		result = vid_enc_get_next_msg(client_ctx, &cb_msg);
-		if (!result)
-			return -EIO;
+		result_read = vid_enc_get_next_msg(client_ctx, &cb_msg);
+		if (result_read < 0)
+			return result_read;
 		if (copy_to_user(venc_msg.out, &cb_msg, sizeof(cb_msg)))
 			return -EFAULT;
 		break;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 22270de..91d67d5 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -18,10 +18,11 @@
 #define EVENT_MASKS_TYPE		4
 #define PKT_TYPE			8
 #define DEINIT_TYPE			16
-#define MEMORY_DEVICE_LOG_TYPE		32
+#define USER_SPACE_LOG_TYPE		32
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
+#define UART_MODE			4
 
 /* different values that go in for diag_data_type */
 #define DATA_TYPE_EVENT         	0
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 91cbbda..df44376 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -17,9 +17,11 @@
 #ifndef _LINUX_ION_H
 #define _LINUX_ION_H
 
+#include <linux/ioctl.h>
 #include <linux/types.h>
 #include <mach/ion.h>
 
+
 struct ion_handle;
 /**
  * enum ion_heap_types - list of all possible types of heaps
@@ -69,6 +71,8 @@
 
 #define ION_SET_CACHE(__cache)  ((__cache) << ION_CACHE_SHIFT)
 
+#define ION_IS_CACHED(__flags)	((__flags) & (1 << ION_CACHE_SHIFT))
+
 #ifdef __KERNEL__
 struct ion_device;
 struct ion_heap;
@@ -328,6 +332,24 @@
 	unsigned long arg;
 };
 
+
+/* struct ion_flush_data - data passed to ion for flushing caches
+ *
+ * @handle:	handle with data to flush
+ * @vaddr:	userspace virtual address mapped with mmap
+ * @offset:	offset into the handle to flush
+ * @length:	length of handle to flush
+ *
+ * Performs cache operations on the handle. If p is the start address
+ * of the handle, p + offset through p + offset + length will have
+ * the cache operations performed
+ */
+struct ion_flush_data {
+	struct ion_handle *handle;
+	void *vaddr;
+	unsigned int offset;
+	unsigned int length;
+};
 #define ION_IOC_MAGIC		'I'
 
 /**
@@ -384,4 +406,26 @@
  */
 #define ION_IOC_CUSTOM		_IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
 
+
+/**
+ * DOC: ION_IOC_CLEAN_CACHES - clean the caches
+ *
+ * Clean the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_CACHES	_IOWR(ION_IOC_MAGIC, 7, \
+						struct ion_flush_data)
+/**
+ * DOC: ION_MSM_IOC_INV_CACHES - invalidate the caches
+ *
+ * Invalidate the caches of the handle specified.
+ */
+#define ION_IOC_INV_CACHES	_IOWR(ION_IOC_MAGIC, 8, \
+						struct ion_flush_data)
+/**
+ * DOC: ION_MSM_IOC_CLEAN_CACHES - clean and invalidate the caches
+ *
+ * Clean and invalidate the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_INV_CACHES	_IOWR(ION_IOC_MAGIC, 9, \
+						struct ion_flush_data)
 #endif /* _LINUX_ION_H */
diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 4096355..edd3c28 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -13,16 +13,10 @@
 #ifndef __LEDS_PM8XXX_H__
 #define __LEDS_PM8XXX_H__
 
+#include <linux/kernel.h>
 
 #define PM8XXX_LEDS_DEV_NAME	"pm8xxx-led"
 
-#define PM8XXX_LED_ID_SHIFT		0
-#define PM8XXX_LED_MODE_SHIFT		4
-#define PM8XXX_LED_MAX_CURRENT_SHIFT	8
-#define PM8XXX_LED_ID_MASK		0xF
-#define PM8XXX_LED_MODE_MASK		0xF0
-#define PM8XXX_LED_MAX_CURRENT_MASK	0xFFFF00
-
 /**
  * enum pm8xxx_leds - PMIC8XXX supported led ids
  * @PM8XXX_ID_LED_KB_LIGHT - keyboard backlight led
@@ -55,4 +49,30 @@
 	PM8XXX_LED_MODE_DTEST4
 };
 
+/**
+ * pm8xxx_led_config - led configuration parameters
+ * id - LED id
+ * mode - LED mode
+ * max_current - maximum current that LED can sustain
+ */
+struct pm8xxx_led_config {
+	u8	id;
+	u8	mode;
+	u16	max_current;
+};
+
+/**
+ * pm8xxx_led_platform_data - platform data for LED
+ * led_core - array of LEDs. Each datum in array contains
+ *	core data for the LED
+ * configs - array of platform configuration parameters
+ *	for each LED. It maps one-to-one with
+ *	array of LEDs
+ * num_configs - count of members of configs array
+ */
+struct pm8xxx_led_platform_data {
+	struct	led_platform_data	*led_core;
+	struct	pm8xxx_led_config	*configs;
+	u32				num_configs;
+};
 #endif /* __LEDS_PM8XXX_H__ */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index bde5bbc..64bdab1 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -33,7 +33,7 @@
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
-#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
 #include <linux/mfd/pm8xxx/vibrator.h>
 
 #define PM8921_NR_IRQS		256
@@ -126,7 +126,7 @@
 	struct pm8921_regulator_platform_data	*regulator_pdatas;
 	int					num_regulators;
 	struct pm8921_adc_platform_data		*adc_pdata;
-	struct led_platform_data		*leds_pdata;
+	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
 };
 
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3c47a92..4c9b53e 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -239,11 +239,26 @@
 	uint32_t       vb;
 };
 
-struct msm_isp_stats_event_ctrl {
+struct msm_mctl_pp_cmd_ack_event {
+	uint32_t cmd;        /* VPE_CMD_ZOOM? */
+	int      status;     /* 0 done, < 0 err */
+	uint32_t cookie;     /* daemon's cookie */
+};
+
+struct msm_mctl_pp_event_info {
+	int32_t  event;
+	union {
+		struct msm_mctl_pp_cmd_ack_event ack;
+	};
+};
+
+struct msm_isp_event_ctrl {
 	unsigned short resptype;
 	union {
 		struct msm_cam_evt_msg isp_msg;
 		struct msm_ctrl_cmd ctrl;
+		struct msm_cam_evt_divert_frame div_frame;
+		struct msm_mctl_pp_event_info pp_event_info;
 	} isp_data;
 };
 
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index fd46692..bd69d46 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -273,12 +273,6 @@
 	/* TBD: 3D related */
 };
 
-struct msm_mctl_pp_cmd_ack_event {
-	uint32_t cmd;        /* VPE_CMD_ZOOM? */
-	int      status;     /* 0 done, < 0 err */
-	uint32_t cookie;     /* daemon's cookie */
-};
-
 struct msm_pp_frame_sp {
 	unsigned long  phy_addr;
 	uint32_t       y_off;
@@ -307,13 +301,5 @@
 	};
 };
 
-struct msm_mctl_pp_event_info {
-	int32_t  event;
-	union {
-		struct msm_mctl_pp_cmd_ack_event ack;
-	};
-};
-
-
 #endif /*__MSM_ISP_H__*/
 
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index d5a3009..dc154f2 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -244,6 +244,7 @@
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 	struct irqaction *action;
+	int mask_this_irq = 0;
 	irqreturn_t action_ret;
 
 	might_sleep();
@@ -253,8 +254,10 @@
 	kstat_incr_irqs_this_cpu(irq, desc);
 
 	action = desc->action;
-	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data)))
+	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
+		mask_this_irq = 1;
 		goto out_unlock;
+	}
 
 	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
 	raw_spin_unlock_irq(&desc->lock);
@@ -268,6 +271,11 @@
 
 out_unlock:
 	raw_spin_unlock_irq(&desc->lock);
+	if (unlikely(mask_this_irq)) {
+		chip_bus_lock(desc);
+		mask_irq(desc);
+		chip_bus_sync_unlock(desc);
+	}
 }
 EXPORT_SYMBOL_GPL(handle_nested_irq);
 
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 9f77f61..e9f49b5 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -386,7 +386,8 @@
 	if (debug_mask & DEBUG_SUSPEND)
 		pr_info("power_suspend_late return %d\n", ret);
 
-	msm_suspend_check_done = 1;
+	if (ret == 0)
+		msm_suspend_check_done = 1;
 	return ret;
 }
 
diff --git a/kernel/printk.c b/kernel/printk.c
index ccdfac7..bddd32b 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -53,10 +53,6 @@
 
 #define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
 
-#ifdef        CONFIG_DEBUG_LL
-extern void printascii(char *);
-#endif
-
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
@@ -928,9 +924,6 @@
 	printed_len += vscnprintf(printk_buf + printed_len,
 				  sizeof(printk_buf) - printed_len, fmt, args);
 
-#ifdef	CONFIG_DEBUG_LL
-	printascii(printk_buf);
-#endif
 
 	p = printk_buf;
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 079538b..733e9d2 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -50,10 +50,13 @@
 	struct hci_dev *hdev = conn->hdev;
 	struct hci_cp_le_create_conn cp;
 
+	BT_DBG("%p", conn);
+
 	conn->state = BT_CONNECT;
 	conn->out = 1;
 	conn->link_mode |= HCI_LM_MASTER;
 	conn->sec_level = BT_SECURITY_LOW;
+	conn->type = LE_LINK;
 
 	memset(&cp, 0, sizeof(cp));
 	cp.scan_interval = cpu_to_le16(0x0004);
@@ -300,9 +303,6 @@
 
 	BT_DBG("conn %p state %d", conn, conn->state);
 
-	if (atomic_read(&conn->refcnt))
-		return;
-
 	hci_dev_lock(hdev);
 
 	switch (conn->state) {
@@ -317,11 +317,14 @@
 		break;
 	case BT_CONFIG:
 	case BT_CONNECTED:
-		reason = hci_proto_disconn_ind(conn);
-		hci_acl_disconn(conn, reason);
+		if (!atomic_read(&conn->refcnt)) {
+			reason = hci_proto_disconn_ind(conn);
+			hci_acl_disconn(conn, reason);
+		}
 		break;
 	default:
-		conn->state = BT_CLOSED;
+		if (!atomic_read(&conn->refcnt))
+			conn->state = BT_CLOSED;
 		break;
 	}
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ad88382..699284a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1401,7 +1401,7 @@
 int hci_register_dev(struct hci_dev *hdev)
 {
 	struct list_head *head = &hci_dev_list, *p;
-	int i, id = 0;
+	int i, id;
 
 	BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
 						hdev->bus, hdev->owner);
@@ -1409,6 +1409,8 @@
 	if (!hdev->open || !hdev->close || !hdev->destruct)
 		return -EINVAL;
 
+	id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
+
 	write_lock_bh(&hci_dev_list_lock);
 
 	/* Find first available device id */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e2d6490..da8b780 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1352,6 +1352,10 @@
 			else
 				BT_ERR("No memory for new connection");
 		}
+
+		if (conn)
+			mod_timer(&conn->disc_timer,
+					jiffies + msecs_to_jiffies(5000));
 	}
 
 	hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d103bef6..dea21c1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -909,6 +909,37 @@
 	}
 }
 
+/* Find socket with fixed cid with given source and destination bdaddrs.
+ * Returns closest match, locked.
+ */
+static struct sock *l2cap_get_sock_by_fixed_scid(int state,
+				__le16 cid, bdaddr_t *src, bdaddr_t *dst)
+{
+	struct sock *sk = NULL, *sk1 = NULL;
+	struct hlist_node *node;
+
+	read_lock(&l2cap_sk_list.lock);
+
+	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		if (state && sk->sk_state != state)
+			continue;
+
+		if (l2cap_pi(sk)->scid == cid && !bacmp(&bt_sk(sk)->dst, dst)) {
+			/* Exact match. */
+			if (!bacmp(&bt_sk(sk)->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+
+	read_unlock(&l2cap_sk_list.lock);
+
+	return node ? sk : sk1;
+}
+
 /* Find socket with cid and source bdaddr.
  * Returns closest match, locked.
  */
@@ -7051,7 +7082,7 @@
 {
 	struct sock *sk;
 
-	sk = l2cap_get_sock_by_scid(0, cid, conn->src);
+	sk = l2cap_get_sock_by_fixed_scid(0, cid, conn->src, conn->dst);
 	if (!sk)
 		goto drop;
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 848a515..a328db9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1411,6 +1411,10 @@
 		BT_DBG("Unable to find a pending command");
 		return;
 	}
+
+	if (status)
+		pairing_complete(cmd, status);
+
 	hci_conn_put(conn);
 }
 
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index aea2447..6838fd5 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -438,6 +438,8 @@
 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
 								&reason);
 		del_timer(&hcon->smp_timer);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+		mgmt_auth_failed(hcon->hdev->id, conn->dst, reason);
 		hci_conn_put(hcon);
 	} else if (hcon->cfm_pending) {
 		BT_DBG("send_pairing_confirm");
@@ -685,6 +687,8 @@
 
 	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
+	hci_conn_hold(hcon);
+
 	return 0;
 }
 
@@ -845,6 +849,8 @@
 		reason = 0;
 		err = -EPERM;
 		del_timer(&hcon->smp_timer);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+		mgmt_auth_failed(hcon->hdev->id, conn->dst, skb->data[1]);
 		hci_conn_put(hcon);
 		break;
 
@@ -893,6 +899,8 @@
 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
 								&reason);
 		del_timer(&hcon->smp_timer);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+		mgmt_auth_failed(hcon->hdev->id, conn->dst, reason);
 		hci_conn_put(hcon);
 	}
 
@@ -986,6 +994,8 @@
 			hcon->disconn_cfm_cb(hcon, 0);
 
 		del_timer(&hcon->smp_timer);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+		mgmt_auth_failed(hcon->hdev->id, conn->dst, SMP_UNSPECIFIED);
 		hci_conn_put(hcon);
 	}
 
@@ -998,6 +1008,8 @@
 
 	BT_DBG("smp: %d %d %d", status, encrypt, hcon->sec_req);
 
+	clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+
 	if (!status && encrypt && !hcon->sec_req)
 		smp_distribute_keys(conn, 0);
 
@@ -1005,6 +1017,9 @@
 	else if (hcon->sec_req  && (status || !encrypt))
 		smp_conn_security(conn, hcon->sec_level);
 
+	else
+		hci_conn_put(hcon);
+
 	return 0;
 }
 
@@ -1016,5 +1031,7 @@
 	BT_DBG("%p", conn);
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
+	mgmt_auth_failed(conn->hcon->hdev->id, conn->dst, SMP_UNSPECIFIED);
 	hci_conn_put(conn->hcon);
 }
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index 98a5139..a97a981 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -319,6 +319,18 @@
 	[TABLA_A_CDC_TX8_DMIC_CTL] = 1,
 	[TABLA_A_CDC_TX9_DMIC_CTL] = 1,
 	[TABLA_A_CDC_TX10_DMIC_CTL] = 1,
+	[TABLA_A_CDC_ANC2_CTL] = 1,
+	[TABLA_A_CDC_ANC2_SHIFT] = 1,
+	[TABLA_A_CDC_ANC2_FILT1_B1_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT1_B2_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT1_B3_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT1_B4_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT2_B1_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT2_B2_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT2_B3_CTL] = 1,
+	[TABLA_A_CDC_ANC2_SPARE] = 1,
+	[TABLA_A_CDC_ANC2_FILT3_CTL] = 1,
+	[TABLA_A_CDC_ANC2_FILT4_CTL] = 1,
 	[TABLA_A_CDC_SRC1_PDA_CFG] = 1,
 	[TABLA_A_CDC_SRC2_PDA_CFG] = 1,
 	[TABLA_A_CDC_SRC1_FS_CTL] = 1,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index fd00253..548b834 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1095,7 +1095,7 @@
 		pr_err("%s: Failed to configure gpio %d\n", __func__,
 			PM8921_GPIO_PM_TO_SYS(35));
 	else
-		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
+		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
 
 	return 0;
 }
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index b287c70..ecfef5b 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -137,9 +137,10 @@
 			session_id = common.voice[VOC_PATH_PASSIVE].session_id;
 		else
 			session_id = common.voice[VOC_PATH_FULL].session_id;
-	}
 
-	pr_debug("%s: %s has session id 0x%x\n", __func__, name, session_id);
+		pr_debug("%s: %s has session id 0x%x\n", __func__, name,
+				session_id);
+	}
 
 	return session_id;
 }