Merge "diag: Add Subsystem restart support" into msm-3.0
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 414f8da..2cd81c8 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -120,7 +120,8 @@
 asflags-y := -Wa,-march=all
 
 # Supply kernel BSS size to the decompressor via a linker symbol.
-KBSS_SZ = $(shell size $(obj)/../../../../vmlinux | awk 'END{print $$3}')
+SIZEBIN := $(if $(shell which $(CROSS_COMPILE)size),$(CROSS_COMPILE)size,size)
+KBSS_SZ = $(shell $(SIZEBIN) $(obj)/../../../../vmlinux | awk 'END{print $$3}')
 LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
 # Supply ZRELADDR to the decompressor via a linker symbol.
 ifneq ($(CONFIG_AUTO_ZRELADDR),y)
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index d5a0b3f..50145f9 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -132,6 +132,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_MSM_ADC=y
+CONFIG_PMIC8058=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_PM8058_XO=y
 # CONFIG_USB_SUPPORT is not set
@@ -149,6 +150,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index dddbdfe..4019a4f 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -130,6 +130,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_MSM_ADC=y
+CONFIG_PMIC8058=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_PM8058_XO=y
 # CONFIG_USB_SUPPORT is not set
@@ -147,6 +148,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
index b05d52a..1cc4b97 100644
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ b/arch/arm/configs/msm7627-perf_defconfig
@@ -194,6 +194,7 @@
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM_HS=y
+CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -247,6 +248,9 @@
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
index 15aec4b..6f0cb31 100644
--- a/arch/arm/configs/msm7627_defconfig
+++ b/arch/arm/configs/msm7627_defconfig
@@ -194,6 +194,7 @@
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM_HS=y
+CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_DCC_TTY=y
 CONFIG_I2C=y
@@ -245,6 +246,9 @@
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 9f31996..cc86af8 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
@@ -243,6 +244,7 @@
 CONFIG_SENSORS_MSM_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_MSM_POPMEM=y
+CONFIG_PMIC8058=y
 CONFIG_MARIMBA_CORE=y
 CONFIG_MARIMBA_CODEC=y
 CONFIG_TIMPANI_CODEC=y
@@ -334,6 +336,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index b7a7b34..9645211 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
@@ -242,6 +243,7 @@
 CONFIG_SENSORS_MSM_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_MSM_POPMEM=y
+CONFIG_PMIC8058=y
 CONFIG_MARIMBA_CORE=y
 CONFIG_MARIMBA_CODEC=y
 CONFIG_TIMPANI_CODEC=y
@@ -318,6 +320,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 5577fd8..3315171 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
@@ -299,6 +300,7 @@
 CONFIG_THERMAL_PM8901=y
 CONFIG_THERMAL_PM8058=y
 CONFIG_THERMAL_TSENS=y
+CONFIG_PMIC8058=y
 CONFIG_MARIMBA_CORE=y
 CONFIG_TIMPANI_CODEC=y
 CONFIG_MEDIA_SUPPORT=y
@@ -390,6 +392,7 @@
 CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 2dc6b36..698855a 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
@@ -290,6 +291,7 @@
 CONFIG_THERMAL_PM8901=y
 CONFIG_THERMAL_PM8058=y
 CONFIG_THERMAL_TSENS=y
+CONFIG_PMIC8058=y
 CONFIG_MARIMBA_CORE=y
 CONFIG_TIMPANI_CODEC=y
 CONFIG_MEDIA_SUPPORT=y
@@ -379,6 +381,7 @@
 CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index ddbe87c..7564020 100755
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -192,6 +192,7 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=m
 CONFIG_RFKILL=y
+CONFIG_RFKILL_PM=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_MISC_DEVICES=y
@@ -219,6 +220,8 @@
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
 CONFIG_WCNSS_CORE=m
+CONFIG_CFG80211=y
+CONFIG_CFG80211_WEXT=n
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_MODE_SLIP6=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/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 2acc8e0..a595612 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -172,6 +172,7 @@
 	select MSM_GPIOMUX
 	select MSM_RPM
 	select MSM_SPM_V2
+	select MSM_NATIVE_RESTART
 endmenu
 
 choice
@@ -944,7 +945,7 @@
 	  via muxing than BAM could without muxing.
 
 config MSM_N_WAY_SMD
-	depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM8960 || ARCH_MSM7X27 || ARCH_MSM7X25 || ARCH_MSM9615))
+	depends on (MSM_SMD && !(ARCH_MSM7X01A))
 	default y
 	bool "MSM N-WAY SMD support"
 	help
@@ -952,7 +953,7 @@
 	  normal APPS-MODEM SMD communication.
 
 config MSM_N_WAY_SMSM
-	depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM8960 || ARCH_MSM7X27 || ARCH_MSM7X25 || ARCH_MSM9615))
+	depends on (MSM_SMD && !(ARCH_MSM7X01A))
 	default y
 	bool "MSM N-WAY SMSM support"
 	help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e81bdcd..0072100 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -75,6 +75,7 @@
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o
         obj-y += socinfo.o
 ifndef CONFIG_ARCH_MSM9615
+ifndef CONFIG_ARCH_APQ8064
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
 	obj-$(CONFIG_MSM_SMD) += pmic.o
@@ -82,6 +83,7 @@
 endif
 endif
 endif
+endif
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
 ifndef CONFIG_ARCH_APQ8064
@@ -158,7 +160,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
@@ -209,7 +211,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
@@ -219,6 +222,7 @@
 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 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 1d0e1a8..d827dd1 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -66,7 +66,7 @@
 #define STBY_KHZ		1
 
 #define HFPLL_NOMINAL_VDD	1050000
-#define HFPLL_LOW_VDD		1050000
+#define HFPLL_LOW_VDD		945000
 #define HFPLL_LOW_VDD_PLL_L_MAX	0x28
 
 #define SECCLKAGD		BIT(4)
@@ -276,36 +276,21 @@
 	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
 	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
 	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
-	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 3 },
-	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 4 },
-	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 4 },
-	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 4 },
-	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 4 },
-	[17] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 5 },
-	[18] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 5 },
-	[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 5 },
-	[20] = { { 1404000, HFPLL, 1, 0, 0x34 }, 1150000, 1150000, 5 },
-	[21] = { { 1458000, HFPLL, 1, 0, 0x36 }, 1150000, 1150000, 5 },
-	[22] = { { 1512000, HFPLL, 1, 0, 0x38 }, 1150000, 1150000, 5 },
-	[23] = { { 1566000, HFPLL, 1, 0, 0x3A }, 1150000, 1150000, 5 },
-	[24] = { { 1620000, HFPLL, 1, 0, 0x3C }, 1150000, 1150000, 5 },
-	[25] = { { 1674000, HFPLL, 1, 0, 0x3E }, 1150000, 1150000, 5 },
 };
 
-/* TODO: Update core voltages when data is available. */
 static struct acpu_level acpu_freq_tbl_8960[] = {
-	{ 0, {STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),  1050000 },
-	{ 1, {  384000, PLL_8, 0, 2, 0x00 }, L2(1),  1050000 },
-	{ 1, {  432000, HFPLL, 2, 0, 0x20 }, L2(6),  1050000 },
-	{ 1, {  486000, HFPLL, 2, 0, 0x24 }, L2(6),  1050000 },
-	{ 1, {  540000, HFPLL, 2, 0, 0x28 }, L2(6),  1050000 },
-	{ 1, {  594000, HFPLL, 1, 0, 0x16 }, L2(6),  1050000 },
-	{ 1, {  648000, HFPLL, 1, 0, 0x18 }, L2(6),  1050000 },
-	{ 1, {  702000, HFPLL, 1, 0, 0x1A }, L2(6),  1050000 },
-	{ 1, {  756000, HFPLL, 1, 0, 0x1C }, L2(13), 1150000 },
-	{ 1, {  810000, HFPLL, 1, 0, 0x1E }, L2(13), 1150000 },
-	{ 1, {  864000, HFPLL, 1, 0, 0x20 }, L2(13), 1150000 },
-	{ 1, {  918000, HFPLL, 1, 0, 0x22 }, L2(13), 1150000 },
+	{ 0, {STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {  384000, PLL_8, 0, 2, 0x00 }, L2(1),   950000 },
+	{ 1, {  432000, HFPLL, 2, 0, 0x20 }, L2(6),   950000 },
+	{ 1, {  486000, HFPLL, 2, 0, 0x24 }, L2(6),   962500 },
+	{ 1, {  540000, HFPLL, 2, 0, 0x28 }, L2(6),   962500 },
+	{ 1, {  594000, HFPLL, 1, 0, 0x16 }, L2(6),   987500 },
+	{ 1, {  648000, HFPLL, 1, 0, 0x18 }, L2(6),  1000000 },
+	{ 1, {  702000, HFPLL, 1, 0, 0x1A }, L2(6),  1025000 },
+	{ 1, {  756000, HFPLL, 1, 0, 0x1C }, L2(11), 1050000 },
+	{ 1, {  810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+	{ 1, {  864000, HFPLL, 1, 0, 0x20 }, L2(11), 1125000 },
+	{ 1, {  918000, HFPLL, 1, 0, 0x22 }, L2(11), 1137500 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index e12caeb..924a46a 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -122,7 +122,7 @@
 		goto out;
 	}
 
-	pr_info("Switching from CPU rate %u KHz -> %u KHz\n",
+	pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
 		strt_s->khz, tgt_s->khz);
 
 	/* Switch CPU speed. */
@@ -131,7 +131,7 @@
 	clk_disable(clocks[strt_s->src].clk);
 
 	drv_state.current_speed = tgt_s;
-	pr_info("CPU speed change complete\n");
+	pr_debug("CPU speed change complete\n");
 
 out:
 	if (reason == SETRATE_CPUFREQ)
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index aa6ce58..87ff559 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -39,6 +39,16 @@
 	&msm9615_device_tsens,
 	&msm_device_nand,
 	&msm_rpm_device,
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+		&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
 };
 
 static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
@@ -87,6 +97,12 @@
 	},
 };
 
+static struct gpiomux_setting ps_hold = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting gsbi4 = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -111,6 +127,15 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
+	{
+		.gpio = 83,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ps_hold,
+		},
+	},
+};
+
 struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
 	{
 		.gpio      = 8,		/* GSBI3 QUP SPI_CLK */
@@ -181,6 +206,117 @@
 	},
 };
 
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x18500000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	1
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
 #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
 	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
 
@@ -460,6 +596,8 @@
 	msm_gpiomux_install(msm9615_gsbi_configs,
 			ARRAY_SIZE(msm9615_gsbi_configs));
 
+	msm_gpiomux_install(msm9615_ps_hold_config,
+			ARRAY_SIZE(msm9615_ps_hold_config));
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/board-apq8064.c b/arch/arm/mach-msm/board-apq8064.c
index 907fa72..d37fb7b 100644
--- a/arch/arm/mach-msm/board-apq8064.c
+++ b/arch/arm/mach-msm/board-apq8064.c
@@ -271,8 +271,10 @@
 	apq8064_add_sdcc(3, apq8064_sdc3_pdata);
 }
 
+#define MSM_SHARED_RAM_PHYS 0x80000000
 static void __init apq8064_map_io(void)
 {
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_apq8064_io();
 	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
@@ -307,6 +309,7 @@
 	&apq8064_slim_ctrl,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
+	&msm_device_smd_apq8064,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 5244434..eb936e4 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/msm_ssbi.h>
 #include <linux/mfd/pmic8058.h>
 #include <linux/regulator/pmic8058-regulator.h>
 #include <linux/i2c.h>
@@ -247,6 +248,7 @@
 	.name = "pm8058-regulator", \
 	.id = _id, \
 	.platform_data = &pm8058_vreg_init[_id], \
+	.pdata_size    = sizeof(pm8058_vreg_init[_id]), \
 }
 
 #ifdef CONFIG_SENSORS_MSM_ADC
@@ -463,18 +465,21 @@
 
 static struct pm8058_platform_data pm8058_fsm9xxx_data = {
 	.irq_base = PMIC8058_IRQ_BASE,
+	.irq = MSM_GPIO_TO_INT(47),
 
 	.num_subdevs = ARRAY_SIZE(pm8058_subdevs),
 	.sub_devices = pm8058_subdevs,
 };
 
-static struct i2c_board_info pm8058_boardinfo[] __initdata = {
-	{
-		I2C_BOARD_INFO("pm8058-core", 0x55),
-		.irq = MSM_GPIO_TO_INT(47),
-		.platform_data = &pm8058_fsm9xxx_data,
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data fsm9xxx_ssbi_pm8058_pdata = {
+	.controller_type = FSM_SBI_CTRL_SSBI,
+	.slave  = {
+		.name                   = "pm8058-core",
+		.platform_data          = &pm8058_fsm9xxx_data,
 	},
 };
+#endif
 
 static int __init buses_init(void)
 {
@@ -483,9 +488,6 @@
 		pr_err("%s: gpio_tlmm_config (gpio=%d) failed\n",
 			__func__, PMIC_GPIO_INT);
 
-	i2c_register_board_info(0 /* I2C_SSBI ID */, pm8058_boardinfo,
-				ARRAY_SIZE(pm8058_boardinfo));
-
 	return 0;
 }
 
@@ -602,10 +604,6 @@
  */
 
 #ifdef CONFIG_I2C_SSBI
-static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi1_pdata = {
-	.controller_type = FSM_SBI_CTRL_SSBI,
-};
-
 static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi2_pdata = {
 	.controller_type = FSM_SBI_CTRL_SSBI,
 };
@@ -613,7 +611,9 @@
 static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi3_pdata = {
 	.controller_type = FSM_SBI_CTRL_SSBI,
 };
+#endif
 
+#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
 /* Intialize GPIO configuration for SSBI */
 static struct msm_gpio ssbi_gpio_config_data[] = {
 	{ GPIO_CFG(140, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA),
@@ -811,8 +811,10 @@
 	&msm_device_smd,
 	&msm_device_dmov,
 	&msm_device_nand,
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+#endif
 #ifdef CONFIG_I2C_SSBI
-	&msm_device_ssbi1,
 	&msm_device_ssbi2,
 	&msm_device_ssbi3,
 #endif
@@ -873,6 +875,14 @@
 
 	regulator_has_full_constraints();
 
+#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
+	fsm9xxx_init_ssbi_gpio();
+#endif
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+			&fsm9xxx_ssbi_pm8058_pdata;
+#endif
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 #ifdef CONFIG_MSM_SPM
@@ -887,8 +897,6 @@
 	fsm9xxx_init_uart1();
 #endif
 #ifdef CONFIG_I2C_SSBI
-	fsm9xxx_init_ssbi_gpio();
-	msm_device_ssbi1.dev.platform_data = &msm_i2c_ssbi1_pdata;
 	msm_device_ssbi2.dev.platform_data = &msm_i2c_ssbi2_pdata;
 	msm_device_ssbi3.dev.platform_data = &msm_i2c_ssbi3_pdata;
 #endif
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-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index ee9df6f..fa53e3d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -21,6 +21,7 @@
 #ifdef CONFIG_SPI_QSD
 #include <linux/spi/spi.h>
 #endif
+#include <linux/msm_ssbi.h>
 #include <linux/mfd/pmic8058.h>
 #include <linux/mfd/marimba.h>
 #include <linux/i2c.h>
@@ -816,19 +817,22 @@
 
 static struct pm8058_platform_data pm8058_7x30_data = {
 	.irq_base = PMIC8058_IRQ_BASE,
+	.irq = MSM_GPIO_TO_INT(PMIC_GPIO_INT),
 
 	.num_subdevs = ARRAY_SIZE(pm8058_subdevs),
 	.sub_devices = pm8058_subdevs,
 	.irq_trigger_flags = IRQF_TRIGGER_LOW,
 };
 
-static struct i2c_board_info pm8058_boardinfo[] __initdata = {
-	{
-		I2C_BOARD_INFO("pm8058-core", 0x55),
-		.irq = MSM_GPIO_TO_INT(PMIC_GPIO_INT),
-		.platform_data = &pm8058_7x30_data,
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data msm7x30_ssbi_pm8058_pdata = {
+	.controller_type = MSM_SBI_CTRL_SSBI2,
+	.slave	= {
+		.name			= "pm8058-core",
+		.platform_data		= &pm8058_7x30_data,
 	},
 };
+#endif
 
 static struct i2c_board_info cy8info[] __initdata = {
 	{
@@ -1607,9 +1611,6 @@
                         = sizeof(surf_keypad_data);
 	}
 
-	i2c_register_board_info(6 /* I2C_SSBI ID */, pm8058_boardinfo,
-				ARRAY_SIZE(pm8058_boardinfo));
-
 	return 0;
 }
 
@@ -5306,8 +5307,11 @@
 	&android_usb_device,
 #endif
 	&qsd_device_spi,
+
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+#endif
 #ifdef CONFIG_I2C_SSBI
-	&msm_device_ssbi6,
 	&msm_device_ssbi7,
 #endif
 	&android_pmem_device,
@@ -5513,11 +5517,6 @@
 }
 
 #ifdef CONFIG_I2C_SSBI
-static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi6_pdata = {
-	.rsl_id = "D:PMIC_SSBI",
-	.controller_type = MSM_SBI_CTRL_SSBI2,
-};
-
 static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi7_pdata = {
 	.rsl_id = "D:CODEC_SSBI",
 	.controller_type = MSM_SBI_CTRL_SSBI,
@@ -6977,6 +6976,11 @@
 		msm_adc_pdata.num_adc = ARRAY_SIZE(msm_adc_surf_device_names);
 	}
 
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+				&msm7x30_ssbi_pm8058_pdata;
+#endif
+
 	platform_add_devices(msm_footswitch_devices,
 			     msm_num_footswitch_devices);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -7034,7 +7038,6 @@
 
 	bt_power_init();
 #ifdef CONFIG_I2C_SSBI
-	msm_device_ssbi6.dev.platform_data = &msm_i2c_ssbi6_pdata;
 	msm_device_ssbi7.dev.platform_data = &msm_i2c_ssbi7_pdata;
 #endif
 	if (machine_is_msm7x30_fluid())
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index 3b6da9a..e3f0e31 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, \
 	}
 
@@ -444,9 +444,9 @@
 /* SAW regulator constraints */
 struct regulator_init_data msm_saw_regulator_pdata_s5 =
 	/*	      ID  vreg_name	       min_uV   max_uV */
-	SAW_VREG_INIT(S5, "8921_s5",	       1050000, 1150000);
+	SAW_VREG_INIT(S5, "8921_s5",	       950000, 1150000);
 struct regulator_init_data msm_saw_regulator_pdata_s6 =
-	SAW_VREG_INIT(S6, "8921_s6",	       1050000, 1150000);
+	SAW_VREG_INIT(S6, "8921_s6",	       950000, 1150000);
 
 /* PM8921 regulator constraints */
 struct pm8921_regulator_platform_data
@@ -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 2cf0a70..058bc47 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -748,8 +748,11 @@
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
 #define MSM_PMEM_ADSP_SIZE         0x3800000
 #define MSM_PMEM_AUDIO_SIZE        0x28B000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
 #define MSM_PMEM_SIZE 0x1800000 /* 24 Mbytes */
-
+#endif
 #define MSM_ION_EBI_SIZE	SZ_8M
 
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
@@ -1334,10 +1337,14 @@
 #define MSM_FB_WRITEBACK_OFFSET 0
 #endif
 
-
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+/* 4 bpp x 2 page HDMI case */
+#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
+#else
 /* Note: must be multiple of 4096 */
 #define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
 				MSM_FB_WRITEBACK_SIZE, 4096)
+#endif
 
 static int writeback_offset(void)
 {
@@ -1696,6 +1703,43 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
+	/* If HDMI is used as primary */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+};
+#else
 static struct msm_bus_vectors mdp_ui_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -1761,6 +1805,7 @@
 		mdp_1080p_vectors,
 	},
 };
+#endif
 
 static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
 	mdp_bus_scale_usecases,
@@ -1770,16 +1815,29 @@
 
 #endif
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+int mdp_core_clk_rate_table[] = {
+	200000000,
+	200000000,
+	200000000,
+	200000000,
+};
+#else
 int mdp_core_clk_rate_table[] = {
 	85330000,
 	85330000,
 	160000000,
 	200000000,
 };
+#endif
 
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	.mdp_core_clk_rate = 200000000,
+#else
 	.mdp_core_clk_rate = 85330000,
+#endif
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -1907,6 +1965,17 @@
 		.ib = 0,
 	},
 };
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+#else
 static struct msm_bus_vectors dtv_bus_def_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -1915,6 +1984,8 @@
 		.ib = 707616000 * 2,
 	},
 };
+#endif
+
 static struct msm_bus_paths dtv_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(dtv_bus_init_vectors),
@@ -3684,6 +3755,7 @@
 
 static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
 	.rtc_write_enable       = false,
+	.rtc_alarm_powerup	= false,
 };
 
 static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 79bad3f..dab800f 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -16,6 +16,7 @@
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/msm_ssbi.h>
 #include <linux/mfd/pmic8058.h>
 
 #include <linux/input/pmic8058-keypad.h>
@@ -2477,11 +2478,6 @@
 
 #ifdef CONFIG_I2C_SSBI
 /* PMIC SSBI */
-static struct msm_i2c_ssbi_platform_data msm_ssbi1_pdata = {
-	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
-};
-
-/* PMIC SSBI */
 static struct msm_i2c_ssbi_platform_data msm_ssbi2_pdata = {
 	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
 };
@@ -2593,13 +2589,21 @@
 #define MSM_FB_WRITEBACK_OFFSET 0
 #endif
 
-
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+/* 4 bpp x 2 page HDMI case */
+#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
+#else
 /* Note: must be multiple of 4096 */
 #define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
 				MSM_FB_WRITEBACK_SIZE + \
 				MSM_FB_DSUB_PMEM_ADDER, 4096)
+#endif
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SF_SIZE 0x8000000 /* 128 Mbytes */
+#else
 #define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+#endif
 
 static int writeback_offset(void)
 {
@@ -3841,35 +3845,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, \
 	}
 
 /*
@@ -3882,198 +3924,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 = {
@@ -4118,7 +4127,6 @@
 	&msm_gsbi12_qup_i2c_device,
 #endif
 #ifdef CONFIG_I2C_SSBI
-	&msm_device_ssbi1,
 	&msm_device_ssbi2,
 	&msm_device_ssbi3,
 #endif
@@ -4963,8 +4971,10 @@
 #ifdef CONFIG_SERIAL_MSM_HS
 	&msm_device_uart_dm1,
 #endif
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+#endif
 #ifdef CONFIG_I2C_SSBI
-	&msm_device_ssbi1,
 	&msm_device_ssbi2,
 	&msm_device_ssbi3,
 #endif
@@ -5061,57 +5071,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)
@@ -6361,20 +6321,23 @@
 
 static struct pm8058_platform_data pm8058_platform_data = {
 	.irq_base = PM8058_IRQ_BASE,
+	.irq = MSM_GPIO_TO_INT(PM8058_GPIO_INT),
 
 	.num_subdevs = ARRAY_SIZE(pm8058_subdevs),
 	.sub_devices = pm8058_subdevs,
 	.irq_trigger_flags = IRQF_TRIGGER_LOW,
 };
 
-static struct i2c_board_info pm8058_boardinfo[] __initdata = {
-	{
-		I2C_BOARD_INFO("pm8058-core", 0x55),
-		.irq = MSM_GPIO_TO_INT(PM8058_GPIO_INT),
-		.platform_data = &pm8058_platform_data,
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data msm8x60_ssbi_pm8058_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8058-core",
+		.platform_data		= &pm8058_platform_data,
 	},
 };
-#endif /* CONFIG_PMIC8058 */
+#endif
+#endif  /* CONFIG_PMIC8058 */
 
 #if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
 		defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
@@ -7158,14 +7121,6 @@
 };
 
 static struct i2c_registry msm8x60_i2c_devices[] __initdata = {
-#ifdef CONFIG_PMIC8058
-	{
-		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_DRAGON,
-		MSM_SSBI1_I2C_BUS_ID,
-		pm8058_boardinfo,
-		ARRAY_SIZE(pm8058_boardinfo),
-	},
-#endif
 #ifdef CONFIG_PMIC8901
 	{
 		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_DRAGON,
@@ -7436,11 +7391,15 @@
 	msm_gsbi1_qup_spi_device.dev.platform_data = &msm_gsbi1_qup_spi_pdata;
 #endif
 #ifdef CONFIG_I2C_SSBI
-	msm_device_ssbi1.dev.platform_data = &msm_ssbi1_pdata;
 	msm_device_ssbi2.dev.platform_data = &msm_ssbi2_pdata;
 	msm_device_ssbi3.dev.platform_data = &msm_ssbi3_pdata;
 #endif
 
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+				&msm8x60_ssbi_pm8058_pdata;
+#endif
+
 	if (machine_is_msm8x60_fluid()) {
 #if (defined(CONFIG_USB_EHCI_MSM_72K) && \
 	(defined(CONFIG_SMB137B_CHARGER) || \
@@ -9127,7 +9086,6 @@
 }
 
 #ifdef CONFIG_MSM_BUS_SCALING
-#ifdef CONFIG_FB_MSM_LCDC_DSUB
 static struct msm_bus_vectors mdp_init_vectors[] = {
 	/* For now, 0th array entry is reserved.
 	 * Please leave 0 as is and don't use it
@@ -9147,6 +9105,52 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
+	/* If HDMI is used as primary */
+	 {
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	 },
+	 /* Master and slaves can be from different fabrics */
+	 {
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	 },
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+};
+#else
+#ifdef CONFIG_FB_MSM_LCDC_DSUB
 static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
 	/* Default case static display/UI/2d/3d if FB SMI */
 	{
@@ -9230,25 +9234,6 @@
 };
 
 #else
-static struct msm_bus_vectors mdp_init_vectors[] = {
-	/* For now, 0th array entry is reserved.
-	 * Please leave 0 as is and don't use it
-	 */
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_SMI,
-		.ab = 0,
-		.ib = 0,
-	},
-	/* Master and slaves can be from different fabrics */
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
 static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
 	/* Default case static display/UI/2d/3d if FB SMI */
 	{
@@ -9359,6 +9344,7 @@
 		mdp_1080p_vectors,
 	},
 };
+#endif
 static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
 	mdp_bus_scale_usecases,
 	ARRAY_SIZE(mdp_bus_scale_usecases),
@@ -9385,6 +9371,26 @@
 		.ib = 0,
 	},
 };
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+#else
 static struct msm_bus_vectors dtv_bus_def_vectors[] = {
 	/* For now, 0th array entry is reserved.
 	 * Please leave 0 as is and don't use it
@@ -9403,6 +9409,7 @@
 		.ib = 707616000,
 	},
 };
+#endif
 static struct msm_bus_paths dtv_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(dtv_bus_init_vectors),
@@ -9543,6 +9550,13 @@
 	160000000,
 	200000000,
 };
+#elif defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY)
+int mdp_core_clk_rate_table[] = {
+	200000000,
+	200000000,
+	200000000,
+	200000000,
+};
 #else
 int mdp_core_clk_rate_table[] = {
 	59080000,
@@ -9554,7 +9568,11 @@
 
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	.mdp_core_clk_rate = 200000000,
+#else
 	.mdp_core_clk_rate = 59080000,
+#endif
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -10118,10 +10136,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 9aa5700..ea2d9d2 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5297,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),
@@ -5338,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"),
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 96e626d..9b9ac4a 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1576,6 +1576,15 @@
 	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
+
+	/* 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),
+
 };
 
 static void set_fsm_mode(void __iomem *mode_reg)
@@ -1666,9 +1675,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/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 637832d..649aeab 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -278,6 +278,11 @@
 
 static SYSDEV_CLASS_ATTR(mfreq, 0200, NULL, store_mfreq);
 
+static struct freq_attr *msm_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
 static struct cpufreq_driver msm_cpufreq_driver = {
 	/* lps calculations are handled here. */
 	.flags		= CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
@@ -285,6 +290,7 @@
 	.verify		= msm_cpufreq_verify,
 	.target		= msm_cpufreq_target,
 	.name		= "msm",
+	.attr		= msm_freq_attr,
 };
 
 static struct notifier_block msm_cpufreq_pm_notifier = {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 02b7569..99e8d23 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -549,6 +549,11 @@
 	.dev.platform_data = &msm_sps_pdata,
 };
 
+struct platform_device msm_device_smd_apq8064 = {
+	.name		= "msm_smd",
+	.id		= -1,
+};
+
 static struct clk_lookup msm_clocks_8064_dummy[] = {
 	CLK_DUMMY("pll2",		PLL2,		NULL, 0),
 	CLK_DUMMY("pll8",		PLL8,		NULL, 0),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index cc1264d..a92324c 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1284,7 +1284,7 @@
 	{
 		.clk_name = "rot_clk",
 		.clk_type = ROTATOR_CORE_CLK,
-		.clk_rate = 160 * 1000 * 1000,
+		.clk_rate = 200 * 1000 * 1000,
 	},
 	{
 		.clk_name = "rotator_pclk",
@@ -1780,7 +1780,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 1200000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(1200),
 	},
 };
 
@@ -1789,7 +1789,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 2048000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
 	},
 };
 
@@ -1798,7 +1798,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 2656000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(2656),
 	},
 };
 
@@ -1807,7 +1807,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 3968000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(3968),
 	},
 };
 
@@ -1854,7 +1854,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 204800000U,
+		.ib = KGSL_CONVERT_TO_MBPS(1200),
 	},
 };
 
@@ -1889,7 +1889,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 204800000U,
+		.ib = KGSL_CONVERT_TO_MBPS(1200),
 	},
 };
 
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index 86f2e18..426be10 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -74,27 +74,26 @@
  * SSBIs
  */
 
-#ifdef CONFIG_I2C_SSBI
-
-#define MSM_SSBI1_PHYS		0x94080000
-#define MSM_SSBI1_SIZE		SZ_4K
-
-static struct resource msm_ssbi1_resources[] = {
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI1_PHYS          0x94080000
+#define MSM_SSBI_PMIC1_PHYS     MSM_SSBI1_PHYS
+static struct resource msm_ssbi_pmic1_resources[] = {
 	{
-		.name   = "ssbi_base",
-		.start	= MSM_SSBI1_PHYS,
-		.end	= MSM_SSBI1_PHYS + MSM_SSBI1_SIZE - 1,
-		.flags	= IORESOURCE_MEM,
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_device_ssbi1 = {
-	.name		= "i2c_ssbi",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(msm_ssbi1_resources),
-	.resource	= msm_ssbi1_resources,
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = msm_ssbi_pmic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_ssbi_pmic1_resources),
 };
+#endif
 
+#ifdef CONFIG_I2C_SSBI
 #define MSM_SSBI2_PHYS		0x94090000
 #define MSM_SSBI2_SIZE		SZ_4K
 
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-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 0da9de3..d7832a3 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -309,24 +309,25 @@
 	.resource	= resources_qup,
 };
 
-#ifdef CONFIG_I2C_SSBI
-#define MSM_SSBI6_PHYS	0xAD900000
-static struct resource msm_ssbi6_resources[] = {
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI_PMIC1_PHYS	0xAD900000
+static struct resource msm_ssbi_pmic1_resources[] = {
 	{
-		.name   = "ssbi_base",
-		.start	= MSM_SSBI6_PHYS,
-		.end	= MSM_SSBI6_PHYS + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_device_ssbi6 = {
-	.name		= "i2c_ssbi",
-	.id		= 6,
-	.num_resources	= ARRAY_SIZE(msm_ssbi6_resources),
-	.resource	= msm_ssbi6_resources,
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = msm_ssbi_pmic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_ssbi_pmic1_resources),
 };
+#endif
 
+#ifdef CONFIG_I2C_SSBI
 #define MSM_SSBI7_PHYS  0xAC800000
 static struct resource msm_ssbi7_resources[] = {
 	{
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 8280aa0..2582024 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -489,7 +489,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 990000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
 	},
 };
 
@@ -498,7 +498,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 1300000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(1300),
 	},
 };
 
@@ -507,7 +507,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 2008000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(2008),
 	},
 };
 
@@ -516,7 +516,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_3D,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 2484000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(2484),
 	},
 };
 
@@ -563,7 +563,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 990000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
 	},
 };
 
@@ -598,7 +598,7 @@
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 0,
-		.ib = 990000000U,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
 	},
 };
 
@@ -878,25 +878,25 @@
 	.resource	= gsbi12_qup_i2c_resources,
 };
 
-#ifdef CONFIG_I2C_SSBI
-/* 8058 PMIC SSBI on /dev/i2c-6 */
-#define MSM_SSBI1_PMIC1C_PHYS	0x00500000
-static struct resource msm_ssbi1_resources[] = {
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI_PMIC1_PHYS	0x00500000
+static struct resource resources_ssbi_pmic1_resource[] = {
 	{
-		.name   = "ssbi_base",
-		.start	= MSM_SSBI1_PMIC1C_PHYS,
-		.end	= MSM_SSBI1_PMIC1C_PHYS + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_device_ssbi1 = {
-	.name		= "i2c_ssbi",
-	.id		= MSM_SSBI1_I2C_BUS_ID,
-	.num_resources	= ARRAY_SIZE(msm_ssbi1_resources),
-	.resource	= msm_ssbi1_resources,
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = resources_ssbi_pmic1_resource,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic1_resource),
 };
+#endif
 
+#ifdef CONFIG_I2C_SSBI
 /* 8901 PMIC SSBI on /dev/i2c-7 */
 #define MSM_SSBI2_PMIC2B_PHYS	0x00C00000
 static struct resource msm_ssbi2_resources[] = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d5cad07..4a82b33 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -112,6 +112,7 @@
 extern struct platform_device msm_device_sps_apq8064;
 extern struct platform_device msm_device_bam_dmux;
 extern struct platform_device msm_device_smd;
+extern struct platform_device msm_device_smd_apq8064;
 extern struct platform_device msm_device_dmov;
 extern struct platform_device msm8960_device_dmov;
 extern struct platform_device apq8064_device_dmov;
@@ -127,6 +128,7 @@
 
 extern struct platform_device msm_device_tsif[2];
 
+extern struct platform_device msm_device_ssbi_pmic1;
 extern struct platform_device msm_device_ssbi1;
 extern struct platform_device msm_device_ssbi2;
 extern struct platform_device msm_device_ssbi3;
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 0d1da49..1b6497d 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -543,7 +543,10 @@
 
 	CAMIO_CSI1_SRC_CLK,
 	CAMIO_CSI_PIX_CLK,
+	CAMIO_CSI_PIX1_CLK,
 	CAMIO_CSI_RDI_CLK,
+	CAMIO_CSI_RDI1_CLK,
+	CAMIO_CSI_RDI2_CLK,
 	CAMIO_CSIPHY0_TIMER_CLK,
 	CAMIO_CSIPHY1_TIMER_CLK,
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-8064.h b/arch/arm/mach-msm/include/mach/irqs-8064.h
index 97657ea..25dcd3f 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8064.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8064.h
@@ -299,13 +299,14 @@
 #define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
 
 /* smd/smsm interrupts */
-#define INT_A9_M2A_0                    MSS_TO_APPS_IRQ_0
-#define INT_A9_M2A_5                    MSS_TO_APPS_IRQ_1
-#define INT_ADSP_A11                    LPASS_SCSS_GP_HIGH_IRQ
-#define INT_ADSP_A11_SMSM               LPASS_SCSS_GP_MEDIUM_IRQ
-#define INT_DSPS_A11                    SPS_MTI_31
-#define INT_WCNSS_A11                   RIVA_APSS_SPARE_IRQ
-#define INT_WCNSS_A11_SMSM              RIVA_APPS_WLAN_SMSM_IRQ
+#define INT_A9_M2A_0		(GIC_SPI_START + 37) /*GSS_TO_APPS_IRQ_0*/
+#define INT_A9_M2A_5		(GIC_SPI_START + 38) /*GSS_TO_APPS_IRQ_1*/
+#define INT_ADSP_A11		LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM	LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11		SPS_MTI_31
+#define INT_DSPS_A11_SMSM	SPS_MTI_30
+#define INT_WCNSS_A11		RIVA_APSS_SPARE_IRQ
+#define INT_WCNSS_A11_SMSM	RIVA_APPS_WLAN_SMSM_IRQ
 
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-8960.h b/arch/arm/mach-msm/include/mach/irqs-8960.h
index 6d121f9..dae0f47 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8960.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8960.h
@@ -273,14 +273,14 @@
 #define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
 
 /* smd/smsm interrupts */
-#define INT_A9_M2A_0                    MSS_TO_APPS_IRQ_0
-#define INT_A9_M2A_5                    MSS_TO_APPS_IRQ_1
-#define INT_ADSP_A11                    LPASS_SCSS_GP_HIGH_IRQ
-#define INT_ADSP_A11_SMSM               LPASS_SCSS_GP_MEDIUM_IRQ
-#define INT_DSPS_A11                    SPS_MTI_31
-#define INT_DSPS_A11_SMSM               SPS_MTI_30
-#define INT_WCNSS_A11                   RIVA_APSS_SPARE_IRQ
-#define INT_WCNSS_A11_SMSM              RIVA_APPS_WLAN_SMSM_IRQ
+#define INT_A9_M2A_0		(GIC_SPI_START + 37) /*MSS_TO_APPS_IRQ_0*/
+#define INT_A9_M2A_5		(GIC_SPI_START + 38) /*MSS_TO_APPS_IRQ_1*/
+#define INT_ADSP_A11		LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM	LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11		SPS_MTI_31
+#define INT_DSPS_A11_SMSM	SPS_MTI_30
+#define INT_WCNSS_A11		RIVA_APSS_SPARE_IRQ
+#define INT_WCNSS_A11_SMSM	RIVA_APPS_WLAN_SMSM_IRQ
 
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
index bbc25fd..e842f8e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
@@ -83,4 +83,7 @@
 #define MSM9615_QFPROM_PHYS		0x00700000
 #define MSM9615_QFPROM_SIZE		SZ_4K
 
+#define MSM9615_IMEM_PHYS		0x2B000000
+#define MSM9615_IMEM_SIZE		SZ_4K
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/restart.h b/arch/arm/mach-msm/include/mach/restart.h
index 3deeeaf..84df9bc 100644
--- a/arch/arm/mach-msm/include/mach/restart.h
+++ b/arch/arm/mach-msm/include/mach/restart.h
@@ -17,7 +17,7 @@
 #define RESTART_NORMAL 0x0
 #define RESTART_DLOAD  0x1
 
-#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960)
+#ifdef CONFIG_MSM_NATIVE_RESTART
 void msm_set_restart_mode(int mode);
 #else
 #define msm_set_restart_mode(mode)
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/io.c b/arch/arm/mach-msm/io.c
index 9137e08..3bb10fb 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -327,6 +327,7 @@
 	MSM_CHIP_DEVICE(RPM, MSM9615),
 	MSM_CHIP_DEVICE(RPM_MPM, MSM9615),
 	MSM_CHIP_DEVICE(APCS_GLB, MSM9615),
+	MSM_CHIP_DEVICE(IMEM, MSM9615),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
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/restart.c b/arch/arm/mach-msm/restart.c
index 7ddcde7..00be696 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -33,11 +33,12 @@
 #include <mach/irqs.h>
 #include <mach/scm.h>
 #include "msm_watchdog.h"
+#include "timer.h"
 
-#define WDT0_RST       (MSM_TMR0_BASE + 0x38)
-#define WDT0_EN        (MSM_TMR0_BASE + 0x40)
-#define WDT0_BARK_TIME (MSM_TMR0_BASE + 0x4C)
-#define WDT0_BITE_TIME (MSM_TMR0_BASE + 0x5C)
+#define WDT0_RST	0x38
+#define WDT0_EN		0x40
+#define WDT0_BARK_TIME	0x4C
+#define WDT0_BITE_TIME	0x5C
 
 #define PSHOLD_CTL_SU (MSM_TLMM_BASE + 0x820)
 
@@ -50,6 +51,7 @@
 void *restart_reason;
 
 int pmic_reset_irq;
+static void __iomem *msm_tmr0_base;
 
 #ifdef CONFIG_MSM_DLOAD_MODE
 static int in_panic;
@@ -218,7 +220,7 @@
 		}
 	}
 
-	__raw_writel(0, WDT0_EN);
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
 	if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) {
 		mb();
 		__raw_writel(0, PSHOLD_CTL_SU); /* Actually reset the chip */
@@ -226,10 +228,10 @@
 		pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
 	}
 
-	__raw_writel(1, WDT0_RST);
-	__raw_writel(5*0x31F3, WDT0_BARK_TIME);
-	__raw_writel(0x31F3, WDT0_BITE_TIME);
-	__raw_writel(1, WDT0_EN);
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
+	__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
+	__raw_writel(1, msm_tmr0_base + WDT0_EN);
 
 	mdelay(10000);
 	printk(KERN_ERR "Restarting has failed\n");
@@ -246,6 +248,7 @@
 	/* Reset detection is switched on below.*/
 	set_dload_mode(1);
 #endif
+	msm_tmr0_base = msm_timer_get_timer0_base();
 	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
 	pm_power_off = msm_power_off;
 
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.c b/arch/arm/mach-msm/sdio_al.c
index 3acd4a4..8267fad 100644
--- a/arch/arm/mach-msm/sdio_al.c
+++ b/arch/arm/mach-msm/sdio_al.c
@@ -351,6 +351,7 @@
 	struct sdio_al_device *bootloader_dev;
 	void *subsys_notif_handle;
 	int sdioc_major;
+	int skip_print_info;
 };
 
 struct sdio_al_work {
@@ -993,7 +994,7 @@
 	}
 	/* Prevent modem to go to sleep until we get the PROG_DONE on
 	   the dummy CMD52 */
-	msmsdcc_set_pwrsave(sdio_al_dev->card->host, 0);
+	msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
 	/* Mark HOST_OK_TOSLEEP */
 	sdio_al_dev->is_ok_to_sleep = 1;
 	write_lpm_info(sdio_al_dev);
@@ -2359,10 +2360,9 @@
 			   u32 not_from_int, struct sdio_channel *ch)
 {
 	int ret = 0;
-	struct sdio_func *wk_func =
-		sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
+	struct sdio_func *wk_func = NULL;
 	unsigned long time_to_wait;
-	struct mmc_host *host = wk_func->card->host;
+	struct mmc_host *host = sdio_al_dev->host;
 
 	if (sdio_al_dev->is_err) {
 		SDIO_AL_ERR(__func__);
@@ -2398,7 +2398,7 @@
 	sdio_al_vote_for_sleep(sdio_al_dev, 0);
 
 	msmsdcc_lpm_disable(host);
-	msmsdcc_set_pwrsave(sdio_al_dev->card->host, 0);
+	msmsdcc_set_pwrsave(host, 0);
 	/* Poll the GPIO */
 	time_to_wait = jiffies + msecs_to_jiffies(1000);
 	while (time_before(jiffies, time_to_wait)) {
@@ -2416,6 +2416,13 @@
 				"get_mdm2ap_status() is 0\n");
 
 	/* Enable Wake up Function */
+	if (!sdio_al_dev->card ||
+	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or wk_func\n");
+		return -ENODEV;
+	}
+	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
 	ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
 	if (ret) {
 		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
@@ -2442,13 +2449,13 @@
 	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
 			" for card %d", sdio_al_dev->host->index);
 
-	msmsdcc_set_pwrsave(sdio_al_dev->card->host, 1);
+	msmsdcc_set_pwrsave(host, 1);
 	pr_debug(MODULE_NAME ":Turn clock off\n");
 
 	return ret;
 error_exit:
 	sdio_al_vote_for_sleep(sdio_al_dev, 1);
-	msmsdcc_set_pwrsave(sdio_al_dev->card->host, 1);
+	msmsdcc_set_pwrsave(host, 1);
 	WARN_ON(ret);
 	sdio_al_get_into_err_state(sdio_al_dev);
 	return ret;
@@ -2476,8 +2483,7 @@
 	pr_debug(MODULE_NAME ":start %s.\n", __func__);
 
 	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
-				" for card %d\n", func->card->host->index);
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
 		return;
 	}
 
@@ -2527,18 +2533,13 @@
 	int i = 0;
 	int fn = 0;
 
-	if (card == NULL) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"sdio_al_setup: No Card detected\n");
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
 		return -ENODEV;
-	}
-
+	func1 = card->sdio_func[0];
 
 	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
 			"card %d\n", sdio_al_dev->host->index);
 
-	func1 = card->sdio_func[0];
-
 	ret = sdio_al->pdata->config_mdm2ap_status(1);
 	if (ret) {
 		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
@@ -2560,13 +2561,13 @@
 
 	sdio_set_drvdata(func1, sdio_al_dev);
 	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
-			"%d\n",	card->host->index);
+			"%d\n",	sdio_al_dev->host->index);
 
 	ret = sdio_claim_irq(func1, sdio_func_irq);
 	if (ret) {
 		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
 				" IRQ for card %d\n",
-				card->host->index);
+				sdio_al_dev->host->index);
 		return ret;
 	}
 
@@ -3797,6 +3798,7 @@
 	}
 
 	dev_info(&card->dev, "SDIO Card claimed.\n");
+	sdio_al->skip_print_info = 0;
 
 	sdio_al_dev->state = CARD_INSERTED;
 
@@ -4018,13 +4020,12 @@
 	struct sdio_func *lpm_func = NULL;
 	int offset = 0;
 	int is_ok_to_sleep = 0;
-	static atomic_t first_time;
 	char buf[50];
 
-	if (atomic_read(&first_time) == 1)
+	if (sdio_al->skip_print_info == 1)
 		return;
 
-	atomic_set(&first_time, 1);
+	sdio_al->skip_print_info = 1;
 
 	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
 			__func__);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 7dec32a..94dd8b8 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -43,15 +43,17 @@
 
 #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
-	|| defined(CONFIG_ARCH_MSM9615)
+	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
 #define CONFIG_QDSP6 1
 #endif
 
-#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960)
+#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
 #define CONFIG_DSPS 1
 #endif
 
-#if defined(CONFIG_ARCH_MSM8960)
+#if defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
 #define CONFIG_WCNSS 1
 #define CONFIG_DSPS_SMSM 1
 #endif
@@ -200,6 +202,23 @@
 #define MSM_TRIG_A2DSPS_SMSM_INT
 #define MSM_TRIG_A2WCNSS_SMD_INT
 #define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_APQ8064)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMD_INT    \
+			(smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMSM_INT   \
+			(smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2DSPS_SMD_INT  \
+			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
+#define MSM_TRIG_A2DSPS_SMSM_INT \
+			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4094))
+#define MSM_TRIG_A2WCNSS_SMD_INT  \
+			(smd_write_intr(1 << 25, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2WCNSS_SMSM_INT  \
+			(smd_write_intr(1 << 23, MSM_APCS_GCC_BASE + 0x8))
 #elif defined(CONFIG_ARCH_FSM9XXX)
 #define MSM_TRIG_A2Q6_SMD_INT	\
 			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 2719891..31634ff 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;
 
@@ -160,6 +162,11 @@
 		rc = hci_recv_frame(skb);
 		if (rc < 0) {
 			BT_ERR("Error in passing the packet to HCI Layer");
+			/*
+			 * skb is getting freed in hci_recv_frame, making it
+			 * to null to avoid multiple access
+			 */
+			skb = NULL;
 			goto out_data;
 		}
 
@@ -228,6 +235,11 @@
 		rc = hci_recv_frame(skb);
 		if (rc < 0) {
 			BT_ERR("Error in passing the packet to HCI Layer");
+			/*
+			 * skb is getting freed in hci_recv_frame, making it
+			 *  to null to avoid multiple access
+			 */
+			skb = NULL;
 			goto out_event;
 		}
 
@@ -306,7 +318,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 +341,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 +376,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 +431,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/msm_rotator.c b/drivers/char/msm_rotator.c
index 01a0504..555e4fa 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -61,6 +61,10 @@
 #define MSM_ROTATOR_MAX_H	0x1fff
 #define MSM_ROTATOR_MAX_W	0x1fff
 
+#define IS_NONPLANAR		0x0
+#define IS_PLANAR		0x1
+#define IS_PLANAR_16ALIGNED	0x2
+
 /* from lsb to msb */
 #define GET_PACK_PATTERN(a, x, y, z, bit) \
 			(((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
@@ -260,6 +264,7 @@
 	case MDP_Y_CRCB_H2V2:
 	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CR_CB_H2V2:
+	case MDP_Y_CR_CB_GH2V2:
 	case MDP_Y_CRCB_H2V2_TILE:
 	case MDP_Y_CBCR_H2V2_TILE:
 		return 1;
@@ -375,7 +380,7 @@
 				  int new_session,
 				  unsigned int in_chroma_paddr,
 				  unsigned int out_chroma_paddr,
-				  int is_planar)
+				  int planar_mode)
 {
 	int bpp;
 	unsigned int in_chr_addr, out_chr_addr;
@@ -385,7 +390,13 @@
 		return -ENOTTY;
 
 	if (!in_chroma_paddr) {
-		in_chr_addr = chroma_addr(in_paddr, info->src.width,
+		if (planar_mode & IS_PLANAR_16ALIGNED)
+			in_chr_addr = chroma_addr(in_paddr,
+				ALIGN(info->src.width, 16),
+				info->src.height,
+				bpp);
+		else
+			in_chr_addr = chroma_addr(in_paddr, info->src.width,
 				info->src.height,
 				bpp);
 	} else
@@ -408,19 +419,33 @@
 			((info->dst_y * info->dst.width)/2 + info->dst_x),
 		  MSM_ROTATOR_OUTP1_ADDR);
 
-	if (is_planar) {
-		iowrite32(in_chr_addr +
+	if (planar_mode & IS_PLANAR) {
+		if (planar_mode & IS_PLANAR_16ALIGNED)
+			iowrite32(in_chr_addr +
+				ALIGN((info->src.width / 2), 16) *
+				(info->src.height / 2),
+				MSM_ROTATOR_SRCP2_ADDR);
+		else
+			iowrite32(in_chr_addr +
 				(info->src.width / 2) * (info->src.height / 2),
 				MSM_ROTATOR_SRCP2_ADDR);
 	}
 
 	if (new_session) {
-		if (is_planar) {
-			iowrite32(info->src.width |
+		if (planar_mode & IS_PLANAR) {
+			if (planar_mode & IS_PLANAR_16ALIGNED) {
+				iowrite32(ALIGN(info->src.width, 16) |
+					ALIGN((info->src.width / 2), 16) << 16,
+					MSM_ROTATOR_SRC_YSTRIDE1);
+				iowrite32(ALIGN((info->src.width / 2), 16),
+					MSM_ROTATOR_SRC_YSTRIDE2);
+			} else {
+				iowrite32(info->src.width |
 					(info->src.width / 2) << 16,
 					MSM_ROTATOR_SRC_YSTRIDE1);
-			iowrite32((info->src.width / 2),
+				iowrite32((info->src.width / 2),
 					MSM_ROTATOR_SRC_YSTRIDE2);
+			}
 		} else {
 			iowrite32(info->src.width |
 					info->src.width << 16,
@@ -448,7 +473,8 @@
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		iowrite32(0 << 29 | 		/* frame format 0 = linear */
 			  (use_imem ? 0 : 1) << 22 | /* tile size */
-			  (is_planar ? 1 : 2) << 19 | /* fetch planes */
+			  ((planar_mode & IS_PLANAR) ?
+				1 : 2) << 19 |  /* fetch planes */
 			  0 << 18 | 		/* unpack align */
 			  1 << 17 | 		/* unpack tight */
 			  1 << 13 | 		/* unpack count 0=1 component */
@@ -911,7 +937,7 @@
 								!= s,
 					    in_chroma_paddr,
 					    out_chroma_paddr,
-						0);
+					    IS_NONPLANAR);
 		break;
 	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CR_CB_H2V2:
@@ -921,7 +947,16 @@
 								!= s,
 					    in_chroma_paddr,
 					    out_chroma_paddr,
-						1);
+					    IS_PLANAR);
+		break;
+	case MDP_Y_CR_CB_GH2V2:
+		rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
+					    in_paddr, out_paddr, use_imem,
+					    msm_rotator_dev->last_session_idx
+								!= s,
+					    in_chroma_paddr,
+					    out_chroma_paddr,
+					    IS_PLANAR | IS_PLANAR_16ALIGNED);
 		break;
 	case MDP_Y_CRCB_H2V2_TILE:
 	case MDP_Y_CBCR_H2V2_TILE:
@@ -1033,6 +1068,7 @@
 	case MDP_Y_CRCB_H2V2:
 	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CR_CB_H2V2:
+	case MDP_Y_CR_CB_GH2V2:
 	case MDP_Y_CBCR_H2V1:
 	case MDP_Y_CRCB_H2V1:
 	case MDP_YCRYCB_H2V1:
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 8850516..8088e44 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -309,20 +309,21 @@
 
 config CRYPTO_DEV_QCE
 	tristate "Qualcomm Crypto Engine (QCE) module"
-	select  CRYPTO_DEV_QCE40 if ARCH_MSM8960
+	select  CRYPTO_DEV_QCE40 if ARCH_MSM8960 || ARCH_MSM9615
 	default n
 	help
-          This driver supports Qualcomm Crypto Engine in MSM7x30 MSM8660
-	  MSM8x55 and MSM8960
+          This driver supports Qualcomm Crypto Engine in MSM7x30, MSM8660
+	  MSM8x55, MSM8960 and MSM9615
 	  To compile this driver as a module, choose M here: the
 	  For MSM7x30 MSM8660 and MSM8x55 the module is called qce
-	  For MSM8960 the module is called qce40
+	  For MSM8960 and MSM9615 the module is called qce40
 
 config CRYPTO_DEV_QCEDEV
 	tristate "QCEDEV Interface to CE module"
 	default n
 	help
-          This driver supports Qualcomm QCEDEV Crypto in MSM7x30 MSM8660, MSM8960.
+          This driver supports Qualcomm QCEDEV Crypto in MSM7x30, MSM8660,
+          MSM8960 and MSM9615.
           This exposes the interface to the QCE hardware accelerator via IOCTLs
 	  To compile this driver as a module, choose M here: the
 	  module will be called qcedev.
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 90a7889..4ef2e08 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -29,6 +29,7 @@
 #include <crypto/sha.h>
 #include <mach/dma.h>
 #include <mach/clk.h>
+#include <mach/socinfo.h>
 
 #include "qce.h"
 #include "qce40.h"
@@ -149,6 +150,12 @@
 			pce_dev->ce_dm.ce_block_size = 16;
 		}
 	}
+	/*
+	* This is a temporary change - until Data Mover changes its
+	* configuration from 16 byte crci to 64 byte crci.
+	*/
+	if (cpu_is_msm9615())
+		pce_dev->ce_dm.ce_block_size = 16;
 
 	dev_info(pce_dev->pdev,
 			"IO base 0x%x\n, ce_in channel %d     , "
@@ -161,6 +168,23 @@
 	return 0;
 };
 
+#ifdef CONFIG_ARCH_MSM9615
+static void config_ce_engine(struct qce_device *pce_dev)
+{
+	unsigned int val = 0;
+
+	val = (1 << CRYPTO_MASK_DOUT_INTR) | (1 << CRYPTO_MASK_DIN_INTR) |
+			(1 << CRYPTO_MASK_OP_DONE_INTR) |
+				(1 << CRYPTO_MASK_ERR_INTR);
+
+	writel_relaxed(val, pce_dev->iobase + CRYPTO_CONFIG_REG);
+}
+#else
+static void config_ce_engine(struct qce_device *pce_dev)
+{
+
+}
+#endif
 
 static void _check_probe_done_call_back(struct msm_dmov_cmd *cmd_ptr,
 		unsigned int result, struct msm_dmov_errdata *err)
@@ -185,6 +209,22 @@
 	clk_reset(pce_dev->ce_core_clk, CLK_RESET_ASSERT);
 	clk_reset(pce_dev->ce_core_clk, CLK_RESET_DEASSERT);
 
+	/*
+	* Ensure previous instruction (any writes to CLK registers)
+	* to toggle the CLK reset lines was completed before configuring
+	* ce engine. The ce engine configuration settings should not be lost
+	* becasue of clk reset.
+	*/
+	mb();
+
+	/* Configure the CE Engine */
+	config_ce_engine(pce_dev);
+
+	/*
+	* Ensure ce configuration is completed.
+	*/
+	mb();
+
 	pce_dev->ce_dm.chan_ce_in_cmd->complete_func =
 				_check_probe_done_call_back;
 	pce_dev->ce_dm.chan_ce_in_cmd->cmdptr =
@@ -2529,4 +2569,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.11");
+MODULE_VERSION("2.12");
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index dcc98a0..9d315d2 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1229,6 +1229,7 @@
 		return qcedev_hmac_final(areq, handle);
 }
 
+#ifdef CONFIG_ANDROID_PMEM
 static int qcedev_pmem_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
 						struct qcedev_handle *handle)
 {
@@ -1438,6 +1439,18 @@
 	return err;
 
 }
+#else
+static int qcedev_pmem_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
+						struct qcedev_handle *handle)
+{
+	return -EPERM;
+}
+static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq,
+						struct qcedev_handle *handle)
+{
+	return -EPERM;
+}
+#endif/*CONFIG_ANDROID_PMEM*/
 
 static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
 				int *di, struct qcedev_handle *handle,
@@ -1837,7 +1850,7 @@
 				podev))
 			return -EINVAL;
 
-		if (qcedev_areq.cipher_op_req.use_pmem == QCEDEV_USE_PMEM)
+		if ((qcedev_areq.cipher_op_req.use_pmem) && (QCEDEV_USE_PMEM))
 			err = qcedev_pmem_ablk_cipher(&qcedev_areq, handle);
 		else
 			err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
@@ -2156,7 +2169,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.23");
+MODULE_VERSION("1.24");
 
 module_init(qcedev_init);
 module_exit(qcedev_exit);
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 44536c8..86d4c8e 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -39,7 +39,8 @@
 {
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
-	unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);
+	unsigned long offset = gen_pool_alloc_aligned(carveout_heap->pool,
+							size, ilog2(align));
 
 	if (!offset)
 		return ION_CARVEOUT_ALLOCATE_FAIL;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 115f073..84f2b33 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -18,6 +18,11 @@
 #include "kgsl_pwrscale.h"
 #include "kgsl_device.h"
 
+#define KGSL_PWRFLAGS_POWER_ON 0
+#define KGSL_PWRFLAGS_CLK_ON   1
+#define KGSL_PWRFLAGS_AXI_ON   2
+#define KGSL_PWRFLAGS_IRQ_ON   3
+
 #define GPU_SWFI_LATENCY	3
 #define UPDATE_BUSY_VAL		1000000
 #define UPDATE_BUSY		50
@@ -577,7 +582,8 @@
 							idle_check_ws);
 
 	mutex_lock(&device->mutex);
-	if (device->requested_state != KGSL_STATE_SLEEP)
+	if (device->ftbl->isidle(device) &&
+		(device->requested_state != KGSL_STATE_SLEEP))
 		kgsl_pwrscale_idle(device);
 
 	if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 794a895..127a19b 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -16,11 +16,6 @@
 /*****************************************************************************
 ** power flags
 *****************************************************************************/
-#define KGSL_PWRFLAGS_POWER_ON 0
-#define KGSL_PWRFLAGS_CLK_ON   1
-#define KGSL_PWRFLAGS_AXI_ON   2
-#define KGSL_PWRFLAGS_IRQ_ON   3
-
 #define KGSL_PWRFLAGS_ON   1
 #define KGSL_PWRFLAGS_OFF  0
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index c4dcb22..923b4fe 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -82,6 +82,13 @@
 	msm_idle_stats_idle_start(&priv->idledev);
 }
 
+static void idlestats_sleep(struct kgsl_device *device,
+			struct kgsl_pwrscale *pwrscale)
+{
+	struct idlestats_priv *priv = pwrscale->priv;
+	priv->idledev.stats->event |= MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED;
+}
+
 static int idlestats_init(struct kgsl_device *device,
 		     struct kgsl_pwrscale *pwrscale)
 {
@@ -130,5 +137,6 @@
 	.init = idlestats_init,
 	.idle = idlestats_idle,
 	.busy = idlestats_busy,
+	.sleep = idlestats_sleep,
 	.close = idlestats_close
 };
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 61a3edb..6cd57b3 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -565,7 +565,7 @@
 	z180_cmdstream_start(device);
 
 	mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_IRQ_ON);
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
 	return 0;
 
 error_clk_off:
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index c454f72..d2bd4df 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -1373,12 +1373,11 @@
 	kfree(message);
 
 fail_worker:
-	enable_irq(mxt->irq);
 	/* Make sure we just didn't miss a interrupt. */
 	if (mxt->read_chg() == 0){
-		disable_irq(mxt->irq);
 		schedule_delayed_work(&mxt->dwork, 0);
-	}
+	} else
+		enable_irq(mxt->irq);
 }
 
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 8dbdc01..2a192db 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -733,7 +733,7 @@
 
 	__u8 sig_threshold = param;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
 	return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
 		&sig_threshold);
@@ -744,7 +744,7 @@
 {
 	__u16 opcode = 0;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
@@ -754,7 +754,7 @@
 {
 	__u16 opcode = 0;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
@@ -764,7 +764,7 @@
 {
 	__u16 opcode = 0;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_GET_RADIO_TEXT_REQ);
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
@@ -774,7 +774,7 @@
 {
 	__u16 opcode = 0;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_GET_AF_LIST_REQ);
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
@@ -987,7 +987,7 @@
 {
 	__u16 opcode = 0;
 
-	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+	opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
 		HCI_OCF_FM_STATION_DBG_PARAM);
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 10c5fbf..36bad1b 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -72,7 +72,7 @@
 struct tavarua_device {
 	struct video_device *videodev;
 	/* driver management */
-	int users;
+	atomic_t users;
 	/* top level driver data */
 	struct marimba *marimba;
 	struct device *dev;
@@ -1690,14 +1690,12 @@
 	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
 	int bahama_present = -ENODEV;
 
-	mutex_lock(&radio->lock);
-	if (radio->users) {
-		mutex_unlock(&radio->lock);
+	if (!atomic_dec_and_test(&radio->users)) {
+		pr_err("%s: Device already in use."
+			"Try again later", __func__);
+		atomic_inc(&radio->users);
 		return -EBUSY;
-	} else {
-		radio->users++;
 	}
-	mutex_unlock(&radio->lock);
 
 	/* initial gpio pin config & Power up */
 	retval = radio->pdata->fm_setup(radio->pdata);
@@ -1877,7 +1875,7 @@
 	radio->pdata->fm_shutdown(radio->pdata);
 open_err_setup:
 	radio->handle_irq = 1;
-	radio->users = 0;
+	atomic_inc(&radio->users);
 	return retval;
 }
 
@@ -1917,8 +1915,11 @@
 		{ 0x00, 0x80 }
 	};
 
-	if (!radio)
+	if (!radio) {
+		pr_err("%s: Radio device not available...", __func__);
 		return -ENODEV;
+	}
+
 	FMDBG("In %s", __func__);
 
 	/* disable radio ctrl */
@@ -2021,7 +2022,7 @@
 	if (radio->pdata->config_i2s_gpio != NULL)
 		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
 	radio->handle_irq = 1;
-	radio->users = 0;
+	atomic_inc(&radio->users);
 	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
 	return 0;
 }
@@ -3535,9 +3536,7 @@
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
 	if (radio) {
-		mutex_lock(&radio->lock);
-		users = radio->users;
-		mutex_unlock(&radio->lock);
+		users = atomic_read(&radio->users);
 		if (users) {
 			retval = tavarua_disable_interrupts(radio);
 			if (retval < 0) {
@@ -3568,9 +3567,7 @@
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
 	if (radio) {
-		mutex_lock(&radio->lock);
-		users = radio->users;
-		mutex_unlock(&radio->lock);
+		users = atomic_read(&radio->users);
 
 		if (users) {
 			retval = tavarua_setup_interrupts(radio,
@@ -3719,8 +3716,8 @@
 			goto err_bufs;
 		}
 	}
-	/* init xfr status */
-	radio->users = 0;
+	/* initializing the device count  */
+	atomic_set(&radio->users, 1);
 	radio->xfr_in_progress = 0;
 	radio->xfr_bytes_left = 0;
 	for (i = 0; i < TAVARUA_XFR_MAX; i++)
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index 0f9fc1d..2af21d6 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -53,7 +53,7 @@
 };
 
 static int32_t imx074_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
-	int16_t next_lens_position)
+	int16_t next_lens_position, void *params)
 {
 	msm_camera_i2c_write(&a_ctrl->i2c_client,
 			     0x00,
@@ -86,7 +86,7 @@
 	      __func__,
 	      dac_value);
 
-	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, dac_value);
+	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, dac_value, NULL);
 
 	return rc;
 }
@@ -122,8 +122,8 @@
 		0x4F,
 		MSM_CAMERA_I2C_BYTE_DATA);
 
-	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F);
-	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F);
+	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL);
+	rc = a_ctrl->func_tbl.actuator_i2c_write(a_ctrl, 0x7F, NULL);
 	a_ctrl->curr_step_pos = 0;
 	return rc;
 }
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index b76fb74..7f570e6 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -40,14 +40,16 @@
 			(next_lens_pos +
 				(sign_direction * damping_code_step))) {
 		rc = a_ctrl->func_tbl.
-			actuator_i2c_write(a_ctrl, next_lens_pos);
+			actuator_i2c_write(a_ctrl, next_lens_pos,
+				damping_params->hw_params);
 		curr_lens_pos = next_lens_pos;
 		usleep(wait_time);
 	}
 
 	if (curr_lens_pos != code_boundary) {
 		rc = a_ctrl->func_tbl.
-			actuator_i2c_write(a_ctrl, code_boundary);
+			actuator_i2c_write(a_ctrl, code_boundary,
+				damping_params->hw_params);
 		usleep(wait_time);
 	}
 	return rc;
@@ -107,6 +109,8 @@
 	}
 
 	curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+	CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
+		a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
 
 	while (a_ctrl->curr_step_pos != dest_step_pos) {
 		step_boundary =
@@ -183,12 +187,10 @@
 			a_ctrl->step_position_table[step_index] = cur_code;
 		}
 	}
-
-	LINFO("step position table\n");
 	for (step_index = 0;
 		step_index < a_ctrl->set_info.total_steps;
 		step_index++) {
-		LINFO("spt i %d, val %d\n",
+		CDBG("step_position_table[%d]= %d\n",
 			step_index,
 			a_ctrl->step_position_table[step_index]);
 	}
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index c228998..d612dad 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -52,7 +52,7 @@
 	int (*actuator_power_down) (struct msm_actuator_ctrl_t *);
 	int32_t (*actuator_config)(void __user *);
 	int32_t (*actuator_i2c_write)(struct msm_actuator_ctrl_t *,
-			int16_t);
+			int16_t, void *);
 	int32_t (*actuator_write_focus)(struct msm_actuator_ctrl_t *,
 			uint16_t,
 			struct damping_params_t *,
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 847a1ec..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) {
@@ -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_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index 43f893b..45871bc 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -60,6 +60,7 @@
 #define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR       0x01D0
 
 /* MIPI	CSID registers */
+#define CSID_HW_VERSION_ADDR                    0x0
 #define CSID_CORE_CTRL_ADDR                     0x4
 #define CSID_RST_CMD_ADDR                       0x8
 #define CSID_CID_LUT_VC_0_ADDR                  0xc
@@ -105,6 +106,9 @@
 #define CAM_VANA_LOAD_UA                  85600
 #define CAM_CSI_LOAD_UA                    20000
 
+#define CSID_VERSION_V2              0x2000011
+
+static uint32_t csid_hw_version;
 static struct clk *camio_cam_clk;
 static struct clk *camio_vfe_clk;
 static struct clk *camio_csi_src_clk;
@@ -113,7 +117,10 @@
 static struct clk *camio_csi0_clk;
 static struct clk *camio_csi0_pclk;
 static struct clk *camio_csi_pix_clk;
+static struct clk *camio_csi_pix1_clk;
 static struct clk *camio_csi_rdi_clk;
+static struct clk *camio_csi_rdi1_clk;
+static struct clk *camio_csi_rdi2_clk;
 static struct clk *camio_csiphy0_timer_clk;
 static struct clk *camio_csiphy1_timer_clk;
 static struct clk *camio_vfe_pclk;
@@ -497,6 +504,13 @@
 		msm_camio_clk_rate_set_2(clk, csid_core);
 		break;
 
+	case CAMIO_CSI_PIX1_CLK:
+		camio_csi_pix1_clk =
+		clk = clk_get(NULL, "csi_pix1_clk");
+		/* mux to select between csid0 and csid1 */
+		msm_camio_clk_rate_set_2(clk, csid_core);
+		break;
+
 	case CAMIO_CSI_RDI_CLK:
 		camio_csi_rdi_clk =
 		clk = clk_get(NULL, "csi_rdi_clk");
@@ -504,6 +518,20 @@
 		msm_camio_clk_rate_set_2(clk, csid_core);
 		break;
 
+	case CAMIO_CSI_RDI1_CLK:
+		camio_csi_rdi1_clk =
+		clk = clk_get(NULL, "csi_rdi1_clk");
+		/* mux to select between csid0 and csid1 */
+		msm_camio_clk_rate_set_2(clk, csid_core);
+		break;
+
+	case CAMIO_CSI_RDI2_CLK:
+		camio_csi_rdi2_clk =
+		clk = clk_get(NULL, "csi_rdi2_clk");
+		/* mux to select between csid0 and csid1 */
+		msm_camio_clk_rate_set_2(clk, csid_core);
+		break;
+
 	case CAMIO_CSIPHY0_TIMER_CLK:
 		camio_csiphy0_timer_clk =
 		clk = clk_get(NULL, "csi0phy_timer_clk");
@@ -596,10 +624,22 @@
 		clk = camio_csi0_phy_clk;
 		break;
 
+	case CAMIO_CSI_PIX1_CLK:
+		clk = camio_csi_pix1_clk;
+		break;
+
 	case CAMIO_CSI_PIX_CLK:
 		clk = camio_csi_pix_clk;
 		break;
 
+	case CAMIO_CSI_RDI1_CLK:
+		clk = camio_csi_rdi1_clk;
+		break;
+
+	case CAMIO_CSI_RDI2_CLK:
+		clk = camio_csi_rdi2_clk;
+		break;
+
 	case CAMIO_CSI_RDI_CLK:
 		clk = camio_csi_rdi_clk;
 		break;
@@ -744,6 +784,40 @@
 	return IRQ_HANDLED;
 }
 #endif
+
+static int msm_camio_enable_v2_clks(void)
+{
+	int rc = 0;
+	csid_hw_version = msm_io_r(csidbase +
+				CSID_HW_VERSION_ADDR);
+	CDBG("%s csid_hw_version %d\n",
+		__func__,
+		csid_hw_version);
+
+	if (csid_hw_version == CSID_VERSION_V2) {
+		rc = msm_camio_clk_enable(CAMIO_CSI_PIX1_CLK);
+		if (rc < 0)
+			goto csi_pix1_fail;
+
+		rc = msm_camio_clk_enable(CAMIO_CSI_RDI1_CLK);
+		if (rc < 0)
+			goto csi_rdi1_fail;
+
+		rc = msm_camio_clk_enable(CAMIO_CSI_RDI2_CLK);
+		if (rc < 0)
+			goto csi_rdi2_fail;
+	}
+
+	return rc;
+
+csi_rdi2_fail:
+	msm_camio_clk_disable(CAMIO_CSI_RDI1_CLK);
+csi_rdi1_fail:
+	msm_camio_clk_disable(CAMIO_CSI_PIX1_CLK);
+csi_pix1_fail:
+	return rc;
+}
+
 static int msm_camio_enable_all_clks(uint8_t csid_core)
 {
 	int rc = 0;
@@ -824,8 +898,18 @@
 	return rc;
 }
 
+static void msm_camio_disable_v2_clks(void)
+{
+	if (csid_hw_version == CSID_VERSION_V2) {
+		msm_camio_clk_disable(CAMIO_CSI_RDI2_CLK);
+		msm_camio_clk_disable(CAMIO_CSI_RDI1_CLK);
+		msm_camio_clk_disable(CAMIO_CSI_PIX1_CLK);
+	}
+}
+
 static void msm_camio_disable_all_clks(uint8_t csid_core)
 {
+	msm_camio_disable_v2_clks();
 	msm_camio_clk_disable(CAMIO_CSI_RDI_CLK);
 	msm_camio_clk_disable(CAMIO_CSI_PIX_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
@@ -1034,6 +1118,7 @@
 	if (rc < 0)
 		goto csiphy_irq_fail;
 #endif
+	msm_camio_enable_v2_clks();
 	CDBG("camio enable done\n");
 	return 0;
 #if DBG_CSIPHY
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_ispif.c b/drivers/media/video/msm/msm_ispif.c
index c5e38ef..8797d38 100644
--- a/drivers/media/video/msm/msm_ispif.c
+++ b/drivers/media/video/msm/msm_ispif.c
@@ -47,6 +47,7 @@
 #define ISPIF_IRQ_MASK_1_ADDR                   0X010C
 #define ISPIF_IRQ_CLEAR_1_ADDR                  0X0110
 #define ISPIF_IRQ_STATUS_1_ADDR                 0X0114
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR         0x0124
 
 /*ISPIF RESET BITS*/
 
@@ -73,9 +74,11 @@
 #define ISPIF_IRQ_STATUS_MASK        0xA493000
 #define ISPIF_IRQ_1_STATUS_MASK      0xA493000
 #define ISPIF_IRQ_STATUS_RDI_SOF_MASK	0x492000
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD     0x1
 
 #define MAX_CID 15
 
+
 static struct ispif_device *ispif;
 
 static uint32_t global_intf_cmd_mask = 0xFFFFFFFF;
@@ -207,6 +210,8 @@
 					ISPIF_IRQ_MASK_ADDR);
 	msm_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
 					ISPIF_IRQ_CLEAR_ADDR);
+	msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+		 ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 	return rc;
 }
 
@@ -410,6 +415,8 @@
 	}
 	msm_io_w(out->ispifIrqStatus0,
 			ispif->base + ISPIF_IRQ_CLEAR_ADDR);
+	msm_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+		 ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 }
 
 static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
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 c801e4a..ea70ce5 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -199,7 +199,7 @@
 			V32_DEMOSAICV3_DBCC_OFF},
 		{VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
 		{VFE_CMD_XBAR_CFG},
-		{VFE_CMD_EZTUNE_CFG},
+		{VFE_CMD_MODULE_CFG, V32_MODULE_CFG_LEN, V32_MODULE_CFG_OFF},
 		{VFE_CMD_ZSL},
 /*115*/	{VFE_CMD_LINEARIZATION_UPDATE, V32_LINEARIZATION_LEN1,
 			V32_LINEARIZATION_OFF1},
@@ -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 */
@@ -1807,7 +1807,7 @@
 		vfe32_sync_timer_start(cmdp);
 		break;
 
-	case VFE_CMD_EZTUNE_CFG: {
+	case VFE_CMD_MODULE_CFG: {
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1885,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__);
 
@@ -1902,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__);
 
@@ -1941,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__);
 
@@ -1958,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__);
 
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index d3ed0e6..d763c2e 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -332,8 +332,8 @@
 #define V32_DEMOSAICV3_ABF_OFF 0x000002A4
 #define V32_DEMOSAICV3_ABF_LEN 180
 
-#define V32_EZTUNE_CFG_OFF 0x00000010
-#define V32_EZTUNE_CFG_LEN 4
+#define V32_MODULE_CFG_OFF 0x00000010
+#define V32_MODULE_CFG_LEN 4
 
 #define V32_CLF_CFG_OFF 0x000006B0
 #define V32_CLF_CFG_LEN 72
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 969595d..3360ac8 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -319,6 +319,7 @@
 	.sensor_get_pict_fps = msm_sensor_get_pict_fps,
 	.sensor_set_fps = msm_sensor_set_fps,
 	.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
+	.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
 	.sensor_setting = msm_sensor_setting,
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 806f763..b9b37e3 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -477,13 +477,13 @@
 
 		case CFG_SET_PICT_EXP_GAIN:
 			if (s_ctrl->func_tbl->
-			sensor_write_exp_gain == NULL) {
+			sensor_write_snapshot_exp_gain == NULL) {
 				rc = -EFAULT;
 				break;
 			}
 			rc =
 				s_ctrl->func_tbl->
-				sensor_write_exp_gain(
+				sensor_write_snapshot_exp_gain(
 					s_ctrl,
 					cdata.cfg.exp_gain.gain,
 					cdata.cfg.exp_gain.line);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index fedd485..1121170 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -115,6 +115,8 @@
 			struct fps_cfg *);
 	int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
 			uint16_t, uint32_t);
+	int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *,
+			uint16_t, uint32_t);
 	int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
 			int update_type, int rt);
 	int32_t (*sensor_set_sensor_mode)
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index d50ea43..4c3370a 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -479,6 +479,7 @@
 	.sensor_get_pict_fps = msm_sensor_get_pict_fps,
 	.sensor_set_fps = msm_sensor_set_fps,
 	.sensor_write_exp_gain = ov2720_write_exp_gain,
+	.sensor_write_snapshot_exp_gain = ov2720_write_exp_gain,
 	.sensor_setting = msm_sensor_setting,
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d291baa..a4feb838 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -155,8 +155,7 @@
 
 config PMIC8058
 	tristate "PMIC8058 Power Management chip"
-	depends on I2C_SSBI && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_FSM9XXX)
-	default y if I2C_SSBI && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_FSM9XXX)
+	depends on MSM_SSBI
 	select MFD_CORE
 	select MSM_SHOW_RESUME_IRQ
 	help
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 7f433db..85c8a9d 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
+#include <linux/msm_ssbi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/pmic8058.h>
 #include <linux/platform_device.h>
@@ -28,6 +29,7 @@
 #include <linux/debugfs.h>
 #include <linux/irq.h>
 #include <linux/syscore_ops.h>
+#include <linux/gpio.h>
 
 /* PMIC8058 Revision */
 #define SSBI_REG_REV			0x002  /* PMIC4 revision */
@@ -143,8 +145,7 @@
 
 struct pm8058_chip {
 	struct pm8058_platform_data	pdata;
-
-	struct i2c_client		*dev;
+	struct device		*dev;
 
 	u8	irqs_allowed[MAX_PM_BLOCKS];
 	u8	blocks_allowed[MAX_PM_MASTERS];
@@ -185,33 +186,15 @@
 }
 
 static inline int
-ssbi_write(struct i2c_client *client, u16 addr, const u8 *buf, size_t len)
+ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
 {
-	int	rc;
-	struct	i2c_msg msg = {
-		.addr           = addr,
-		.flags          = 0x0,
-		.buf            = (u8 *)buf,
-		.len            = len,
-	};
-
-	rc = i2c_transfer(client->adapter, &msg, 1);
-	return (rc == 1) ? 0 : rc;
+	return msm_ssbi_read(dev->parent, addr, buf, len);
 }
 
 static inline int
-ssbi_read(struct i2c_client *client, u16 addr, u8 *buf, size_t len)
+ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
 {
-	int	rc;
-	struct	i2c_msg msg = {
-		.addr           = addr,
-		.flags          = I2C_M_RD,
-		.buf            = buf,
-		.len            = len,
-	};
-
-	rc = i2c_transfer(client->adapter, &msg, 1);
-	return (rc == 1) ? 0 : rc;
+	return msm_ssbi_write(dev->parent, addr, buf, len);
 }
 
 static int pm8058_masked_write(u16 addr, u8 val, u8 mask)
@@ -1318,7 +1301,7 @@
 	}
 
 	if (!chip->count_wakeable)
-		disable_irq(chip->dev->irq);
+		disable_irq(chip->pdata.irq);
 
 	return 0;
 }
@@ -1368,7 +1351,7 @@
 	}
 
 	if (!chip->count_wakeable)
-		enable_irq(chip->dev->irq);
+		enable_irq(chip->pdata.irq);
 }
 
 static struct syscore_ops pm8058_pm = {
@@ -1376,14 +1359,13 @@
 	.resume = pm8058_resume,
 };
 
-static int pm8058_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+static int __devinit pm8058_probe(struct platform_device *pdev)
 {
 	int	i, rc;
-	struct	pm8058_platform_data *pdata = client->dev.platform_data;
+	struct	pm8058_platform_data *pdata = pdev->dev.platform_data;
 	struct	pm8058_chip *chip;
 
-	if (pdata == NULL || !client->irq) {
+	if (pdata == NULL || !gpio_is_valid(pdata->irq)) {
 		pr_err("%s: No platform_data or IRQ.\n", __func__);
 		return -ENODEV;
 	}
@@ -1393,18 +1375,13 @@
 		return -ENODEV;
 	}
 
-	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
-		pr_err("%s: i2c_check_functionality failed.\n", __func__);
-		return -ENODEV;
-	}
-
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
 	if (chip == NULL) {
 		pr_err("%s: kzalloc() failed.\n", __func__);
 		return -ENOMEM;
 	}
 
-	chip->dev = client;
+	chip->dev = &pdev->dev;
 
 	/* Read PMIC chip revision */
 	rc = ssbi_read(chip->dev, SSBI_REG_REV, &chip->revision, 1);
@@ -1417,14 +1394,14 @@
 		      sizeof(chip->pdata));
 
 	mutex_init(&chip->pm_lock);
-	irq_set_handler_data(chip->dev->irq, (void *)chip);
-	irq_set_irq_wake(chip->dev->irq, 1);
+	irq_set_handler_data(pdata->irq, (void *)chip);
+	irq_set_irq_wake(pdata->irq, 1);
 
 	chip->pm_max_irq = 0;
 	chip->pm_max_blocks = 0;
 	chip->pm_max_masters = 0;
 
-	i2c_set_clientdata(client, chip);
+	platform_set_drvdata(pdev, chip);
 
 	pmic_chip = chip;
 
@@ -1437,12 +1414,12 @@
 		irq_set_nested_thread(i, 1);
 	}
 
-	rc = mfd_add_devices(&chip->dev->dev, 0, pdata->sub_devices,
+	rc = mfd_add_devices(chip->dev, 0, pdata->sub_devices,
 			     pdata->num_subdevs, NULL, 0);
 
 	/* Add charger sub device with the chip parameter as driver data */
 	if (pdata->charger_sub_device) {
-		rc = mfd_add_devices(&chip->dev->dev, 0,
+		rc = mfd_add_devices(chip->dev, 0,
 					pdata->charger_sub_device,
 					1, NULL, 0);
 	}
@@ -1457,12 +1434,12 @@
 		}
 	}
 
-	rc = request_threaded_irq(chip->dev->irq, NULL, pm8058_isr_thread,
+	rc = request_threaded_irq(pdata->irq, NULL, pm8058_isr_thread,
 			IRQF_ONESHOT | IRQF_DISABLED | pdata->irq_trigger_flags,
 			"pm8058-irq", chip);
 	if (rc < 0)
 		pr_err("%s: could not request irq %d: %d\n", __func__,
-				chip->dev->irq, rc);
+				pdata->irq, rc);
 
 	rc = pmic8058_dbg_probe(chip);
 	if (rc < 0)
@@ -1478,15 +1455,15 @@
 	return 0;
 }
 
-static int __devexit pm8058_remove(struct i2c_client *client)
+static int __devexit pm8058_remove(struct platform_device *pdev)
 {
 	struct	pm8058_chip *chip;
 
-	chip = i2c_get_clientdata(client);
+	chip = platform_get_drvdata(pdev);
 	if (chip) {
 		if (chip->pm_max_irq) {
-			irq_set_irq_wake(chip->dev->irq, 0);
-			free_irq(chip->dev->irq, chip);
+			irq_set_irq_wake(chip->pdata.irq, 0);
+			free_irq(chip->pdata.irq, chip);
 		}
 		mutex_destroy(&chip->pm_lock);
 		chip->dev = NULL;
@@ -1499,33 +1476,25 @@
 	return 0;
 }
 
-static const struct i2c_device_id pm8058_ids[] = {
-	{ "pm8058-core", 0 },
-	{ },
-};
-MODULE_DEVICE_TABLE(i2c, pm8058_ids);
-
-static struct i2c_driver pm8058_driver = {
-	.driver.name	= "pm8058-core",
-	.id_table	= pm8058_ids,
+static struct platform_driver pm8058_driver = {
 	.probe		= pm8058_probe,
 	.remove		= __devexit_p(pm8058_remove),
+	.driver		= {
+		.name	= "pm8058-core",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init pm8058_init(void)
 {
-	int rc = i2c_add_driver(&pm8058_driver);
-	pr_notice("%s: i2c_add_driver: rc = %d\n", __func__, rc);
-
-	return rc;
+	return platform_driver_register(&pm8058_driver);
 }
+arch_initcall(pm8058_init);
 
 static void __exit pm8058_exit(void)
 {
-	i2c_del_driver(&pm8058_driver);
+	platform_driver_unregister(&pm8058_driver);
 }
-
-arch_initcall(pm8058_init);
 module_exit(pm8058_exit);
 
 MODULE_LICENSE("GPL v2");
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/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/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index e6945d5..c16632e 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -85,8 +85,10 @@
 static int __devinit
 wcnss_wlan_ctrl_probe(struct platform_device *pdev)
 {
-	if (penv)
-		penv->smd_channel_ready = 1;
+	if (!penv)
+		return -ENODEV;
+
+	penv->smd_channel_ready = 1;
 
 	pr_info("%s: SMD ctrl channel up\n", __func__);
 
diff --git a/drivers/platform/msm/ssbi.c b/drivers/platform/msm/ssbi.c
index b4fd02e..8a6dbf7 100644
--- a/drivers/platform/msm/ssbi.c
+++ b/drivers/platform/msm/ssbi.c
@@ -62,6 +62,15 @@
 
 #define SSBI_TIMEOUT_US			100
 
+/* SSBI_FSM Read and Write commands for the FSM9xxx SSBI implementation */
+#define SSBI_FSM_CMD_REG_ADDR_SHFT  (0x08)
+
+#define SSBI_FSM_CMD_READ(AD) \
+	(SSBI_CMD_RDWRN | (((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT))
+
+#define SSBI_FSM_CMD_WRITE(AD, DT) \
+	((((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT) | ((DT) & 0xFF))
+
 struct msm_ssbi {
 	struct device		*dev;
 	struct device		*slave;
@@ -113,6 +122,11 @@
 		ssbi_writel(ssbi, mode2, SSBI2_MODE2);
 	}
 
+	if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
+		cmd = SSBI_FSM_CMD_READ(addr);
+	else
+		cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16);
+
 	while (len) {
 		ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
 		if (ret)
@@ -146,7 +160,13 @@
 		if (ret)
 			goto err;
 
-		ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD);
+		if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
+			ssbi_writel(ssbi, SSBI_FSM_CMD_WRITE(addr, *buf),
+				SSBI2_CMD);
+		else
+			ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf,
+				SSBI2_CMD);
+
 		ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY);
 		if (ret)
 			goto err;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index da7c6fd..d0c1392 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -647,6 +647,49 @@
 	return result;
 }
 
+static int get_battery_uvolts(struct pm8921_bms_chip *chip, int *uvolts)
+{
+	int rc;
+	struct pm8921_adc_chan_result result;
+
+	rc = pm8921_adc_read(chip->vbat_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->vbat_channel, rc);
+		return rc;
+	}
+	pr_debug("mvolts phy = %lld meas = 0x%llx", result.physical,
+						result.measurement);
+	*uvolts = (int)result.physical;
+	*uvolts = *uvolts * 1000;
+	return 0;
+}
+
+static int adc_based_ocv(struct pm8921_bms_chip *chip, int *ocv)
+{
+	int vbatt, rbatt, ibatt, rc;
+
+	rc = get_battery_uvolts(chip, &vbatt);
+	if (rc) {
+		pr_err("failed to read vbatt from adc rc = %d\n", rc);
+		last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
+		return rc;
+	}
+
+	rc =  pm8921_bms_get_battery_current(&ibatt);
+	if (rc) {
+		pr_err("failed to read batt current rc = %d\n", rc);
+		last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
+		return rc;
+	}
+
+	rbatt = calculate_rbatt(the_chip);
+	if (rbatt < 0)
+		rbatt = DEFAULT_RBATT_MOHMS;
+	*ocv = vbatt + ibatt * rbatt;
+	return 0;
+}
+
 static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
 							int chargecycles)
 {
@@ -680,24 +723,6 @@
 	*val = cc_mah;
 }
 
-static int get_battery_uvolts(struct pm8921_bms_chip *chip, int *uvolts)
-{
-	int rc;
-	struct pm8921_adc_chan_result result;
-
-	rc = pm8921_adc_read(chip->vbat_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					chip->vbat_channel, rc);
-		return rc;
-	}
-	pr_debug("mvolts phy = %lld meas = 0x%llx", result.physical,
-						result.measurement);
-	*uvolts = (int)result.physical;
-	*uvolts = *uvolts * 1000;
-	return 0;
-}
-
 static int calculate_unusable_charge_mah(struct pm8921_bms_chip *chip,
 				 int fcc, int batt_temp, int chargecycles)
 {
@@ -798,6 +823,9 @@
  *				- unusable charge (due to battery resistance)
  * SOC% = (remaining usable charge/ fcc - usable_charge);
  */
+#define BMS_BATT_NOMINAL	3700000
+#define MIN_OPERABLE_SOC	10
+#define BATTERY_POWER_SUPPLY_SOC	53
 static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
 						int batt_temp, int chargecycles)
 {
@@ -815,25 +843,43 @@
 	/* calculate remaining usable charge */
 	remaining_usable_charge = remaining_charge - cc_mah - unusable_charge;
 	pr_debug("RUC = %dmAh\n", remaining_usable_charge);
-	if (remaining_usable_charge < 0) {
+	soc = (remaining_usable_charge * 100) / (fcc - unusable_charge);
+	if (soc > 100)
+		soc = 100;
+	pr_debug("SOC = %u%%\n", soc);
+
+	if (soc < MIN_OPERABLE_SOC) {
+		int ocv = 0, rc;
+
+		rc = adc_based_ocv(chip, &ocv);
+		if (rc == 0 && ocv >= BMS_BATT_NOMINAL) {
+			/*
+			 * The ocv doesnt seem to have dropped for
+			 * soc to go negative.
+			 * The setup must be using a power supply
+			 * instead of real batteries.
+			 * Fake high enough soc to prevent userspace
+			 * shutdown for low battery
+			 */
+			soc = BATTERY_POWER_SUPPLY_SOC;
+			pr_debug("Adjusting SOC to %d\n",
+						BATTERY_POWER_SUPPLY_SOC);
+		}
+	}
+
+	if (soc < 0) {
 		pr_err("bad rem_usb_chg = %d rem_chg %d,"
 				"cc_mah %lld, unusb_chg %d\n",
 				remaining_usable_charge, remaining_charge,
 				cc_mah, unusable_charge);
 		pr_err("for bad rem_usb_chg last_ocv_uv = %d"
-				"chargecycles = %d, batt_temp = %d\n",
-				last_ocv_uv, chargecycles, batt_temp);
+				"chargecycles = %d, batt_temp = %d"
+				"fcc = %d soc =%d\n",
+				last_ocv_uv, chargecycles, batt_temp,
+				fcc, soc);
 		update_userspace = 0;
 	}
 
-	soc = (remaining_usable_charge * 100) / (fcc - unusable_charge);
-	if (soc > 100 || soc < 0) {
-		pr_err("bad soc rem_usb_chg %d fcc %d unusb_chg %d\n",
-				remaining_usable_charge, fcc, unusable_charge);
-		update_userspace = 0;
-	}
-	pr_debug("SOC = %u%%\n", soc);
-
 	if (update_userspace) {
 		last_soc = soc;
 	}
@@ -1163,7 +1209,7 @@
 
 static void check_initial_ocv(struct pm8921_bms_chip *chip)
 {
-	int ocv, vbatt, rbatt, ibatt, rc;
+	int ocv, rc;
 
 	/*
 	 * Check if a last_good_ocv is available,
@@ -1171,24 +1217,8 @@
 	 */
 	rc = read_last_good_ocv(chip, &ocv);
 	if (rc || ocv == 0) {
-		rc = get_battery_uvolts(chip, &vbatt);
-		if (rc) {
-			pr_err("failed to read vbatt from adc rc = %d\n", rc);
-			last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
-			return;
-		}
-
-		rc =  pm8921_bms_get_battery_current(&ibatt);
-		if (rc) {
-			pr_err("failed to read batt current rc = %d\n", rc);
-			last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
-			return;
-		}
-
-		rbatt = calculate_rbatt(the_chip);
-		if (rbatt < 0)
-			rbatt = DEFAULT_RBATT_MOHMS;
-		last_ocv_uv = vbatt + ibatt * rbatt;
+		rc = adc_based_ocv(chip, &last_ocv_uv);
+		pr_err("failed to read ocv from adc and bms rc = %d\n", rc);
 	}
 	pr_debug("ocv = %d last_ocv_uv = %d\n", ocv, last_ocv_uv);
 }
diff --git a/drivers/regulator/pm8058-xo.c b/drivers/regulator/pm8058-xo.c
index ac65395..581e228 100644
--- a/drivers/regulator/pm8058-xo.c
+++ b/drivers/regulator/pm8058-xo.c
@@ -154,7 +154,7 @@
 		return -EINVAL;
 
 	if (pdev->id >= 0 && pdev->id < PM8058_XO_ID_MAX) {
-		chip = platform_get_drvdata(pdev);
+		chip = dev_get_drvdata(pdev->dev.parent);
 		rdesc = &pm8058_xo_buffer_desc[pdev->id];
 		xo = &pm8058_xo_buffer[pdev->id];
 		xo->pdata = pdev->dev.platform_data;
@@ -163,6 +163,7 @@
 		if (rc)
 			goto bail;
 
+		platform_set_drvdata(pdev, chip);
 		xo->rdev = regulator_register(rdesc, &pdev->dev,
 					&xo->pdata->init_data, xo);
 		if (IS_ERR(xo->rdev)) {
diff --git a/drivers/regulator/pmic8058-regulator.c b/drivers/regulator/pmic8058-regulator.c
index 98ba163..c11f32b 100644
--- a/drivers/regulator/pmic8058-regulator.c
+++ b/drivers/regulator/pmic8058-regulator.c
@@ -1690,7 +1690,7 @@
 		return -EINVAL;
 
 	if (pdev->id >= 0 && pdev->id < PM8058_VREG_MAX) {
-		chip = platform_get_drvdata(pdev);
+		chip = dev_get_drvdata(pdev->dev.parent);
 		rdesc = &pm8058_vreg_descrip[pdev->id];
 		vreg = &pm8058_vreg[pdev->id];
 		vreg->pdata = pdev->dev.platform_data;
@@ -1705,6 +1705,7 @@
 			vreg->pdata->init_data.constraints.valid_modes_mask
 			      &= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
 
+		platform_set_drvdata(pdev, chip);
 		vreg->rdev = regulator_register(rdesc, &pdev->dev,
 				&vreg->pdata->init_data, vreg);
 		if (IS_ERR(vreg->rdev)) {
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 0bdb89e..e53374e 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -30,6 +30,8 @@
 /* RTC_CTRL register bit fields */
 #define PM8xxx_RTC_ENABLE	BIT(7)
 #define PM8xxx_RTC_ALARM_ENABLE	BIT(1)
+#define PM8xxx_RTC_ABORT_ENABLE BIT(0)
+
 #define PM8xxx_RTC_ALARM_CLEAR  BIT(0)
 
 #define NUM_8_BIT_RTC_REGS	0x4
@@ -461,6 +463,14 @@
 		}
 	}
 
+	/* Enable abort enable feature */
+	ctrl_reg |= PM8xxx_RTC_ABORT_ENABLE;
+	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "PM8xxx write failed!\n");
+		goto fail_rtc_enable;
+	}
+
 	rtc_dd->ctrl_reg = ctrl_reg;
 	if (rtc_write_enable == true)
 		pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;
@@ -539,9 +549,48 @@
 	return 0;
 }
 
+static void pm8xxx_rtc_shutdown(struct platform_device *pdev)
+{
+	u8 value[4] = {0, 0, 0, 0};
+	u8 reg;
+	int rc;
+	unsigned long irq_flags;
+	bool rtc_alarm_powerup = false;
+	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+	struct pm8xxx_rtc_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdata != NULL)
+		rtc_alarm_powerup =  pdata->rtc_alarm_powerup;
+
+	if (!rtc_alarm_powerup) {
+
+		spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+		dev_dbg(&pdev->dev, "Disabling alarm interrupts\n");
+
+		/* Disable RTC alarms */
+		reg = rtc_dd->ctrl_reg;
+		reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+		rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_base, 1);
+		if (rc < 0) {
+			dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+			goto fail_alarm_disable;
+		}
+
+		/* Clear Alarm register */
+		rc = pm8xxx_write_wrapper(rtc_dd, value,
+				rtc_dd->alarm_rw_base, NUM_8_BIT_RTC_REGS);
+		if (rc < 0)
+			dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+
+fail_alarm_disable:
+		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+	}
+}
+
 static struct platform_driver pm8xxx_rtc_driver = {
 	.probe		= pm8xxx_rtc_probe,
 	.remove		= __devexit_p(pm8xxx_rtc_remove),
+	.shutdown	= pm8xxx_rtc_shutdown,
 	.driver	= {
 		.name	= PM8XXX_RTC_DEV_NAME,
 		.owner	= THIS_MODULE,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 20b73a1..5e38238 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1105,8 +1105,10 @@
 		cdev->desc.bDeviceClass = device_desc.bDeviceClass;
 		cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
 		cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
-		usb_add_config(cdev, &android_config_driver,
-					android_bind_config);
+		if (usb_add_config(cdev, &android_config_driver,
+							android_bind_config))
+			return size;
+
 		usb_gadget_connect(cdev->gadget);
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index d3059d1..7fd603d 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -499,6 +499,11 @@
 	---help---
 	  Support for EBI2 TMD QVGA (240x320) and Epson QCIF (176x220) panel
 
+config FB_MSM_HDMI_AS_PRIMARY
+	bool "Use HDMI as primary panel"
+	---help---
+	Support for using HDMI as primary
+
 config FB_MSM_PANEL_NONE
 	bool "NONE"
 	---help---
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 4203779..a499a62 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -280,8 +280,11 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	ssize_t ret = strnlen(buf, PAGE_SIZE);
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	int hpd = 1;
+#else
 	int hpd = atoi(buf);
-
+#endif
 	if (external_common_state->hpd_feature) {
 		if (hpd == 0 && external_common_state->hpd_feature_on) {
 			external_common_state->hpd_feature(0);
@@ -1283,7 +1286,11 @@
 	pinfo->pdest = DISPLAY_2;
 	pinfo->wait_cycle = 0;
 	pinfo->bpp = 24;
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	pinfo->fb_num = 2;
+#else
 	pinfo->fb_num = 1;
+#endif
 
 	/* blk */
 	pinfo->lcdc.border_clr = 0;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index fe3c614..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)
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index f07a8b4..a44f7c0 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -223,8 +223,11 @@
 	 * get/set panel specific fb info
 	 */
 	mfd->panel_info = pdata->panel_info;
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+#else
 	mfd->fb_imgType = MDP_RGB_565;
-
+#endif
 	fbi = mfd->fbi;
 	fbi->var.pixclock = mfd->panel_info.clk_rate;
 	fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ecefdc3..f8cadbb 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -453,7 +453,8 @@
 	*luma_off = 0;
 	*chroma_off = 0;
 
-	if (pipe->src_x) {
+	if (pipe->src_x && (pipe->frame_format ==
+		MDP4_FRAME_FORMAT_LINEAR)) {
 		src_xy = (pipe->src_y << 16) | pipe->src_x;
 		src_xy &= 0xffff0000;
 		outpdw(vg_base + 0x0004, src_xy);	/* MDP_RGB_SRC_XY */
@@ -540,7 +541,7 @@
 	outpdw(vg_base + 0x0008, dst_size);	/* MDP_RGB_DST_SIZE */
 	outpdw(vg_base + 0x000c, dst_xy);	/* MDP_RGB_DST_XY */
 
-	if (pipe->frame_format)
+	if (pipe->frame_format != MDP4_FRAME_FORMAT_LINEAR)
 		outpdw(vg_base + 0x0048, frame_size);	/* TILE frame size */
 
 	/*
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index e6ba15e..82bce01 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -115,8 +115,13 @@
 		format = MDP_RGB_565;
 	else if (bpp == 3)
 		format = MDP_RGB_888;
-	else
+	else {
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+		format = MSMFB_DEFAULT_TYPE;
+#else
 		format = MDP_ARGB_8888;
+#endif
+	}
 
 	if (dtv_pipe == NULL) {
 		ptype = mdp4_overlay_format2type(format);
@@ -143,7 +148,12 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	if (is_mdp4_hw_reset()) {
+		mdp4_hw_init();
+		outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+	}
+#endif
 	pipe->src_height = fbi->var.yres;
 	pipe->src_width = fbi->var.xres;
 	pipe->src_h = fbi->var.yres;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index fb0d771..00cffda 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -556,8 +556,17 @@
 		outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
 		mb();
 		isr &= mask;
-		if (isr & INTR_HIST_DONE)
-			complete(&mdp_hist_comp);
+		if (isr & INTR_HIST_DONE) {
+			if (waitqueue_active(&(mdp_hist_comp.wait))) {
+				complete(&mdp_hist_comp);
+			} else {
+				if (mdp_is_hist_start == TRUE) {
+					MDP_OUTP(MDP_BASE + 0x95004,
+							mdp_hist_frame_cnt);
+					MDP_OUTP(MDP_BASE + 0x95000, 1);
+				}
+			}
+		}
 	}
 
 out:
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index bde0573..e5ec4cb 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3002,8 +3002,13 @@
 	 * at panel_info
 	 *
 	 */
-	if (type == HDMI_PANEL || type == DTV_PANEL || type == TV_PANEL)
+	if (type == HDMI_PANEL || type == DTV_PANEL || type == TV_PANEL) {
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+		pdata->panel_info.fb_num = 2;
+#else
 		pdata->panel_info.fb_num = 1;
+#endif
+	}
 	else
 		pdata->panel_info.fb_num = MSM_FB_NUM;
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 87ed889..c2ab8ad 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1133,11 +1133,25 @@
 		vidc_sm_get_metadata_status(&ddl->shared_mem
 			[ddl->command_channel],
 			&decoder->meta_data_exists);
-		if (decoder->output_order == VCD_DEC_ORDER_DISPLAY)
+		if (decoder->output_order == VCD_DEC_ORDER_DISPLAY) {
 			vidc_sm_get_frame_tags(&ddl->shared_mem
 				[ddl->command_channel],
 				&dec_disp_info->tag_top,
 				&dec_disp_info->tag_bottom);
+			if (dec_disp_info->display_correct ==
+				VIDC_1080P_DECODE_NOT_CORRECT ||
+				dec_disp_info->display_correct ==
+				VIDC_1080P_DECODE_APPROX_CORRECT)
+				output_vcd_frm->flags |=
+					VCD_FRAME_FLAG_DATACORRUPT;
+		} else {
+			if (dec_disp_info->decode_correct ==
+				VIDC_1080P_DECODE_NOT_CORRECT ||
+				dec_disp_info->decode_correct ==
+				VIDC_1080P_DECODE_APPROX_CORRECT)
+				output_vcd_frm->flags |=
+					VCD_FRAME_FLAG_DATACORRUPT;
+		}
 		output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
 		vidc_sm_get_picture_times(&ddl->shared_mem
 			[ddl->command_channel],
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index e9d4353..8160895 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -200,6 +200,10 @@
 #define VIDC_SM_CHROMA_ADDR_CHANGE_BMASK  0x00000001
 #define VIDC_SM_CHROMA_ADDR_CHANGE_SHFT   0
 
+#define VIDC_SM_SEI_ENABLE_ADDR                     0x0180
+#define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_BMSK  0x00000001
+#define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_SHFT  0
+
 #define DDL_MEM_WRITE_32(base, offset, val) ddl_mem_write_32(\
 	(u32 *) ((u8 *) (base)->align_virtual_addr + (offset)), (val))
 #define DDL_MEM_READ_32(base, offset) ddl_mem_read_32(\
@@ -703,3 +707,14 @@
 	}
 	DDL_MEM_WRITE_32(shared_mem, 0x15c, profile_enforce);
 }
+void vidc_sm_set_decoder_sei_enable(struct ddl_buf_addr *shared_mem,
+	u32 sei_enable)
+{
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_SEI_ENABLE_ADDR, sei_enable);
+}
+
+void vidc_sm_get_decoder_sei_enable(struct ddl_buf_addr *shared_mem,
+	u32 *sei_enable)
+{
+	*sei_enable = DDL_MEM_READ_32(shared_mem, VIDC_SM_SEI_ENABLE_ADDR);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index c6eed86..8a4b598 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -47,6 +47,7 @@
 #define VIDC_SM_LEVEL_VC1_ADV_3  (3)
 #define VIDC_SM_LEVEL_VC1_ADV_4  (4)
 
+#define VIDC_SM_RECOVERY_POINT_SEI  (1)
 enum VIDC_SM_frame_skip {
 	VIDC_SM_FRAME_SKIP_DISABLE      = 0,
 	VIDC_SM_FRAME_SKIP_ENABLE_LEVEL = 1,
@@ -163,4 +164,8 @@
 	u32 addr_change);
 void vidc_sm_set_mpeg4_profile_override(struct ddl_buf_addr *shared_mem,
 	enum vidc_sm_mpeg4_profileinfo profile_info);
+void vidc_sm_set_decoder_sei_enable(struct ddl_buf_addr *shared_mem,
+	u32 sei_enable);
+void vidc_sm_get_decoder_sei_enable(struct ddl_buf_addr *shared_mem,
+	u32 *sei_enable);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 8ba90a9..8b293b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -246,6 +246,10 @@
 		vidc_sm_set_mpeg4_profile_override(
 			&ddl->shared_mem[ddl->command_channel],
 			VIDC_SM_PROFILE_INFO_ASP);
+	if (VCD_CODEC_H264 == decoder->codec.codec)
+		vidc_sm_set_decoder_sei_enable(
+			&ddl->shared_mem[ddl->command_channel],
+			VIDC_SM_RECOVERY_POINT_SEI);
 	ddl_context->vidc_decode_seq_start[ddl->command_channel](
 		&seq_start_param);
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index ae918f0..5b4cdee 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -36,6 +36,8 @@
 #define VIDC_1080P_SI_RG7_DISPLAY_CROP_MASK      0x00000040
 #define VIDC_1080P_SI_RG7_DISPLAY_CROP_SHIFT     6
 
+#define VIDC_1080P_SI_RG7_DISPLAY_CORRECT_MASK    0x00000180
+#define VIDC_1080P_SI_RG7_DISPLAY_CORRECT_SHIFT   7
 #define VIDC_1080P_SI_RG8_DECODE_FRAMETYPE_MASK  0x00000007
 
 #define VIDC_1080P_SI_RG10_NUM_DPB_BMSK      0x00003fff
@@ -54,6 +56,8 @@
 #define VIDC_1080P_SI_RG11_DECODE_CROPP_MASK     0x00000100
 #define VIDC_1080P_SI_RG11_DECODE_CROPP_SHIFT    8
 
+#define VIDC_1080P_SI_RG11_DECODE_CORRECT_MASK    0x00000600
+#define VIDC_1080P_SI_RG11_DECODE_CORRECT_SHIFT   9
 #define VIDC_1080P_BASE_OFFSET_SHIFT         11
 
 
@@ -501,6 +505,9 @@
 	dec_disp_info->disp_crop_exists = VIDC_GETFIELD(display_result,
 		VIDC_1080P_SI_RG7_DISPLAY_CROP_MASK,
 		VIDC_1080P_SI_RG7_DISPLAY_CROP_SHIFT);
+	dec_disp_info->display_correct = VIDC_GETFIELD(display_result,
+		VIDC_1080P_SI_RG7_DISPLAY_CORRECT_MASK,
+		VIDC_1080P_SI_RG7_DISPLAY_CORRECT_SHIFT);
 }
 
 void vidc_1080p_get_decode_frame(
@@ -535,6 +542,9 @@
 	dec_disp_info->dec_crop_exists = VIDC_GETFIELD(decode_result,
 		VIDC_1080P_SI_RG11_DECODE_CROPP_MASK,
 		VIDC_1080P_SI_RG11_DECODE_CROPP_SHIFT);
+	dec_disp_info->decode_correct = VIDC_GETFIELD(decode_result,
+		VIDC_1080P_SI_RG11_DECODE_CORRECT_MASK,
+		VIDC_1080P_SI_RG11_DECODE_CORRECT_SHIFT);
 }
 
 void vidc_1080p_decode_seq_start_ch0(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index f871509..415030a 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -270,6 +270,12 @@
 	VIDC_1080P_DECODE_FRAMETYPE_OTHERS     = 4,
 	VIDC_1080P_DECODE_FRAMETYPE_32BIT      = 0x7FFFFFFF
 };
+enum vidc_1080P_decode_frame_correct_type {
+	VIDC_1080P_DECODE_NOT_CORRECT = 0,
+	VIDC_1080P_DECODE_CORRECT = 1,
+	VIDC_1080P_DECODE_APPROX_CORRECT = 2,
+	VIDC_1080P_DECODE_CORRECTTYPE_32BIT = 0x7FFFFFFF
+};
 enum vidc_1080p_encode_frame{
 	VIDC_1080P_ENCODE_FRAMETYPE_NOT_CODED  = 0,
 	VIDC_1080P_ENCODE_FRAMETYPE_I          = 1,
@@ -417,6 +423,8 @@
 	enum vidc_1080p_display_status decode_status;
 	enum vidc_1080p_display_coding display_coding;
 	enum vidc_1080p_display_coding decode_coding;
+	enum vidc_1080P_decode_frame_correct_type display_correct;
+	enum vidc_1080P_decode_frame_correct_type decode_correct;
 	enum vidc_1080p_decode_frame input_frame;
 };
 void vidc_1080p_do_sw_reset(enum vidc_1080p_reset init_flag);
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/vcd/vcd_api.h b/drivers/video/msm/vidc/common/vcd/vcd_api.h
index 5735ce2..dec0326 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.h
@@ -17,6 +17,7 @@
 
 #define VCD_FRAME_FLAG_EOS 0x00000001
 #define VCD_FRAME_FLAG_DECODEONLY   0x00000004
+#define VCD_FRAME_FLAG_DATACORRUPT 0x00000008
 #define VCD_FRAME_FLAG_ENDOFFRAME 0x00000010
 #define VCD_FRAME_FLAG_SYNCFRAME 0x00000020
 #define VCD_FRAME_FLAG_EXTRADATA 0x00000040
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index e46dab1..e3fbecb 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -200,6 +200,7 @@
 header-y += inotify.h
 header-y += input.h
 header-y += ioctl.h
+header-y += ion.h
 header-y += ip.h
 header-y += ip6_tunnel.h
 header-y += ip_vs.h
diff --git a/include/linux/idle_stats_device.h b/include/linux/idle_stats_device.h
index 0b1ee39..7906d18 100644
--- a/include/linux/idle_stats_device.h
+++ b/include/linux/idle_stats_device.h
@@ -9,6 +9,7 @@
 #define MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED_RESET 2
 #define MSM_IDLE_STATS_EVENT_COLLECTION_NEARLY_FULL   4
 #define MSM_IDLE_STATS_EVENT_COLLECTION_FULL          8
+#define MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED      16
 
 /*
  * All time, timer, and time interval values are in units of
diff --git a/include/linux/ion.h b/include/linux/ion.h
index df44376..ece819d 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -19,7 +19,6 @@
 
 #include <linux/ioctl.h>
 #include <linux/types.h>
-#include <mach/ion.h>
 
 
 struct ion_handle;
@@ -74,6 +73,7 @@
 #define ION_IS_CACHED(__flags)	((__flags) & (1 << ION_CACHE_SHIFT))
 
 #ifdef __KERNEL__
+#include <mach/ion.h>
 struct ion_device;
 struct ion_heap;
 struct ion_mapper;
diff --git a/include/linux/mfd/pm8xxx/rtc.h b/include/linux/mfd/pm8xxx/rtc.h
index 14f1983..bb3f98a 100644
--- a/include/linux/mfd/pm8xxx/rtc.h
+++ b/include/linux/mfd/pm8xxx/rtc.h
@@ -20,6 +20,7 @@
  */
 struct pm8xxx_rtc_platform_data {
 	bool rtc_write_enable;
+	bool rtc_alarm_powerup;
 };
 
 #endif /* __RTC_PM8XXX_H__ */
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
index 8370f18..4d9f257 100644
--- a/include/linux/mfd/pmic8058.h
+++ b/include/linux/mfd/pmic8058.h
@@ -80,6 +80,7 @@
 struct pm8058_platform_data {
 	/* This table is only needed for misc interrupts. */
 	int		irq_base;
+	int		irq;
 	int 		(*init)(struct pm8058_chip *pm_chip);
 
 	int		num_subdevs;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index ae26f27..b55cfe1 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -27,6 +27,9 @@
 
 #define KGSL_MAX_PWRLEVELS 5
 
+#define KGSL_CONVERT_TO_MBPS(val) \
+	(val*1000*1000U)
+
 /* device id */
 enum kgsl_deviceid {
 	KGSL_DEVICE_3D0		= 0x00000000,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 26994fc..144caa0 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -79,6 +79,7 @@
 	MDP_Y_CRCB_H2V2_TILE,  /* Y and CrCb, pseudo planer tile */
 	MDP_Y_CBCR_H2V2_TILE,  /* Y and CbCr, pseudo planer tile */
 	MDP_Y_CR_CB_H2V2,  /* Y, Cr and Cb, planar */
+	MDP_Y_CR_CB_GH2V2,  /* Y, Cr and Cb, planar aligned to Android YV12 */
 	MDP_Y_CB_CR_H2V2,  /* Y, Cb and Cr, planar */
 	MDP_Y_CRCB_H1V1,  /* Y and CrCb, pseduo planer w/ Cr is in MSB */
 	MDP_Y_CBCR_H1V1,  /* Y and CbCr, pseduo planer w/ Cb is in MSB */
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..f6668ef 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -156,7 +156,7 @@
 #define VFE_CMD_DEMOSAICV3_DBCC_UPDATE                  110
 #define VFE_CMD_DEMOSAICV3_DBPC_UPDATE                  111
 #define VFE_CMD_XBAR_CFG                                112
-#define VFE_CMD_EZTUNE_CFG                              113
+#define VFE_CMD_MODULE_CFG                              113
 #define VFE_CMD_ZSL                                     114
 #define VFE_CMD_LINEARIZATION_UPDATE                    115
 #define VFE_CMD_DEMOSAICV3_ABF_UPDATE                   116
@@ -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/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/lib/Kconfig.debug b/lib/Kconfig.debug
index c6b006a..6a9e368 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -413,7 +413,7 @@
 
 config DEBUG_KMEMLEAK
 	bool "Kernel memory leak detector"
-	depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
+	depends on DEBUG_KERNEL && EXPERIMENTAL && \
 		(X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
 
 	select DEBUG_FS
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index aacee45..4facb03 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -100,6 +100,7 @@
 
 #include <linux/kmemcheck.h>
 #include <linux/kmemleak.h>
+#include <linux/memory_hotplug.h>
 
 /*
  * Kmemleak configuration and common defines.
@@ -1220,9 +1221,9 @@
 #endif
 
 	/*
-	 * Struct page scanning for each node. The code below is not yet safe
-	 * with MEMORY_HOTPLUG.
+	 * Struct page scanning for each node.
 	 */
+	lock_memory_hotplug();
 	for_each_online_node(i) {
 		pg_data_t *pgdat = NODE_DATA(i);
 		unsigned long start_pfn = pgdat->node_start_pfn;
@@ -1241,6 +1242,7 @@
 			scan_block(page, page + 1, NULL, 1);
 		}
 	}
+	unlock_memory_hotplug();
 
 	/*
 	 * Scanning the task stacks (may introduce false negatives).
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index a6e2aab..94d0f06 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -438,6 +438,7 @@
 		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) {
@@ -686,6 +687,8 @@
 
 	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
+	hci_conn_hold(hcon);
+
 	return 0;
 }
 
@@ -846,7 +849,8 @@
 		reason = 0;
 		err = -EPERM;
 		del_timer(&hcon->smp_timer);
-		mgmt_auth_failed(hcon->hdev->id, conn->dst, skb->data[1]);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+		mgmt_auth_failed(hcon->hdev->id, conn->dst, skb->data[0]);
 		hci_conn_put(hcon);
 		break;
 
@@ -895,6 +899,7 @@
 		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);
 	}
@@ -989,6 +994,7 @@
 			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);
 	}
@@ -1002,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);
 
@@ -1009,6 +1017,9 @@
 	else if (hcon->sec_req  && (status || !encrypt))
 		smp_conn_security(conn, hcon->sec_level);
 
+	else
+		hci_conn_put(hcon);
+
 	return 0;
 }
 
@@ -1020,6 +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/scripts/checkpatch.pl b/scripts/checkpatch.pl
index c96213d..de6f8e1 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1229,7 +1229,6 @@
 	my @setup_docs = ();
 	my $setup_docs = 0;
 
-	my $in_code_block = 0;
 	my $exec_file = "";
 
 	my $shorttext = BEFORE_SHORTTEXT;
@@ -1375,6 +1374,7 @@
 		if ($line =~ /^diff --git.*?(\S+)$/) {
 			$realfile = $1;
 			$realfile =~ s@^([^/]*)/@@;
+			$exec_file = $realfile;
 
 		} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
 			$realfile = $1;
@@ -1389,16 +1389,14 @@
 			if ($realfile =~ m@^include/asm/@) {
 				ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
 			}
-			$in_code_block = 1;
+			$exec_file = "";
 			next;
 		}
 		elsif ($rawline =~ /^diff.+a\/(.+)\sb\/.+$/) {
 			$exec_file = $1;
-			$in_code_block = 0;
 		}
 		#Check state to make sure we aren't in code block.
-		elsif  (!$in_code_block			   &&
-			($exec_file =~ /^.+\.[chS]$/ or
+		elsif  (($exec_file =~ /^.+\.[chS]$/ or
 			 $exec_file =~ /^.+\.txt$/ or
 			 $exec_file =~ /^.+\.ihex$/ or
 			 $exec_file =~ /^.+\.hex$/ or
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d169001..ec31c0f 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -240,7 +240,14 @@
 		digital_gain),
 	SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
 		40, digital_gain),
-
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
+		40, digital_gain),
 	SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),