Merge "Bluetooth: Schedule HCI_TX task after connection cleanup" into msm-3.0
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2097e0a..0a7fe5f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -222,6 +222,10 @@
 	  to allow physical memory down to a theoretical minimum of 64K
 	  boundaries.
 
+config GENERIC_BUG
+	def_bool y
+	depends on BUG
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 342aad6..45b6e60 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -249,6 +249,8 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index c524759..7e91971 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -248,6 +248,8 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_MSM_SOC=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 985d735..3346397 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -62,6 +62,7 @@
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 CONFIG_MSM_SDIO_SMEM=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V3=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -344,6 +345,8 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index dbde99f..654edb5 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -54,6 +54,7 @@
 # CONFIG_MSM_RPCSERVER_HANDSET is not set
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V3=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -332,6 +333,8 @@
 CONFIG_SND_SOC=y
 CONFIG_MSM_8x60_VOIP=y
 CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 748b8ca..2abe7e9 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -75,7 +75,6 @@
 CONFIG_MSM_QDSS=y
 CONFIG_MSM_SLEEP_STATS=y
 CONFIG_STRICT_MEMORY_RWX=y
-CONFIG_MSM_SHOW_RESUME_IRQ=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -292,11 +291,11 @@
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MT9M114=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_GEMINI=y
-CONFIG_MT9M114=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -323,6 +322,8 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index b5aa1b4..ed9a45b 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -187,8 +187,8 @@
 CONFIG_RTC_DRV_PM8XXX=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
-CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 4d88425..9abe7a0 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -3,21 +3,58 @@
 
 
 #ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-extern void __bug(const char *file, int line) __attribute__((noreturn));
 
-/* give file/line information */
-#define BUG()		__bug(__FILE__, __LINE__)
-
+/*
+ * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
+ * We need to be careful not to conflict with those used by other modules and
+ * the register_undef_hook() system.
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+#define BUG_INSTR_VALUE 0xde02
+#define BUG_INSTR_TYPE ".hword "
 #else
-
-/* this just causes an oops */
-#define BUG()		do { *(int *)0 = 0; } while (1)
-
+#define BUG_INSTR_VALUE 0xe7f001f2
+#define BUG_INSTR_TYPE ".word "
 #endif
 
+
+#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
+#define _BUG(file, line, value) __BUG(file, line, value)
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+/*
+ * The extra indirection is to ensure that the __FILE__ string comes through
+ * OK. Many version of gcc do not support the asm %c parameter which would be
+ * preferable to this unpleasantness. We use mergeable string sections to
+ * avoid multiple copies of the string appearing in the kernel image.
+ */
+
+#define __BUG(__file, __line, __value)				\
+do {								\
+	BUILD_BUG_ON(sizeof(struct bug_entry) != 12);		\
+	asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n"	\
+		".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
+		"2:\t.asciz " #__file "\n" 			\
+		".popsection\n" 				\
+		".pushsection __bug_table,\"a\"\n"		\
+		"3:\t.word 1b, 2b\n"				\
+		"\t.hword " #__line ", 0\n"			\
+		".popsection");					\
+	unreachable();						\
+} while (0)
+
+#else  /* not CONFIG_DEBUG_BUGVERBOSE */
+
+#define __BUG(__file, __line, __value)				\
+do {								\
+	asm volatile(BUG_INSTR_TYPE #__value);			\
+	unreachable();						\
+} while (0)
+#endif  /* CONFIG_DEBUG_BUGVERBOSE */
+
 #define HAVE_ARCH_BUG
-#endif
+#endif  /* CONFIG_BUG */
 
 #include <asm-generic/bug.h>
 
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 2f8bf62..b0c57a9 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -398,6 +398,15 @@
 	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
 	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
 	mov	r3, r3
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	ldr	r3, =0xff00fc00
+	and	r3, r9, r3
+	ldr 	r4, =0x51000400
+	cmp	r3, r4
+	mrceq	p15, 7, r3, c15, c0, 2
+	biceq	r3, r3, #0x400
+	mcreq	p15, 7, r3, c15, c0, 2
+#endif
 	mov	r3, r13
 	mov	pc, r3
 __enable_mmu_end:
diff --git a/arch/arm/kernel/perf_event_msm_krait_l2.c b/arch/arm/kernel/perf_event_msm_krait_l2.c
index c8b48a8..335ccaf 100644
--- a/arch/arm/kernel/perf_event_msm_krait_l2.c
+++ b/arch/arm/kernel/perf_event_msm_krait_l2.c
@@ -117,7 +117,7 @@
 	set_l2_indirect_reg(group_reg, resr_val);
 }
 
-static void set_evfilter(int ctr)
+static void set_evfilter_task_mode(int ctr)
 {
 	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
 	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
@@ -125,6 +125,14 @@
 	set_l2_indirect_reg(filter_reg, filter_val);
 }
 
+static void set_evfilter_sys_mode(int ctr)
+{
+	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+	u32 filter_val = 0x000f003f;
+
+	set_l2_indirect_reg(filter_reg, filter_val);
+}
+
 static void enable_intenset(u32 idx)
 {
 	if (idx == L2CYCLE_CTR_EVENT_IDX)
@@ -298,7 +306,10 @@
 	set_evres(evdesc.event_groupsel, evdesc.event_reg,
 		  evdesc.event_group_code);
 
-	set_evfilter(idx);
+	if (event->cpu < 0)
+		set_evfilter_task_mode(idx);
+	else
+		set_evfilter_sys_mode(idx);
 
 out:
 	enable_intenset(idx);
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
index 33fb5bf..c242754 100644
--- a/arch/arm/kernel/perf_event_msm_l2.c
+++ b/arch/arm/kernel/perf_event_msm_l2.c
@@ -427,13 +427,20 @@
 	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
 }
 
-static void bb_l2_set_evfilter(void)
+static void bb_l2_set_evfilter_task_mode(void)
 {
 	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
 
 	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
 }
 
+static void bb_l2_set_evfilter_sys_mode(void)
+{
+	u32 filter_val = 0x000f003f;
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
 static void bb_l2_enable_intenset(u32 idx)
 {
 	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
@@ -633,7 +640,10 @@
 
 	bb_l2_set_evcntcr();
 
-	bb_l2_set_evfilter();
+	if (event->cpu < 0)
+		bb_l2_set_evfilter_task_mode();
+	else
+		bb_l2_set_evfilter_sys_mode();
 
 	bb_l2_evt_setup(evtinfo.grp, evtinfo.val);
 
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c063c56..ef37557 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -21,6 +21,7 @@
 #include <linux/kdebug.h>
 #include <linux/module.h>
 #include <linux/kexec.h>
+#include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -270,6 +271,8 @@
 	raw_spin_lock_irq(&die_lock);
 	console_verbose();
 	bust_spinlocks(1);
+	if (!user_mode(regs))
+		report_bug(regs->ARM_pc, regs);
 	ret = __die(str, err, thread, regs);
 
 	if (regs && kexec_should_crash(thread->task))
@@ -301,6 +304,24 @@
 	}
 }
 
+#ifdef CONFIG_GENERIC_BUG
+
+int is_valid_bugaddr(unsigned long pc)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+	unsigned short bkpt;
+#else
+	unsigned long bkpt;
+#endif
+
+	if (probe_kernel_address((unsigned *)pc, bkpt))
+		return 0;
+
+	return bkpt == BUG_INSTR_VALUE;
+}
+
+#endif
+
 static LIST_HEAD(undef_hook);
 static DEFINE_RAW_SPINLOCK(undef_lock);
 
@@ -697,16 +718,6 @@
 	arm_notify_die("unknown data abort code", regs, &info, instr, 0);
 }
 
-void __attribute__((noreturn)) __bug(const char *file, int line)
-{
-	printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
-	*(int *)0 = 0;
-
-	/* Avoid "noreturn function does return" */
-	for (;;);
-}
-EXPORT_SYMBOL(__bug);
-
 void __readwrite_bug(const char *fn)
 {
 	printk("%s called, but not implemented\n", fn);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 8652d45..6530fa3 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -24,7 +24,8 @@
 #define ARM_CPU_KEEP(x)
 #endif
 
-#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
+#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
+	defined(CONFIG_GENERIC_BUG)
 #define ARM_EXIT_KEEP(x)	x
 #else
 #define ARM_EXIT_KEEP(x)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 204aa5d..a0cf8ca 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -151,6 +151,8 @@
 	select ARCH_MEMORY_PROBE
 	select ARCH_MEMORY_REMOVE
 	select FIX_MOVABLE_ZONE
+	select CLEANCACHE
+	select QCACHE
 
 config ARCH_MSM8930
 	bool "MSM8930"
@@ -1580,6 +1582,13 @@
 
 	  Say yes to support these devices.
 
+config MSM_PIL_QDSP6V3
+	tristate "QDSP6v3 (Hexagon) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down QDSP6v3 processors (hexagon).
+	  The QDSP6 is a low power DSP used in audio software applications.
+
 config MSM_PIL_QDSP6V4
 	tristate "QDSP6v4 (Hexagon) Boot Support"
 	depends on MSM_PIL
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 05f4ab4..ee15313 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -71,6 +71,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += peripheral-reset.o
 obj-$(CONFIG_ARCH_MSM8960) += peripheral-reset-8960.o
 endif
+obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
 obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
@@ -214,10 +215,10 @@
 obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
 obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
 obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -231,7 +232,7 @@
 obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
 board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
 board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o
-board-8064-all-objs += board-8064.o board-8064-storage.o
+board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o
 obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 82d8173..c9ca339 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -244,6 +244,57 @@
 		},
 };
 
+/*TODO: Update the rpm vreg id when the rpm driver is ready */
+static struct scalable scalable_8930[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+};
+
 static struct scalable *scalable;
 static struct l2_level *l2_freq_tbl;
 static struct acpu_level *acpu_freq_tbl;
@@ -461,6 +512,51 @@
 	{ 0, { 0 } }
 };
 
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8930[(x)])
+static struct l2_level l2_freq_tbl_8930[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 2 },
+	[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 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8930[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   937500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   962500 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   987500 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+	{ 0, { 0 } }
+};
+
 static unsigned long acpuclk_8960_get_rate(int cpu)
 {
 	return scalable[cpu].current_speed->khz;
@@ -527,7 +623,7 @@
 {
 	int rc;
 
-	if (cpu_is_msm8960()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930()) {
 		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
 				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
 				sc->vreg[VREG_HFPLL_A].max_vdd, 0);
@@ -574,7 +670,7 @@
 	 */
 	writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
 
-	if (cpu_is_msm8960()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930()) {
 		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
 				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
 				0, 0);
@@ -1122,7 +1218,7 @@
 	struct acpu_level *l, *max_acpu_level = NULL;
 
 	/* Select frequency tables. */
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
+	if (cpu_is_msm8960()) {
 		uint32_t pte_efuse, pvs;
 		struct acpu_level *v1, *v2;
 
@@ -1170,6 +1266,11 @@
 		acpu_freq_tbl = acpu_freq_tbl_8064;
 		l2_freq_tbl = l2_freq_tbl_8064;
 		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
+	} else if (cpu_is_msm8930()) {
+		scalable = scalable_8930;
+		acpu_freq_tbl = acpu_freq_tbl_8930;
+		l2_freq_tbl = l2_freq_tbl_8930;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8930);
 	} else {
 		BUG();
 	}
@@ -1210,3 +1311,7 @@
 struct acpuclk_soc_data acpuclk_8960_soc_data __initdata = {
 	.init = acpuclk_8960_init,
 };
+
+struct acpuclk_soc_data acpuclk_8930_soc_data __initdata = {
+	.init = acpuclk_8960_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index 2b188d8..b12258f 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -109,5 +109,6 @@
 extern struct acpuclk_soc_data acpuclk_8960_soc_data;
 extern struct acpuclk_soc_data acpuclk_9xxx_soc_data;
 extern struct acpuclk_soc_data acpuclk_9615_soc_data;
+extern struct acpuclk_soc_data acpuclk_8930_soc_data;
 
 #endif
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
new file mode 100644
index 0000000..50673b4
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -0,0 +1,154 @@
+/* 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8064.h"
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+/* The SPI configurations apply to GSBI 5*/
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* The SPI configurations apply to GSBI 5 chip select 2*/
+static struct gpiomux_setting gpio_spi_cs2_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+struct msm_gpiomux_config apq8064_ethernet_configs[] = {
+	{
+		.gpio = 43,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+			[GPIOMUX_ACTIVE] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
+static struct gpiomux_setting audio_auxpcm[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_1,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+};
+
+static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	{
+		.gpio      = 51,		/* GSBI5 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 52,		/* GSBI5 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 31,		/* GSBI5 QUP SPI_CS2_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+		},
+	},
+	{
+		.gpio      = 54,		/* GSBI5 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+#endif
+};
+
+static struct msm_gpiomux_config apq8064_audio_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 43,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 44,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 45,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 46,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+};
+
+void __init apq8064_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return;
+	}
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(apq8064_ethernet_configs,
+			ARRAY_SIZE(apq8064_ethernet_configs));
+#endif
+
+	msm_gpiomux_install(apq8064_gsbi_configs,
+			ARRAY_SIZE(apq8064_gsbi_configs));
+
+	msm_gpiomux_install(apq8064_audio_auxpcm_configs,
+			ARRAY_SIZE(apq8064_audio_auxpcm_configs));
+}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
new file mode 100644
index 0000000..032d8da
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -0,0 +1,102 @@
+/* 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8064.h"
+
+
+static struct pm8xxx_mpp_platform_data
+apq8064_pm8921_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_gpio_platform_data
+apq8064_pm8921_gpio_pdata __devinitdata = {
+	.gpio_base	= PM8921_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_irq_platform_data
+apq8064_pm8921_irq_pdata __devinitdata = {
+	.irq_base		= PM8921_IRQ_BASE,
+	.devirq			= PM8921_USR_IRQ_N,
+	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
+	.dev_id			= 0,
+};
+
+static struct pm8921_platform_data
+apq8064_pm8921_platform_data __devinitdata = {
+	.regulator_pdatas	= msm8064_pm8921_regulator_pdata,
+	.irq_pdata		= &apq8064_pm8921_irq_pdata,
+	.gpio_pdata		= &apq8064_pm8921_gpio_pdata,
+	.mpp_pdata		= &apq8064_pm8921_mpp_pdata,
+};
+
+static struct pm8xxx_irq_platform_data
+apq8064_pm8821_irq_pdata __devinitdata = {
+	.irq_base		= PM8821_IRQ_BASE,
+	.devirq			= PM8821_USR_IRQ_N,
+	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
+	.dev_id			= 1,
+};
+
+static struct pm8xxx_mpp_platform_data
+apq8064_pm8821_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8821_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8821_platform_data
+apq8064_pm8821_platform_data __devinitdata = {
+	.irq_pdata	= &apq8064_pm8821_irq_pdata,
+	.mpp_pdata	= &apq8064_pm8821_mpp_pdata,
+};
+
+static struct msm_ssbi_platform_data apq8064_ssbi_pm8921_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name		= "pm8921-core",
+		.platform_data	= &apq8064_pm8921_platform_data,
+	},
+};
+
+static struct msm_ssbi_platform_data apq8064_ssbi_pm8821_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name		= "pm8821-core",
+		.platform_data	= &apq8064_pm8821_platform_data,
+	},
+};
+
+void __init apq8064_init_pmic(void)
+{
+	apq8064_device_ssbi_pmic1.dev.platform_data =
+						&apq8064_ssbi_pm8921_pdata;
+	apq8064_device_ssbi_pmic2.dev.platform_data =
+				&apq8064_ssbi_pm8821_pdata;
+	apq8064_pm8921_platform_data.num_regulators =
+					msm8064_pm8921_regulator_pdata_len;
+
+	if (machine_is_apq8064_rumi3()) {
+		apq8064_pm8921_irq_pdata.devirq = 0;
+		apq8064_pm8821_irq_pdata.devirq = 0;
+	}
+}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 6e2c044..b13a48c 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -48,7 +48,7 @@
 
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x600000
 #define MSM_PMEM_ADSP_SIZE         0x3800000
-#define MSM_PMEM_AUDIO_SIZE        0x28B000
+#define MSM_PMEM_AUDIO_SIZE        0x2B4000
 #define MSM_PMEM_SIZE 0x1800000 /* 24 Mbytes */
 
 static struct memtype_reserve apq8064_reserve_table[] __initdata = {
@@ -152,7 +152,6 @@
 	apq8064_reserve_table[p->memory_type].size += p->size;
 }
 
-
 static void __init reserve_pmem_memory(void)
 {
 	reserve_memory_for(&android_pmem_adsp_pdata);
@@ -467,27 +466,28 @@
 #ifdef CONFIG_HW_RANDOM_MSM
 	&apq8064_device_rng,
 #endif
-	&msm_pcm,
-	&msm_pcm_routing,
-	&msm_cpudai0,
-	&msm_cpudai1,
-	&msm_cpudai_hdmi_rx,
-	&msm_cpudai_bt_rx,
-	&msm_cpudai_bt_tx,
-	&msm_cpudai_fm_rx,
-	&msm_cpudai_fm_tx,
-	&msm_cpu_fe,
-	&msm_stub_codec,
-	&msm_voice,
-	&msm_voip,
-	&msm_lpa_pcm,
-	&msm_cpudai_afe_01_rx,
-	&msm_cpudai_afe_01_tx,
-	&msm_cpudai_afe_02_rx,
-	&msm_cpudai_afe_02_tx,
-	&msm_pcm_afe,
-	&msm_cpudai_auxpcm_rx,
-	&msm_cpudai_auxpcm_tx,
+	&apq_pcm,
+	&apq_pcm_routing,
+	&apq_cpudai0,
+	&apq_cpudai1,
+	&apq_cpudai_hdmi_rx,
+	&apq_cpudai_bt_rx,
+	&apq_cpudai_bt_tx,
+	&apq_cpudai_fm_rx,
+	&apq_cpudai_fm_tx,
+	&apq_cpu_fe,
+	&apq_stub_codec,
+	&apq_voice,
+	&apq_voip,
+	&apq_lpa_pcm,
+	&apq_pcm_hostless,
+	&apq_cpudai_afe_01_rx,
+	&apq_cpudai_afe_01_tx,
+	&apq_cpudai_afe_02_rx,
+	&apq_cpudai_afe_02_tx,
+	&apq_pcm_afe,
+	&apq_cpudai_auxpcm_rx,
+	&apq_cpudai_auxpcm_tx,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -521,130 +521,6 @@
 	},
 };
 
-#ifdef CONFIG_KS8851
-static struct gpiomux_setting gpio_eth_config = {
-	.pull = GPIOMUX_PULL_NONE,
-	.drv = GPIOMUX_DRV_8MA,
-	.func = GPIOMUX_FUNC_GPIO,
-};
-
-/* The SPI configurations apply to GSBI 5*/
-static struct gpiomux_setting gpio_spi_config = {
-	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-/* The SPI configurations apply to GSBI 5 chip select 2*/
-static struct gpiomux_setting gpio_spi_cs2_config = {
-	.func = GPIOMUX_FUNC_3,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-#endif
-
-struct msm_gpiomux_config apq8064_ethernet_configs[NR_GPIO_IRQS] = {
-#ifdef CONFIG_KS8851
-	{
-		.gpio = KS8851_IRQ_GPIO,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
-			[GPIOMUX_ACTIVE] = &gpio_eth_config,
-		}
-	},
-#endif
-};
-
-static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
-#ifdef CONFIG_KS8851
-	{
-		.gpio      = 51,		/* GSBI5 QUP SPI_DATA_MOSI */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 52,		/* GSBI5 QUP SPI_DATA_MISO */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 31,		/* GSBI5 QUP SPI_CS2_N */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
-		},
-	},
-	{
-		.gpio      = 54,		/* GSBI5 QUP SPI_CLK */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-#endif
-};
-
-static struct pm8xxx_mpp_platform_data
-apq8064_pm8921_mpp_pdata __devinitdata = {
-	.mpp_base	= PM8921_MPP_PM_TO_SYS(1),
-};
-
-static struct pm8xxx_gpio_platform_data
-apq8064_pm8921_gpio_pdata __devinitdata = {
-	.gpio_base	= PM8921_GPIO_PM_TO_SYS(1),
-};
-
-static struct pm8xxx_irq_platform_data
-apq8064_pm8921_irq_pdata __devinitdata = {
-	.irq_base		= PM8921_IRQ_BASE,
-	.devirq			= PM8921_USR_IRQ_N,
-	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
-	.dev_id			= 0,
-};
-
-static struct pm8921_platform_data
-apq8064_pm8921_platform_data __devinitdata = {
-	.regulator_pdatas	= msm8064_pm8921_regulator_pdata,
-	.irq_pdata		= &apq8064_pm8921_irq_pdata,
-	.gpio_pdata		= &apq8064_pm8921_gpio_pdata,
-	.mpp_pdata		= &apq8064_pm8921_mpp_pdata,
-};
-
-static struct pm8xxx_irq_platform_data
-apq8064_pm8821_irq_pdata __devinitdata = {
-	.irq_base		= PM8821_IRQ_BASE,
-	.devirq			= PM8821_USR_IRQ_N,
-	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
-	.dev_id			= 1,
-};
-
-static struct pm8xxx_mpp_platform_data
-apq8064_pm8821_mpp_pdata __devinitdata = {
-	.mpp_base	= PM8821_MPP_PM_TO_SYS(1),
-};
-
-static struct pm8821_platform_data
-apq8064_pm8821_platform_data __devinitdata = {
-	.irq_pdata	= &apq8064_pm8821_irq_pdata,
-	.mpp_pdata	= &apq8064_pm8821_mpp_pdata,
-};
-
-static struct msm_ssbi_platform_data apq8064_ssbi_pm8921_pdata __devinitdata = {
-	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
-	.slave	= {
-		.name		= "pm8921-core",
-		.platform_data	= &apq8064_pm8921_platform_data,
-	},
-};
-
-static struct msm_ssbi_platform_data apq8064_ssbi_pm8821_pdata __devinitdata = {
-	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
-	.slave	= {
-		.name		= "pm8821-core",
-		.platform_data	= &apq8064_pm8821_platform_data,
-	},
-};
-
 static struct slim_boardinfo apq8064_slim_devices[] = {
 	{
 	.bus_num = 1,
@@ -658,77 +534,12 @@
 	.src_clk_rate = 24000000,
 };
 
-
-static struct gpiomux_setting audio_auxpcm[] = {
-	/* Suspended state */
-	{
-		.func = GPIOMUX_FUNC_GPIO,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-	/* Active state */
-	{
-		.func = GPIOMUX_FUNC_1,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-};
-static struct msm_gpiomux_config apq8064_audio_auxpcm_configs[] __initdata = {
-	{
-		.gpio = 43,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 44,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 45,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 46,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-};
-
 static void __init apq8064_i2c_init(void)
 {
 	apq8064_device_qup_i2c_gsbi4.dev.platform_data =
 					&apq8064_i2c_qup_gsbi4_pdata;
 }
 
-static int __init gpiomux_init(void)
-{
-	int rc;
-
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
-	if (rc) {
-		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
-		return rc;
-	}
-	msm_gpiomux_install(apq8064_ethernet_configs,
-			ARRAY_SIZE(apq8064_ethernet_configs));
-
-	msm_gpiomux_install(apq8064_gsbi_configs,
-			ARRAY_SIZE(apq8064_gsbi_configs));
-	msm_gpiomux_install(apq8064_audio_auxpcm_configs,
-			ARRAY_SIZE(apq8064_audio_auxpcm_configs));
-	return 0;
-}
-
 #ifdef CONFIG_KS8851
 static int ethernet_init(void)
 {
@@ -763,18 +574,13 @@
 	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 	apq8064_clock_init();
-	gpiomux_init();
+	apq8064_init_gpiomux();
 	apq8064_i2c_init();
 
 	apq8064_device_qup_spi_gsbi5.dev.platform_data =
 						&apq8064_qup_spi_gsbi5_pdata;
-	apq8064_device_ssbi_pmic1.dev.platform_data =
-						&apq8064_ssbi_pm8921_pdata;
-	apq8064_device_ssbi_pmic2.dev.platform_data =
-				&apq8064_ssbi_pm8821_pdata;
+	apq8064_init_pmic();
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
-	apq8064_pm8921_platform_data.num_regulators =
-					msm8064_pm8921_regulator_pdata_len;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	apq8064_init_mmc();
 	slim_register_board_info(apq8064_slim_devices,
@@ -793,8 +599,6 @@
 
 static void __init apq8064_rumi3_init(void)
 {
-	apq8064_pm8921_irq_pdata.devirq = 0;
-	apq8064_pm8821_irq_pdata.devirq = 0;
 	apq8064_common_init();
 	ethernet_init();
 	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index d9da00a..4a48897 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -42,4 +42,6 @@
 		struct mmc_platform_data *plat);
 
 void apq8064_init_mmc(void);
+void apq8064_init_gpiomux(void);
+void apq8064_init_pmic(void);
 #endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index f1103cb..2fb6153 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -781,7 +781,7 @@
 	platform_device_register(&mipi_dsi_novatek_panel_device);
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-	if (!cpu_is_msm8627())
+	if (!cpu_is_msm8930())
 		platform_device_register(&hdmi_msm_device);
 #endif
 
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index d6c6ec8..620716a 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -117,7 +117,7 @@
 #endif
 
 #define MSM_PMEM_ADSP_SIZE         0x3800000
-#define MSM_PMEM_AUDIO_SIZE        0x28B000
+#define MSM_PMEM_AUDIO_SIZE        0x2B4000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
@@ -1806,6 +1806,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #ifdef CONFIG_I2C
 #define I2C_SURF 1
 #define I2C_FFA  (1 << 1)
@@ -1996,7 +2000,7 @@
 	msm8930_init_hsic();
 	msm8930_init_cam();
 	msm8930_init_mmc();
-	acpuclk_init(&acpuclk_8960_soc_data);
+	acpuclk_init(&acpuclk_8930_soc_data);
 	register_i2c_devices();
 	msm8930_init_fb();
 	slim_register_board_info(msm_slim_devices,
@@ -2006,7 +2010,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	change_memory_power = &msm8930_change_memory_power;
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 9e97e3f..f84944b 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -131,7 +131,7 @@
 	{
 		.gpio = 5,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
@@ -262,8 +262,8 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 140451840,
-		.ib  = 561807360,
+		.ab  = 154275840,
+		.ib  = 617103360,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5e1ea0d..c5d47f4 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -403,10 +403,11 @@
 	325,
 };
 
+#define MAX_VOLTAGE_MV		4200
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 60000,
-	.max_voltage		= 4200,
+	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
 	.resume_voltage_delta	= 100,
 	.term_current		= 100,
@@ -431,6 +432,7 @@
 	.i_test			= 2500,
 	.v_failure		= 3000,
 	.calib_delay_ms		= 600000,
+	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index cadaa4d..dc43627 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -79,6 +79,8 @@
 #include <mach/ion.h>
 #include <mach/mdm2.h>
 
+#include <linux/fmem.h>
+
 #include "timer.h"
 #include "devices.h"
 #include "devices-msm8x60.h"
@@ -114,12 +116,21 @@
 		.io_open_drain_ena = 0x0,
 		.irq_summary       = -1,
 	},
+	[SX150X_LIQUID] = {
+		.gpio_base         = GPIO_LIQUID_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0c08,
+		.io_pulldn_ena     = 0x4060,
+		.io_open_drain_ena = 0x000c,
+		.io_polarity       = 0,
+		.irq_summary       = -1,
+	},
 };
 
 #endif
 
-#define MSM_PMEM_ADSP_SIZE         0x3800000
-#define MSM_PMEM_AUDIO_SIZE        0x28B000
+#define MSM_PMEM_ADSP_SIZE         0x4200000
+#define MSM_PMEM_AUDIO_SIZE        0x2B4000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
@@ -217,6 +228,9 @@
 };
 #endif
 
+struct fmem_platform_data fmem_pdata = {
+};
+
 #define DSP_RAM_BASE_8960 0x8da00000
 #define DSP_RAM_SIZE_8960 0x1800000
 static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -276,6 +290,10 @@
 #endif
 }
 
+static void __init reserve_fmem_memory(void)
+{
+}
+
 static int msm8960_paddr_to_memtype(unsigned int paddr)
 {
 	return MEMTYPE_EBI1;
@@ -326,6 +344,12 @@
 };
 #endif
 
+struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
 static void reserve_ion_memory(void)
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
@@ -338,6 +362,7 @@
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
+	reserve_fmem_memory();
 }
 
 static struct reserve_info msm8960_reserve_info __initdata = {
@@ -398,6 +423,7 @@
 static void __init msm8960_reserve(void)
 {
 	msm_reserve();
+	fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size);
 }
 
 static int msm8960_change_memory_power(u64 start, u64 size,
@@ -1614,6 +1640,7 @@
 #ifdef CONFIG_MSM_FAKE_BATTERY
 	&fish_battery_device,
 #endif
+	&fmem_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	&android_pmem_device,
@@ -1895,6 +1922,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #ifdef CONFIG_I2C
 #define I2C_SURF 1
 #define I2C_FFA  (1 << 1)
@@ -1986,6 +2017,13 @@
 };
 #endif /* CONFIG_ISL9519_CHARGER */
 
+static struct i2c_board_info liquid_io_expander_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x20),
+		.platform_data = &msm8960_sx150x_data[SX150X_LIQUID]
+	},
+};
+
 static struct i2c_registry msm8960_i2c_devices[] __initdata = {
 #ifdef CONFIG_MSM_CAMERA
 	{
@@ -2027,6 +2065,12 @@
 		msm_isa1200_board_info,
 		ARRAY_SIZE(msm_isa1200_board_info),
 	},
+	{
+		I2C_LIQUID,
+		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+		liquid_io_expander_i2c_info,
+		ARRAY_SIZE(liquid_io_expander_i2c_info),
+	},
 };
 #endif /* CONFIG_I2C */
 
@@ -2099,7 +2143,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
 static void __init msm8960_rumi3_init(void)
@@ -2130,7 +2174,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
 static void __init msm8960_cdp_init(void)
@@ -2205,8 +2249,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	change_memory_power = &msm8960_change_memory_power;
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
-
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
 }
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 56fa3ca..e22868f 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -57,12 +57,13 @@
 	GPIO_CAM_GP_XMT_FLASH_INT,
 	GPIO_CAM_GP_LED_EN1,
 	GPIO_CAM_GP_LED_EN2,
-
+	GPIO_LIQUID_EXPANDER_BASE = GPIO_CAM_EXPANDER_BASE + 8,
 };
 #endif
 
 enum {
 	SX150X_CAM,
+	SX150X_LIQUID,
 };
 
 #endif
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index c4b7c5a..7cf4a8c 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -75,6 +75,7 @@
 };
 VREG_CONSUMERS(S3) = {
 	REGULATOR_SUPPLY("8018_s3",		NULL),
+	REGULATOR_SUPPLY("wlan_vreg",		"wlan_ar6000_pm_dev"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8018_s4",		NULL),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index be0e4e6..f5bd44d 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/msm_ssbi.h>
+#include <linux/memblock.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/mmc.h>
@@ -35,6 +36,7 @@
 #include "pm.h"
 #include "acpuclock.h"
 #include <linux/power/ltc4088-charger.h>
+#include "pm-boot.h"
 
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -627,6 +629,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_APCS_GLB_BASE +  0x24,
+};
+
 static int __init gpiomux_init(void)
 {
 	int rc;
@@ -736,9 +743,9 @@
 		.src_pipe_index = 11,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
 		.dst_pipe_index = 0,
-		.data_fifo_base_offset = 0xf00,
-		.data_fifo_size = 0x400,
-		.desc_fifo_base_offset = 0x1300,
+		.data_fifo_base_offset = 0x1100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
 	[0][PEER_PERIPHERAL_TO_USB] = {
@@ -747,8 +754,8 @@
 		.dst_phy_addr = USB_BAM_PHY_BASE,
 		.dst_pipe_index = 10,
 		.data_fifo_base_offset = 0xa00,
-		.data_fifo_size = 0x400,
-		.desc_fifo_base_offset = 0xe00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
 };
@@ -850,6 +857,11 @@
 					&msm9615_i2c_qup_gsbi5_pdata;
 }
 
+static void __init msm9615_reserve(void)
+{
+	msm_pm_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
+}
+
 static void __init msm9615_common_init(void)
 {
 	msm9615_device_init();
@@ -880,6 +892,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 						msm_pm_data);
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
 static void __init msm9615_cdp_init(void)
@@ -897,6 +910,7 @@
 	.init_irq = msm9615_init_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_cdp_init,
+	.reserve = msm9615_reserve,
 MACHINE_END
 
 MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
@@ -904,4 +918,5 @@
 	.init_irq = msm9615_init_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_mtp_init,
+	.reserve = msm9615_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 333d366..550e288 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -51,7 +51,14 @@
 #define PMIC_GPIO_SD_DET	165
 
 #define GPIO_EPHY_RST_N		37
-
+#define GPIO_MAC_TXD_3      119
+#define GPIO_MAC_TXD_2      120
+#define GPIO_MAC_TXD_1      121
+#define GPIO_MAC_TXD_0      122
+#define GPIO_MAC_TX_EN      123
+#define GPIO_MAC_MDIO       127
+#define GPIO_MAC_MDC        128
+#define GPIO_MAC_TX_CLK     133
 #define GPIO_GRFC_FTR0_0	136 /* GRFC 20 */
 #define GPIO_GRFC_FTR0_1	137 /* GRFC 21 */
 #define GPIO_GRFC_FTR1_0	145 /* GRFC 22 */
@@ -472,7 +479,23 @@
 
 static struct msm_gpio phy_config_data[] = {
 	{ GPIO_CFG(GPIO_EPHY_RST_N, 0, GPIO_CFG_OUTPUT,
-		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "MAC_RST_N" },
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_RST_N" },
+	{ GPIO_CFG(GPIO_MAC_TXD_3, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_3"},
+	{ GPIO_CFG(GPIO_MAC_TXD_2, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_2"},
+	{ GPIO_CFG(GPIO_MAC_TXD_1, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_1"},
+	{ GPIO_CFG(GPIO_MAC_TXD_0, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_0"},
+	{ GPIO_CFG(GPIO_MAC_TX_EN, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TX_EN"},
+	{ GPIO_CFG(GPIO_MAC_TX_CLK, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_10MA), "MAC_TX_CLK"},
+	{ GPIO_CFG(GPIO_MAC_MDIO, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "MDIO_MAC_MDIO"},
+	{ GPIO_CFG(GPIO_MAC_MDC, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "MDC_MAC_MDC"},
 };
 
 static int __init phy_init(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
new file mode 100644
index 0000000..c3657b5
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -0,0 +1,391 @@
+/* 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.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "board-msm7627a.h"
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+
+static unsigned long vreg_sts, gpio_sts;
+
+struct sdcc_gpio {
+	struct msm_gpio *cfg_data;
+	uint32_t size;
+	struct msm_gpio *sleep_cfg_data;
+};
+
+/**
+ * Due to insufficient drive strengths for SDC GPIO lines some old versioned
+ * SD/MMC cards may cause data CRC errors. Hence, set optimal values
+ * for SDC slots based on timing closure and marginality. SDC1 slot
+ * require higher value since it should handle bad signal quality due
+ * to size of T-flash adapters.
+ */
+static struct msm_gpio sdc1_cfg_data[] = {
+	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_3"},
+	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_2"},
+	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_1"},
+	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_0"},
+	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_cmd"},
+	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_14MA),
+								"sdc1_clk"},
+};
+
+static struct msm_gpio sdc2_cfg_data[] = {
+	{GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc2_clk"},
+	{GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_cmd"},
+	{GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_3"},
+	{GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_2"},
+	{GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_1"},
+	{GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_0"},
+};
+
+static struct msm_gpio sdc2_sleep_cfg_data[] = {
+	{GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_clk"},
+	{GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_cmd"},
+	{GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_dat_3"},
+	{GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_dat_2"},
+	{GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_dat_1"},
+	{GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+								"sdc2_dat_0"},
+};
+static struct msm_gpio sdc3_cfg_data[] = {
+	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc3_clk"},
+	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_cmd"},
+	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_3"},
+	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_2"},
+	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_1"},
+	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_0"},
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	{GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_7"},
+	{GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_6"},
+	{GPIO_CFG(21, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_5"},
+	{GPIO_CFG(108, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_4"},
+#endif
+};
+
+static struct msm_gpio sdc4_cfg_data[] = {
+	{GPIO_CFG(19, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_3"},
+	{GPIO_CFG(20, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_2"},
+	{GPIO_CFG(21, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_1"},
+	{GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_cmd"},
+	{GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_0"},
+	{GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc4_clk"},
+};
+
+static struct sdcc_gpio sdcc_cfg_data[] = {
+	{
+		.cfg_data = sdc1_cfg_data,
+		.size = ARRAY_SIZE(sdc1_cfg_data),
+	},
+	{
+		.cfg_data = sdc2_cfg_data,
+		.size = ARRAY_SIZE(sdc2_cfg_data),
+		.sleep_cfg_data = sdc2_sleep_cfg_data,
+	},
+	{
+		.cfg_data = sdc3_cfg_data,
+		.size = ARRAY_SIZE(sdc3_cfg_data),
+	},
+	{
+		.cfg_data = sdc4_cfg_data,
+		.size = ARRAY_SIZE(sdc4_cfg_data),
+	},
+};
+
+static int gpio_sdc1_hw_det = 85;
+static void gpio_sdc1_config(void)
+{
+	if (machine_is_msm7627a_qrd1())
+		gpio_sdc1_hw_det = 42;
+}
+
+static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
+static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct sdcc_gpio *curr;
+
+	curr = &sdcc_cfg_data[dev_id - 1];
+	if (!(test_bit(dev_id, &gpio_sts)^enable))
+		return rc;
+
+	if (enable) {
+		set_bit(dev_id, &gpio_sts);
+		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
+		if (rc)
+			pr_err("%s: Failed to turn on GPIOs for slot %d\n",
+					__func__,  dev_id);
+	} else {
+		clear_bit(dev_id, &gpio_sts);
+		if (curr->sleep_cfg_data) {
+			rc = msm_gpios_enable(curr->sleep_cfg_data, curr->size);
+			msm_gpios_free(curr->sleep_cfg_data, curr->size);
+			return rc;
+		}
+		msm_gpios_disable_free(curr->cfg_data, curr->size);
+	}
+	return rc;
+}
+
+static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct regulator *curr = sdcc_vreg_data[dev_id - 1];
+
+	if (test_bit(dev_id, &vreg_sts) == enable)
+		return 0;
+
+	if (!curr)
+		return -ENODEV;
+
+	if (IS_ERR(curr))
+		return PTR_ERR(curr);
+
+	if (enable) {
+		set_bit(dev_id, &vreg_sts);
+
+		rc = regulator_enable(curr);
+		if (rc)
+			pr_err("%s: could not enable regulator: %d\n",
+						__func__, rc);
+	} else {
+		clear_bit(dev_id, &vreg_sts);
+
+		rc = regulator_disable(curr);
+		if (rc)
+			pr_err("%s: could not disable regulator: %d\n",
+						__func__, rc);
+	}
+	return rc;
+}
+
+static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+
+	rc = msm_sdcc_setup_gpio(pdev->id, !!vdd);
+	if (rc)
+		goto out;
+
+	rc = msm_sdcc_setup_vreg(pdev->id, !!vdd);
+out:
+	return rc;
+}
+
+#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
+	&& defined(CONFIG_MMC_MSM_CARD_HW_DETECTION)
+static unsigned int msm7627a_sdcc_slot_status(struct device *dev)
+{
+	int status;
+
+	status = gpio_tlmm_config(GPIO_CFG(gpio_sdc1_hw_det, 2, GPIO_CFG_INPUT,
+				GPIO_CFG_PULL_UP, GPIO_CFG_8MA),
+				GPIO_CFG_ENABLE);
+	if (status)
+		pr_err("%s:Failed to configure tlmm for GPIO %d\n", __func__,
+				gpio_sdc1_hw_det);
+
+	status = gpio_request(gpio_sdc1_hw_det, "SD_HW_Detect");
+	if (status) {
+		pr_err("%s:Failed to request GPIO %d\n", __func__,
+				gpio_sdc1_hw_det);
+	} else {
+		status = gpio_direction_input(gpio_sdc1_hw_det);
+		if (!status) {
+			if (machine_is_msm7627a_qrd1())
+				status = !gpio_get_value(gpio_sdc1_hw_det);
+			else
+				status = gpio_get_value(gpio_sdc1_hw_det);
+		}
+		gpio_free(gpio_sdc1_hw_det);
+	}
+	return status;
+}
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data sdc1_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status      = msm7627a_sdcc_slot_status,
+	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data sdc2_plat_data = {
+	/*
+	 * SDC2 supports only 1.8V, claim for 2.85V range is just
+	 * for allowing buggy cards who advertise 2.8V even though
+	 * they can operate at 1.8V supply.
+	 */
+	.ocr_mask       = MMC_VDD_28_29 | MMC_VDD_165_195,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
+#endif
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+#ifdef CONFIG_MMC_MSM_SDC2_DUMMY52_REQUIRED
+	.dummy52_required = 1,
+#endif
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data sdc3_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+	.nonremovable   = 1,
+};
+#endif
+
+#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
+		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
+static struct mmc_platform_data sdc4_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+};
+#endif
+
+static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
+{
+	int rc;
+
+	BUG_ON(sdcc_no < 1 || sdcc_no > 4);
+
+	sdcc_no--;
+
+	sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
+
+	if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
+		rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
+		pr_err("%s: could not get regulator \"%s\": %d\n",
+				__func__, supply, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
+
+	if (rc) {
+		pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
+				__func__, supply, uV, rc);
+		goto reg_free;
+	}
+
+	return rc;
+
+reg_free:
+	regulator_put(sdcc_vreg_data[sdcc_no]);
+out:
+	sdcc_vreg_data[sdcc_no] = NULL;
+	return rc;
+}
+
+void __init msm7627a_init_mmc(void)
+{
+	/* eMMC slot */
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	if (mmc_regulator_init(3, "emmc", 3000000))
+		return;
+	msm_add_sdcc(3, &sdc3_plat_data);
+#endif
+	/* Micro-SD slot */
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	gpio_sdc1_config();
+	if (mmc_regulator_init(1, "mmc", 2850000))
+		return;
+	sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+	msm_add_sdcc(1, &sdc1_plat_data);
+#endif
+	/* SDIO WLAN slot */
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	if (mmc_regulator_init(2, "mmc", 2850000))
+		return;
+	msm_add_sdcc(2, &sdc2_plat_data);
+#endif
+	/* Not Used */
+#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
+		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
+	if (mmc_regulator_init(4, "mmc", 2850000))
+		return;
+	msm_add_sdcc(4, &sdc4_plat_data);
+#endif
+}
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
new file mode 100644
index 0000000..6b22c71
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -0,0 +1,18 @@
+/* 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_BOARD_7627A__
+#define __ARCH_ARM_MACH_MSM_BOARD_7627A__
+
+void __init msm7627a_init_mmc(void);
+
+#endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 15705ec..d8efcfe 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1625,6 +1625,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static void
 msm_i2c_gpio_config(int iface, int config_type)
 {
@@ -1818,8 +1823,8 @@
 		msm_pm_set_platform_data(msm7x25_pm_data,
 					ARRAY_SIZE(msm7x25_pm_data));
 
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				ioremap(0, PAGE_SIZE)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+
 	msm7x27_wlan_init();
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index f369c6c..dcb12bb3 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -54,6 +54,7 @@
 #include <mach/rpc_server_handset.h>
 #include <mach/socinfo.h>
 #include "pm-boot.h"
+#include "board-msm7627a.h"
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
@@ -554,7 +555,7 @@
 };
 static struct bt_vreg_info bt_vregs[] = {
 	{"msme1", 2, 1800000, 1800000, 0, NULL},
-	{"bt", 21, 2900000, 3050000, 1, NULL}
+	{"bt", 21, 2900000, 3300000, 1, NULL}
 };
 
 static int bahama_bt(int on)
@@ -1323,362 +1324,6 @@
 	.resource       = smc91x_resources,
 };
 
-#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
-
-static unsigned long vreg_sts, gpio_sts;
-
-struct sdcc_gpio {
-	struct msm_gpio *cfg_data;
-	uint32_t size;
-	struct msm_gpio *sleep_cfg_data;
-};
-
-/**
- * Due to insufficient drive strengths for SDC GPIO lines some old versioned
- * SD/MMC cards may cause data CRC errors. Hence, set optimal values
- * for SDC slots based on timing closure and marginality. SDC1 slot
- * require higher value since it should handle bad signal quality due
- * to size of T-flash adapters.
- */
-static struct msm_gpio sdc1_cfg_data[] = {
-	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_3"},
-	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_2"},
-	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_1"},
-	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_0"},
-	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_cmd"},
-	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_14MA),
-								"sdc1_clk"},
-};
-
-static struct msm_gpio sdc2_cfg_data[] = {
-	{GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc2_clk"},
-	{GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_cmd"},
-	{GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_3"},
-	{GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_2"},
-	{GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_1"},
-	{GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_0"},
-};
-
-static struct msm_gpio sdc2_sleep_cfg_data[] = {
-	{GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-								"sdc2_clk"},
-	{GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-								"sdc2_cmd"},
-	{GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-								"sdc2_dat_3"},
-	{GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-								"sdc2_dat_2"},
-	{GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-								"sdc2_dat_1"},
-	{GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-								"sdc2_dat_0"},
-};
-static struct msm_gpio sdc3_cfg_data[] = {
-	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc3_clk"},
-	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_cmd"},
-	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_3"},
-	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_2"},
-	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_1"},
-	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_0"},
-#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
-	{GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_7"},
-	{GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_6"},
-	{GPIO_CFG(21, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_5"},
-	{GPIO_CFG(108, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_4"},
-#endif
-};
-
-static struct msm_gpio sdc4_cfg_data[] = {
-	{GPIO_CFG(19, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_3"},
-	{GPIO_CFG(20, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_2"},
-	{GPIO_CFG(21, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_1"},
-	{GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_cmd"},
-	{GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_0"},
-	{GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc4_clk"},
-};
-
-static struct sdcc_gpio sdcc_cfg_data[] = {
-	{
-		.cfg_data = sdc1_cfg_data,
-		.size = ARRAY_SIZE(sdc1_cfg_data),
-	},
-	{
-		.cfg_data = sdc2_cfg_data,
-		.size = ARRAY_SIZE(sdc2_cfg_data),
-		.sleep_cfg_data = sdc2_sleep_cfg_data,
-	},
-	{
-		.cfg_data = sdc3_cfg_data,
-		.size = ARRAY_SIZE(sdc3_cfg_data),
-	},
-	{
-		.cfg_data = sdc4_cfg_data,
-		.size = ARRAY_SIZE(sdc4_cfg_data),
-	},
-};
-
-static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
-
-static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
-{
-	int rc = 0;
-	struct sdcc_gpio *curr;
-
-	curr = &sdcc_cfg_data[dev_id - 1];
-	if (!(test_bit(dev_id, &gpio_sts)^enable))
-		return rc;
-
-	if (enable) {
-		set_bit(dev_id, &gpio_sts);
-		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
-		if (rc)
-			pr_err("%s: Failed to turn on GPIOs for slot %d\n",
-					__func__,  dev_id);
-	} else {
-		clear_bit(dev_id, &gpio_sts);
-		if (curr->sleep_cfg_data) {
-			rc = msm_gpios_enable(curr->sleep_cfg_data, curr->size);
-			msm_gpios_free(curr->sleep_cfg_data, curr->size);
-			return rc;
-		}
-		msm_gpios_disable_free(curr->cfg_data, curr->size);
-	}
-	return rc;
-}
-
-static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
-{
-	int rc = 0;
-	struct regulator *curr = sdcc_vreg_data[dev_id - 1];
-
-	if (test_bit(dev_id, &vreg_sts) == enable)
-		return 0;
-
-	if (!curr)
-		return -ENODEV;
-
-	if (IS_ERR(curr))
-		return PTR_ERR(curr);
-
-	if (enable) {
-		set_bit(dev_id, &vreg_sts);
-
-		rc = regulator_enable(curr);
-		if (rc)
-			pr_err("%s: could not enable regulator: %d\n",
-					__func__, rc);
-	} else {
-		clear_bit(dev_id, &vreg_sts);
-
-		rc = regulator_disable(curr);
-		if (rc)
-			pr_err("%s: could not disable regulator: %d\n",
-					__func__, rc);
-	}
-	return rc;
-}
-
-static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
-{
-	int rc = 0;
-	struct platform_device *pdev;
-
-	pdev = container_of(dv, struct platform_device, dev);
-
-	rc = msm_sdcc_setup_gpio(pdev->id, !!vdd);
-	if (rc)
-		goto out;
-
-	rc = msm_sdcc_setup_vreg(pdev->id, !!vdd);
-out:
-	return rc;
-}
-
-#define GPIO_SDC1_HW_DET 85
-
-#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
-	&& defined(CONFIG_MMC_MSM_CARD_HW_DETECTION)
-static unsigned int msm7x2xa_sdcc_slot_status(struct device *dev)
-{
-	int status;
-
-	status = gpio_tlmm_config(GPIO_CFG(GPIO_SDC1_HW_DET, 2, GPIO_CFG_INPUT,
-			GPIO_CFG_PULL_UP, GPIO_CFG_8MA), GPIO_CFG_ENABLE);
-	if (status)
-		pr_err("%s:Failed to configure tlmm for GPIO %d\n", __func__,
-				GPIO_SDC1_HW_DET);
-
-	status = gpio_request(GPIO_SDC1_HW_DET, "SD_HW_Detect");
-	if (status) {
-		pr_err("%s:Failed to request GPIO %d\n", __func__,
-				GPIO_SDC1_HW_DET);
-	} else {
-		status = gpio_direction_input(GPIO_SDC1_HW_DET);
-		if (!status)
-			status = gpio_get_value(GPIO_SDC1_HW_DET);
-		gpio_free(GPIO_SDC1_HW_DET);
-	}
-	return status;
-}
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static struct mmc_platform_data sdc1_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
-	.status      = msm7x2xa_sdcc_slot_status,
-	.status_irq  = MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
-	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-#endif
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static struct mmc_platform_data sdc2_plat_data = {
-	/*
-	 * SDC2 supports only 1.8V, claim for 2.85V range is just
-	 * for allowing buggy cards who advertise 2.8V even though
-	 * they can operate at 1.8V supply.
-	 */
-	.ocr_mask	= MMC_VDD_28_29 | MMC_VDD_165_195,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
-	.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
-#endif
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-static struct mmc_platform_data sdc3_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
-	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
-#else
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-#endif
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-	.nonremovable	= 1,
-};
-#endif
-
-#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
-		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-static struct mmc_platform_data sdc4_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-};
-#endif
-
-static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
-{
-	int rc;
-
-	BUG_ON(sdcc_no < 1 || sdcc_no > 4);
-
-	sdcc_no--;
-
-	sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
-
-	if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
-		rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
-		pr_err("%s: could not get regulator \"%s\": %d\n",
-				__func__, supply, rc);
-		goto out;
-	}
-
-	rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
-
-	if (rc) {
-		pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
-				__func__, supply, uV, rc);
-		goto reg_free;
-	}
-
-	return rc;
-
-reg_free:
-	regulator_put(sdcc_vreg_data[sdcc_no]);
-out:
-	sdcc_vreg_data[sdcc_no] = NULL;
-	return rc;
-}
-
-static void __init msm7x27a_init_mmc(void)
-{
-	/* eMMC slot */
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-	if (mmc_regulator_init(3, "emmc", 3000000))
-		return;
-	msm_add_sdcc(3, &sdc3_plat_data);
-#endif
-	/* Micro-SD slot */
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-	if (mmc_regulator_init(1, "mmc", 2850000))
-		return;
-	msm_add_sdcc(1, &sdc1_plat_data);
-#endif
-	/* SDIO WLAN slot */
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-	if (mmc_regulator_init(2, "mmc", 2850000))
-		return;
-	msm_add_sdcc(2, &sdc2_plat_data);
-#endif
-	/* Not Used */
-#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
-		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-	if (mmc_regulator_init(4, "mmc", 2850000))
-		return;
-	msm_add_sdcc(4, &sdc4_plat_data);
-#endif
-}
-#endif
-
 #ifdef CONFIG_SERIAL_MSM_HS
 static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
 	.inject_rx_on_wakeup	= 1,
@@ -1720,6 +1365,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -3294,7 +2944,7 @@
 	/* Ensure ar6000pm device is registered before MMC/SDC */
 	msm7x27a_init_ar6000pm();
 #ifdef CONFIG_MMC_MSM
-	msm7x27a_init_mmc();
+	msm7627a_init_mmc();
 #endif
 	msm_fb_add_devices();
 #ifdef CONFIG_USB_EHCI_MSM_72K
@@ -3303,8 +2953,7 @@
 
 	msm_pm_set_platform_data(msm7x27a_pm_data,
 				ARRAY_SIZE(msm7x27a_pm_data));
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				ioremap(0, PAGE_SIZE)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 #if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
 	register_i2c_devices();
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 9ba92ed..857c88a 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -2948,6 +2948,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct resource qsd_spi_resources[] = {
 	{
 		.name   = "spi_irq_in",
@@ -6710,8 +6715,7 @@
 	hdmi_init_regs();
 	msm_fb_add_devices();
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				(uint32_t *)PAGE_OFFSET));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_device_i2c_init();
 	msm_device_i2c_2_init();
 	qup_device_i2c_init();
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 765f49e..75c1b80 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -915,6 +915,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
 
 #define ISP1763_INT_GPIO		117
@@ -5082,6 +5086,7 @@
 static struct platform_device *surf_devices[] __initdata = {
 	&msm_device_smd,
 	&msm_device_uart_dm12,
+	&msm_pil_q6v3,
 #ifdef CONFIG_I2C_QUP
 	&msm_gsbi3_qup_i2c_device,
 	&msm_gsbi4_qup_i2c_device,
@@ -6633,6 +6638,10 @@
 	PM8901_VREG_INIT_VS(HDMI_MVS),
 };
 
+static struct pm8xxx_misc_platform_data pm8901_misc_pdata = {
+	.priority		= 1,
+};
+
 static struct pm8xxx_irq_platform_data pm8901_irq_pdata = {
 	.irq_base		= PM8901_IRQ_BASE,
 	.devirq			= MSM_GPIO_TO_INT(PM8901_GPIO_INT),
@@ -6648,6 +6657,7 @@
 	.mpp_pdata		= &pm8901_mpp_pdata,
 	.regulator_pdatas	= pm8901_vreg_init,
 	.num_regulators		= ARRAY_SIZE(pm8901_vreg_init),
+	.misc_pdata		= &pm8901_misc_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8x60_ssbi_pm8901_pdata __devinitdata = {
@@ -10169,7 +10179,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_SCSS_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	pm8058_gpios_init();
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 537251a..889ac00 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -52,6 +52,7 @@
 #include "timer.h"
 #include "pm-boot.h"
 #include "board-msm7x27a-regulator.h"
+#include "board-msm7627a.h"
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
@@ -1270,301 +1271,6 @@
 	.is_phy_status_timer_on = 1,
 };
 
-#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
-
-static unsigned long vreg_sts, gpio_sts;
-
-struct sdcc_gpio {
-	struct msm_gpio *cfg_data;
-	uint32_t size;
-	struct msm_gpio *sleep_cfg_data;
-};
-
-/**
- * Due to insufficient drive strengths for SDC GPIO lines some old versioned
- * SD/MMC cards may cause data CRC errors. Hence, set optimal values
- * for SDC slots based on timing closure and marginality. SDC1 slot
- * require higher value since it should handle bad signal quality due
- * to size of T-flash adapters.
- */
-static struct msm_gpio sdc1_cfg_data[] = {
-	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_3"},
-	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_2"},
-	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_1"},
-	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_dat_0"},
-	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
-								"sdc1_cmd"},
-	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_14MA),
-								"sdc1_clk"},
-};
-
-static struct msm_gpio sdc2_cfg_data[] = {
-	{GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc2_clk"},
-	{GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_cmd"},
-	{GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_3"},
-	{GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_2"},
-	{GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_1"},
-	{GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc2_dat_0"},
-};
-
-static struct msm_gpio sdc2_sleep_cfg_data[] = {
-	{GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_clk"},
-	{GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_cmd"},
-	{GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_dat_3"},
-	{GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_dat_2"},
-	{GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_dat_1"},
-	{GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-								"sdc2_dat_0"},
-};
-static struct msm_gpio sdc3_cfg_data[] = {
-	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc3_clk"},
-	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_cmd"},
-	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_3"},
-	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_2"},
-	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_1"},
-	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_0"},
-#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
-	{GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_7"},
-	{GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_6"},
-	{GPIO_CFG(21, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_5"},
-	{GPIO_CFG(108, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc3_dat_4"},
-#endif
-};
-
-static struct msm_gpio sdc4_cfg_data[] = {
-	{GPIO_CFG(19, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_3"},
-	{GPIO_CFG(20, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_2"},
-	{GPIO_CFG(21, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_1"},
-	{GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_cmd"},
-	{GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
-								"sdc4_dat_0"},
-	{GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
-								"sdc4_clk"},
-};
-
-static struct sdcc_gpio sdcc_cfg_data[] = {
-	{
-		.cfg_data = sdc1_cfg_data,
-		.size = ARRAY_SIZE(sdc1_cfg_data),
-	},
-	{
-		.cfg_data = sdc2_cfg_data,
-		.size = ARRAY_SIZE(sdc2_cfg_data),
-		.sleep_cfg_data = sdc2_sleep_cfg_data,
-	},
-	{
-		.cfg_data = sdc3_cfg_data,
-		.size = ARRAY_SIZE(sdc3_cfg_data),
-	},
-	{
-		.cfg_data = sdc4_cfg_data,
-		.size = ARRAY_SIZE(sdc4_cfg_data),
-	},
-};
-
-static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
-static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
-{
-	int rc = 0;
-	struct sdcc_gpio *curr;
-
-	curr = &sdcc_cfg_data[dev_id - 1];
-	if (!(test_bit(dev_id, &gpio_sts)^enable))
-		return rc;
-
-	if (enable) {
-		set_bit(dev_id, &gpio_sts);
-		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
-		if (rc)
-			pr_err("%s: Failed to turn on GPIOs for slot %d\n",
-					__func__,  dev_id);
-	} else {
-		clear_bit(dev_id, &gpio_sts);
-		if (curr->sleep_cfg_data) {
-			rc = msm_gpios_enable(curr->sleep_cfg_data, curr->size);
-			msm_gpios_free(curr->sleep_cfg_data, curr->size);
-			return rc;
-		}
-		msm_gpios_disable_free(curr->cfg_data, curr->size);
-	}
-	return rc;
-}
-
-static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
-{
-	int rc = 0;
-	struct regulator *curr = sdcc_vreg_data[dev_id - 1];
-
-	if (test_bit(dev_id, &vreg_sts) == enable)
-		return 0;
-
-	if (!curr)
-		return -ENODEV;
-
-	if (IS_ERR(curr))
-		return PTR_ERR(curr);
-
-	if (enable) {
-		set_bit(dev_id, &vreg_sts);
-
-		rc = regulator_enable(curr);
-		if (rc)
-			pr_err("%s: could not enable regulator: %d\n",
-						__func__, rc);
-	} else {
-		clear_bit(dev_id, &vreg_sts);
-
-		rc = regulator_disable(curr);
-		if (rc)
-			pr_err("%s: could not disable regulator: %d\n",
-						__func__, rc);
-	}
-	return rc;
-}
-
-static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
-{
-	int rc = 0;
-	struct platform_device *pdev;
-
-	pdev = container_of(dv, struct platform_device, dev);
-
-	rc = msm_sdcc_setup_gpio(pdev->id, !!vdd);
-	if (rc)
-		goto out;
-
-	rc = msm_sdcc_setup_vreg(pdev->id, !!vdd);
-out:
-	return rc;
-}
-
-#define GPIO_SDC1_HW_DET 42
-
-#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
-	&& defined(CONFIG_MMC_MSM_CARD_HW_DETECTION)
-static unsigned int msm7627a_sdcc_slot_status(struct device *dev)
-{
-	int status;
-
-	status = gpio_tlmm_config(GPIO_CFG(GPIO_SDC1_HW_DET, 2, GPIO_CFG_INPUT,
-			GPIO_CFG_PULL_UP, GPIO_CFG_8MA), GPIO_CFG_ENABLE);
-	if (status)
-		pr_err("%s:Failed to configure tlmm for GPIO %d\n", __func__,
-				GPIO_SDC1_HW_DET);
-
-	status = gpio_request(GPIO_SDC1_HW_DET, "SD_HW_Detect");
-	if (status) {
-		pr_err("%s:Failed to request GPIO %d\n", __func__,
-				GPIO_SDC1_HW_DET);
-	} else {
-		status = gpio_direction_input(GPIO_SDC1_HW_DET);
-		if (!status)
-			status = !gpio_get_value(GPIO_SDC1_HW_DET);
-		gpio_free(GPIO_SDC1_HW_DET);
-	}
-	return status;
-}
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static struct mmc_platform_data sdc1_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
-	.status      = msm7627a_sdcc_slot_status,
-	.status_irq  = MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
-	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-#endif
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static struct mmc_platform_data sdc2_plat_data = {
-	/*
-	 * SDC2 supports only 1.8V, claim for 2.85V range is just
-	 * for allowing buggy cards who advertise 2.8V even though
-	 * they can operate at 1.8V supply.
-	 */
-	.ocr_mask	= MMC_VDD_28_29 | MMC_VDD_165_195,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
-	.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
-#endif
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-#ifdef CONFIG_MMC_MSM_SDC2_DUMMY52_REQUIRED
-	.dummy52_required = 1,
-#endif
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-static struct mmc_platform_data sdc3_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
-	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
-#else
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-#endif
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-	.nonremovable	= 1,
-};
-#endif
-
-#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
-		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-static struct mmc_platform_data sdc4_plat_data = {
-	.ocr_mask	= MMC_VDD_28_29,
-	.translate_vdd  = msm_sdcc_setup_power,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.msmsdcc_fmin	= 144000,
-	.msmsdcc_fmid	= 24576000,
-	.msmsdcc_fmax	= 49152000,
-};
-#endif
-#endif
-
 #ifdef CONFIG_SERIAL_MSM_HS
 static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
 	.inject_rx_on_wakeup	= 1,
@@ -1606,6 +1312,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -1697,69 +1408,6 @@
 	}
 };
 
-static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
-{
-	int rc;
-
-	BUG_ON(sdcc_no < 1 || sdcc_no > 4);
-
-	sdcc_no--;
-
-	sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
-
-	if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
-		rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
-		pr_err("%s: could not get regulator \"%s\": %d\n",
-				__func__, supply, rc);
-		goto out;
-	}
-
-	rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
-
-	if (rc) {
-		pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
-				__func__, supply, uV, rc);
-		goto reg_free;
-	}
-
-	return rc;
-
-reg_free:
-	regulator_put(sdcc_vreg_data[sdcc_no]);
-out:
-	sdcc_vreg_data[sdcc_no] = NULL;
-	return rc;
-}
-
-static void __init msm7627a_init_mmc(void)
-{
-	/* eMMC slot */
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-	if (mmc_regulator_init(3, "emmc", 3000000))
-		return;
-	msm_add_sdcc(3, &sdc3_plat_data);
-#endif
-	/* Micro-SD slot */
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-	if (mmc_regulator_init(1, "mmc", 2850000))
-		return;
-	msm_add_sdcc(1, &sdc1_plat_data);
-#endif
-	/* SDIO WLAN slot */
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-	if (mmc_regulator_init(2, "mmc", 2850000))
-		return;
-	msm_add_sdcc(2, &sdc2_plat_data);
-#endif
-	/* Not Used */
-#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
-		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-	if (mmc_regulator_init(4, "mmc", 2850000))
-		return;
-	msm_add_sdcc(4, &sdc4_plat_data);
-#endif
-}
-
 #define SND(desc, num) { .name = #desc, .id = num }
 static struct snd_endpoint snd_endpoints_list[] = {
 	SND(HANDSET, 0),
@@ -2543,8 +2191,6 @@
 	msm7x2x_misc_init();
 	msm7627a_init_regulators();
 	msm_device_i2c_init();
-	msm7627a_init_mmc();
-
 	qrd1_camera_gpio_cfg();
 #ifdef CONFIG_SERIAL_MSM_HS
 	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
@@ -2560,13 +2206,14 @@
 		&msm_gadget_pdata;
 	platform_add_devices(qrd1_devices,
 			ARRAY_SIZE(qrd1_devices));
+	msm7627a_init_mmc();
+
 #ifdef CONFIG_USB_EHCI_MSM_72K
 	msm7627a_init_host();
 #endif
 	msm_pm_set_platform_data(msm7627a_pm_data,
 				ARRAY_SIZE(msm7627a_pm_data));
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				ioremap(0, PAGE_SIZE)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	msm_fb_add_devices();
 
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 0dcd0f4..10432a0 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2297,6 +2297,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (unsigned int *)PAGE_OFFSET,
+};
+
 static void
 msm_i2c_gpio_config(int iface, int config_type)
 {
@@ -2437,8 +2442,7 @@
 	spi_register_board_info(msm_spi_board_info,
 				ARRAY_SIZE(msm_spi_board_info));
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				(uint32_t *)PAGE_OFFSET));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 #ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
 	if (machine_is_qsd8x50_ffa())
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 841c899..ed5f265 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -41,6 +41,7 @@
 #define REG_GCC(off)	(MSM_APCS_GCC_BASE + (off))
 
 /* Peripheral clock registers. */
+#define ADM0_PBUS_CLK_CTL_REG			REG(0x2208)
 #define CE1_HCLK_CTL_REG			REG(0x2720)
 #define CE1_CORE_CLK_CTL_REG			REG(0x2724)
 #define CE3_HCLK_CTL_REG			REG(0x36C4)
@@ -109,6 +110,7 @@
 #define RINGOSC_NS_REG				REG(0x2DC0)
 #define RINGOSC_STATUS_REG			REG(0x2DCC)
 #define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
+#define RPM_MSG_RAM_HCLK_CTL_REG		REG(0x27E0)
 #define SC0_U_CLK_BRANCH_ENA_VOTE_REG		REG(0x3080)
 #define SDCn_APPS_CLK_MD_REG(n)			REG(0x2828+(0x20*((n)-1)))
 #define SDCn_APPS_CLK_NS_REG(n)			REG(0x282C+(0x20*((n)-1)))
@@ -631,14 +633,12 @@
 	},
 };
 
-static int soc_clk_reset(struct clk *clk, enum clk_reset_action action)
-{
-	return branch_reset(&to_rcg_clk(clk)->b, action);
-}
-
 static struct clk_ops clk_ops_rcg_8960 = {
 	.enable = rcg_clk_enable,
 	.disable = rcg_clk_disable,
+	.enable_hwcg = rcg_clk_enable_hwcg,
+	.disable_hwcg = rcg_clk_disable_hwcg,
+	.in_hwcg_mode = rcg_clk_in_hwcg_mode,
 	.auto_off = rcg_clk_disable,
 	.handoff = rcg_clk_handoff,
 	.set_rate = rcg_clk_set_rate,
@@ -646,7 +646,7 @@
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
-	.reset = soc_clk_reset,
+	.reset = rcg_clk_reset,
 	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
@@ -654,12 +654,16 @@
 static struct clk_ops clk_ops_branch = {
 	.enable = branch_clk_enable,
 	.disable = branch_clk_disable,
+	.enable_hwcg = branch_clk_enable_hwcg,
+	.disable_hwcg = branch_clk_disable_hwcg,
+	.in_hwcg_mode = branch_clk_in_hwcg_mode,
 	.auto_off = branch_clk_disable,
 	.is_enabled = branch_clk_is_enabled,
 	.reset = branch_clk_reset,
 	.is_local = local_clk_is_local,
 	.get_parent = branch_clk_get_parent,
 	.set_parent = branch_clk_set_parent,
+	.handoff = branch_clk_handoff,
 };
 
 static struct clk_ops clk_ops_reset = {
@@ -686,6 +690,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN_REG,
 		.en_mask = BIT(21),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(11),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(14),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -702,6 +708,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN_REG,
 		.en_mask = BIT(22),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(15),
 		.reset_reg = SW_RESET_CORE_REG,
 		.reset_mask = BIT(10),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -732,6 +740,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN4_REG,
 		.en_mask = BIT(23),
+		.hwcg_reg = MAXI_EN4_REG,
+		.hwcg_mask = BIT(22),
 		.halt_reg = DBG_BUS_VEC_I_REG,
 		.halt_bit = 25,
 	},
@@ -746,6 +756,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN4_REG,
 		.en_mask = BIT(25),
+		.hwcg_reg = MAXI_EN4_REG,
+		.hwcg_mask = BIT(24),
 		.halt_reg = DBG_BUS_VEC_I_REG,
 		.halt_bit = 26,
 	},
@@ -761,6 +773,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN_REG,
 		.en_mask = BIT(19),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(13),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(4)|BIT(5)|BIT(7),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -794,6 +808,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN_REG,
 		.en_mask = BIT(23),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(16),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(13),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -810,6 +826,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN2_REG,
 		.en_mask = BIT(24),
+		.hwcg_reg = MAXI_EN2_REG,
+		.hwcg_mask = BIT(25),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(6),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -826,6 +844,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN2_REG,
 		.en_mask = BIT(26),
+		.hwcg_reg = MAXI_EN2_REG,
+		.hwcg_mask = BIT(27),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(15),
 		.halt_reg = DBG_BUS_VEC_E_REG,
@@ -922,6 +942,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(18),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(20),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(5),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -954,6 +976,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(22),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(15),
 		.reset_reg = SW_RESET_AHB2_REG,
 		.reset_mask = BIT(0),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -970,6 +994,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(19),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(28),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(12),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -986,6 +1012,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(2),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(29),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(11),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1002,6 +1030,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(3),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(27),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(10),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1018,6 +1048,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(14),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(21),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(9),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1034,6 +1066,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(4),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(22),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(9),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1066,6 +1100,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(6),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(12),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(8),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1130,6 +1166,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(15),
+		.hwcg_reg = AHB_EN_REG,
+		.hwcg_mask = BIT(26),
 		.halt_reg = DBG_BUS_VEC_F_REG,
 		.halt_bit = 22,
 	},
@@ -1160,6 +1198,8 @@
 	.b = {
 		.ctl_reg = AHB_EN_REG,
 		.en_mask = BIT(11),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(26),
 		.reset_reg = SW_RESET_AHB_REG,
 		.reset_mask = BIT(1),
 		.halt_reg = DBG_BUS_VEC_F_REG,
@@ -1537,7 +1577,7 @@
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
-	.reset = soc_clk_reset,
+	.reset = rcg_clk_reset,
 	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
@@ -1707,6 +1747,8 @@
 	.b = {
 		.ctl_reg = PMEM_ACLK_CTL_REG,
 		.en_mask = BIT(4),
+		.hwcg_reg = PMEM_ACLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 20,
 	},
@@ -2133,6 +2175,8 @@
 	.b = {
 		.ctl_reg = CE1_CORE_CLK_CTL_REG,
 		.en_mask = BIT(4),
+		.hwcg_reg = CE1_CORE_CLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
 		.halt_bit = 27,
 	},
@@ -2257,6 +2301,8 @@
 	.b = {
 		.ctl_reg = DMA_BAM_HCLK_CTL,
 		.en_mask = BIT(4),
+		.hwcg_reg = DMA_BAM_HCLK_CTL,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 12,
 	},
@@ -2271,6 +2317,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(1),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(1),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
 		.halt_bit = 11,
 	},
@@ -2285,6 +2333,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(2),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(2),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
 		.halt_bit = 7,
 	},
@@ -2299,6 +2349,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(3),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(3),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
 		.halt_bit = 3,
 	},
@@ -2313,6 +2365,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(4),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(4),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 27,
 	},
@@ -2327,6 +2381,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(5),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(5),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 23,
 	},
@@ -2341,6 +2397,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(6),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(6),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 19,
 	},
@@ -2355,6 +2413,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(7),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(7),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 15,
 	},
@@ -2369,6 +2429,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(8),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(8),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 11,
 	},
@@ -2383,6 +2445,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(9),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(9),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 7,
 	},
@@ -2397,6 +2461,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(10),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(10),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
 		.halt_bit = 3,
 	},
@@ -2411,6 +2477,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(11),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(11),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
 		.halt_bit = 18,
 	},
@@ -2425,6 +2493,8 @@
 	.b = {
 		.ctl_reg = GSBIn_HCLK_CTL_REG(12),
 		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(12),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
 		.halt_bit = 14,
 	},
@@ -2470,6 +2540,8 @@
 	.b = {
 		.ctl_reg = TSIF_HCLK_CTL_REG,
 		.en_mask = BIT(4),
+		.hwcg_reg = TSIF_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
 		.halt_bit = 7,
 	},
@@ -2512,6 +2584,8 @@
 	.b = {
 		.ctl_reg = USB_HS1_HCLK_CTL_REG,
 		.en_mask = BIT(4),
+		.hwcg_reg = USB_HS1_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 1,
 	},
@@ -2568,6 +2642,8 @@
 	.b = {
 		.ctl_reg = SDCn_HCLK_CTL_REG(1),
 		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(1),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 11,
 	},
@@ -2582,6 +2658,8 @@
 	.b = {
 		.ctl_reg = SDCn_HCLK_CTL_REG(2),
 		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(2),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 10,
 	},
@@ -2596,6 +2674,8 @@
 	.b = {
 		.ctl_reg = SDCn_HCLK_CTL_REG(3),
 		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(3),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 9,
 	},
@@ -2610,6 +2690,8 @@
 	.b = {
 		.ctl_reg = SDCn_HCLK_CTL_REG(4),
 		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(4),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 8,
 	},
@@ -2624,6 +2706,8 @@
 	.b = {
 		.ctl_reg = SDCn_HCLK_CTL_REG(5),
 		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(5),
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_DFAB_STATE_REG,
 		.halt_bit = 7,
 	},
@@ -2654,6 +2738,8 @@
 	.b = {
 		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
 		.en_mask = BIT(3),
+		.hwcg_reg = ADM0_PBUS_CLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
 		.halt_check = HALT_VOTED,
 		.halt_bit = 13,
@@ -2714,6 +2800,8 @@
 	.b = {
 		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
 		.en_mask = BIT(6),
+		.hwcg_reg = RPM_MSG_RAM_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
 		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
 		.halt_check = HALT_VOTED,
 		.halt_bit = 12,
@@ -5074,22 +5162,24 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
 	CLK_LOOKUP("measure",		measure_clk.c,		"debug"),
 
-	CLK_DUMMY("afab_clk",		AFAB_CLK,	NULL, 0),
-	CLK_DUMMY("afab_a_clk",		AFAB_A_CLK,	NULL, 0),
-	CLK_DUMMY("cfpb_clk",		CFPB_CLK,	NULL, 0),
-	CLK_DUMMY("cfpb_a_clk",		CFPB_A_CLK,	NULL, 0),
+	CLK_DUMMY("bus_clk",		AFAB_CLK,	"msm_apps_fab", 0),
+	CLK_DUMMY("bus_a_clk",		AFAB_A_CLK,	"msm_apps_fab", 0),
+	CLK_DUMMY("bus_clk",		SFAB_CLK,	"msm_sys_fab", 0),
+	CLK_DUMMY("bus_a_clk",		SFAB_A_CLK,	"msm_sys_fab", 0),
+	CLK_DUMMY("bus_clk",		SFPB_CLK,	"msm_sys_fpb", 0),
+	CLK_DUMMY("bus_a_clk",		SFPB_A_CLK,	"msm_sys_fpb", 0),
+	CLK_DUMMY("bus_clk",		MMFAB_CLK,	"msm_mm_fab", 0),
+	CLK_DUMMY("bus_a_clk",		MMFAB_A_CLK,	"msm_mm_fab", 0),
+	CLK_DUMMY("bus_clk",		CFPB_CLK,	"msm_cpss_fpb", 0),
+	CLK_DUMMY("bus_a_clk",		CFPB_A_CLK,	"msm_cpss_fpb", 0),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c, "msm_bus"),
+	CLK_DUMMY("mem_a_clk",		EBI1_A_CLK,        "msm_bus", 0),
+
+	CLK_DUMMY("ebi1_clk",		EBI1_CLK,	NULL, 0),
 	CLK_DUMMY("dfab_clk",		DFAB_CLK,	NULL, 0),
 	CLK_DUMMY("dfab_a_clk",		DFAB_A_CLK,	NULL, 0),
-	CLK_DUMMY("ebi1_clk",		EBI1_CLK,	NULL, 0),
-	CLK_DUMMY("ebi1_a_clk",		EBI1_A_CLK,	NULL, 0),
-	CLK_DUMMY("mmfab_clk",		MMFAB_CLK,	NULL, 0),
-	CLK_DUMMY("mmfab_a_clk",	MMFAB_A_CLK,	NULL, 0),
-	CLK_DUMMY("mmfpb_clk",		MMFPB_CLK,	NULL, 0),
-	CLK_DUMMY("mmfpb_a_clk",	MMFPB_A_CLK,	NULL, 0),
-	CLK_DUMMY("sfab_clk",		SFAB_CLK,	NULL, 0),
-	CLK_DUMMY("sfab_a_clk",		SFAB_A_CLK,	NULL, 0),
-	CLK_DUMMY("sfpb_clk",		SFPB_CLK,	NULL, 0),
-	CLK_DUMMY("sfpb_a_clk",		SFPB_A_CLK,	NULL, 0),
+	CLK_DUMMY("bus_clk",		MMFPB_CLK,	NULL, 0),
+	CLK_DUMMY("bus_a_clk",		MMFPB_A_CLK,	NULL, 0),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		NULL),
@@ -5291,7 +5381,6 @@
 	CLK_LOOKUP("usb_hsic_system_clk", usb_hsic_system_clk.c,	NULL),
 	CLK_LOOKUP("usb_hsic_p_clk",	usb_hsic_p_clk.c,	NULL),
 
-	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     NULL),
@@ -5306,24 +5395,25 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
 	CLK_LOOKUP("measure",		measure_clk.c,		"debug"),
 
-	CLK_LOOKUP("afab_clk",		afab_clk.c,	NULL),
-	CLK_LOOKUP("afab_a_clk",	afab_a_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_clk",		cfpb_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,	"clock-8960"),
-	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
-	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_a_clk",	ebi1_a_clk.c,	NULL),
-	CLK_LOOKUP("mmfab_clk",		mmfab_clk.c,	NULL),
-	CLK_LOOKUP("mmfab_a_clk",	mmfab_a_clk.c,	NULL),
-	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,	NULL),
-	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	"clock-8960"),
-	CLK_LOOKUP("sfab_clk",		sfab_clk.c,	NULL),
-	CLK_LOOKUP("sfab_a_clk",	sfab_a_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_clk",		sfpb_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_a_clk",	sfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
+	CLK_LOOKUP("dfab_clk",		dfab_clk.c,		NULL),
+	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		NULL),
@@ -5536,7 +5626,6 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 
-	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     NULL),
@@ -5605,6 +5694,7 @@
 
 static void __init reg_init(void)
 {
+	void __iomem *imem_reg;
 	/* Deassert MM SW_RESET_ALL signal. */
 	writel_relaxed(0, SW_RESET_ALL_REG);
 
@@ -5613,12 +5703,21 @@
 	 * reserved bits on the other SoC. Writing to these reserved bits
 	 * should have no effect.
 	 */
-	/* Initialize MM AHB registers: Enable the FPB clock and disable HW
-	 * gating for all clocks. Also set VFE_AHB's FORCE_CORE_ON bit to
-	 * prevent its memory from being collapsed when the clock is halted.
-	 * The sleep and wake-up delays are set to safe values. */
-	rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
-	writel_relaxed(0x000007F9, AHB_EN2_REG);
+	/*
+	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
+	 * gating on 8960v1/8064 for all clocks. Also set VFE_AHB's
+	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+	 * the clock is halted. The sleep and wake-up delays are set to safe
+	 * values.
+	 */
+	if (cpu_is_msm8960() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) {
+		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
+		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+	} else {
+		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
+		writel_relaxed(0x000007F9, AHB_EN2_REG);
+	}
 	if (cpu_is_apq8064())
 		rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
 
@@ -5629,14 +5728,31 @@
 	/* Initialize MM AXI registers: Enable HW gating for all clocks that
 	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
 	 * delays to safe values. */
-	/* TODO: Enable HW Gating */
-	rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
-	rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+	if (cpu_is_msm8960() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+		rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
+		rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	} else {
+		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
+		rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	}
 	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
-	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
 	if (cpu_is_apq8064())
 		rmwreg(0x009FE4FF, MAXI_EN5_REG, 0x01FFEFFF);
-	rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
+	if (cpu_is_msm8960() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
+	else
+		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
+
+	/* Enable IMEM's clk_on signal */
+	imem_reg = ioremap(0x04b00040, 4);
+	if (imem_reg) {
+		writel_relaxed(0x3, imem_reg);
+		iounmap(imem_reg);
+	}
 
 	/* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
 	 * memories retain state even when not clocked. Also, set sleep and
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 454e9cf..45094d9 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -535,11 +535,6 @@
 	writel_relaxed(pll_mode, MM_PLL2_MODE_REG);
 }
 
-static int soc_clk_reset(struct clk *clk, enum clk_reset_action action)
-{
-	return branch_reset(&to_rcg_clk(clk)->b, action);
-}
-
 static struct clk_ops clk_ops_rcg_8x60 = {
 	.enable = rcg_clk_enable,
 	.disable = rcg_clk_disable,
@@ -550,7 +545,7 @@
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
-	.reset = soc_clk_reset,
+	.reset = rcg_clk_reset,
 	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
@@ -3576,28 +3571,29 @@
 
 static struct clk_lookup msm_clocks_8x60[] = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,	NULL),
-	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
-	CLK_LOOKUP("pll4",		pll4_clk.c,	"peripheral-reset"),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
-	CLK_LOOKUP("afab_clk",		afab_clk.c,	NULL),
-	CLK_LOOKUP("afab_a_clk",	afab_a_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_clk",		cfpb_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,	"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,	"msm_mm_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	"msm_cpss_fpb"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c, "msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,	"msm_bus"),
+	CLK_LOOKUP("smi_clk",		smi_clk.c,	"msm_bus"),
+	CLK_LOOKUP("smi_a_clk",		smi_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
 	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
 	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_a_clk",	ebi1_a_clk.c,	NULL),
-	CLK_LOOKUP("mmfab_clk",		mmfab_clk.c,	NULL),
-	CLK_LOOKUP("mmfab_a_clk",	mmfab_a_clk.c,	NULL),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,	NULL),
 	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("sfab_clk",		sfab_clk.c,	NULL),
-	CLK_LOOKUP("sfab_a_clk",	sfab_a_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_clk",		sfpb_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_a_clk",	sfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("smi_clk",		smi_clk.c,	NULL),
-	CLK_LOOKUP("smi_a_clk",		smi_a_clk.c,	NULL),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		NULL),
@@ -3793,7 +3789,6 @@
 	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
 
-	CLK_LOOKUP("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL),
 	CLK_LOOKUP("mem_clk",		ebi1_adm0_clk.c, "msm_dmov.0"),
 	CLK_LOOKUP("mem_clk",		ebi1_adm1_clk.c, "msm_dmov.1"),
 
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 553fb4d..8c5f027 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -414,11 +414,6 @@
 	},
 };
 
-static int soc_clk_reset(struct clk *clk, enum clk_reset_action action)
-{
-	return branch_reset(&to_rcg_clk(clk)->b, action);
-}
-
 static struct clk_ops clk_ops_rcg_9615 = {
 	.enable = rcg_clk_enable,
 	.disable = rcg_clk_disable,
@@ -428,7 +423,7 @@
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
-	.reset = soc_clk_reset,
+	.reset = rcg_clk_reset,
 	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
@@ -1631,16 +1626,18 @@
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
-	CLK_LOOKUP("cfpb_clk",		cfpb_clk.c,	NULL),
-	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	NULL),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	NULL),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
 	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
 	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_a_clk",	ebi1_a_clk.c,	NULL),
-	CLK_LOOKUP("sfab_clk",		sfab_clk.c,	NULL),
-	CLK_LOOKUP("sfab_a_clk",	sfab_a_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_clk",		sfpb_clk.c,	NULL),
-	CLK_LOOKUP("sfpb_a_clk",	sfpb_a_clk.c,	NULL),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,	NULL),
@@ -1703,7 +1700,6 @@
 	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c,	"msm_sdcc.2"),
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,		"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
-	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"),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 4990c81..411a272 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -54,12 +54,31 @@
 
 static int clock_debug_measure_get(void *data, u64 *val)
 {
-	int ret;
 	struct clk *clock = data;
+	int ret, is_hw_gated;
+
+	/* Check to see if the clock is in hardware gating mode */
+	if (clock->flags & CLKFLAG_HWCG)
+		is_hw_gated = clock->ops->in_hwcg_mode(clock);
+	else
+		is_hw_gated = 0;
 
 	ret = clk_set_parent(measure, clock);
-	if (!ret)
+	if (!ret) {
+		/*
+		 * Disable hw gating to get accurate rate measurements. Only do
+		 * this if the clock is explictly enabled by software. This
+		 * allows us to detect errors where clocks are on even though
+		 * software is not requesting them to be on due to broken
+		 * hardware gating signals.
+		 */
+		if (is_hw_gated && clock->count)
+			clock->ops->disable_hwcg(clock);
 		*val = clk_get_rate(measure);
+		/* Reenable hwgating if it was disabled */
+		if (is_hw_gated && clock->count)
+			clock->ops->enable_hwcg(clock);
+	}
 
 	return ret;
 }
@@ -109,6 +128,16 @@
 DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get,
 			NULL, "%llu\n");
 
+static int clock_debug_hwcg_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	*val = !!(clock->flags & CLKFLAG_HWCG);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get,
+			NULL, "%llu\n");
+
 static struct dentry *debugfs_base;
 static u32 debug_suspend;
 static struct clk_lookup *msm_clocks;
@@ -239,6 +268,10 @@
 				&clock_local_fops))
 		goto error;
 
+	if (!debugfs_create_file("has_hw_gating", S_IRUGO, clk_dir, clock,
+				&clock_hwcg_fops))
+		goto error;
+
 	if (measure &&
 	    !clk_set_parent(measure, clock) &&
 	    !debugfs_create_file("measure", S_IRUGO, clk_dir, clock,
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index f8d84be..2a1c013 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -273,6 +273,14 @@
 	return invert ? !status_bit : status_bit;
 }
 
+int branch_in_hwcg_mode(const struct branch *b)
+{
+	if (!b->hwcg_mask)
+		return 0;
+
+	return !!(readl_relaxed(b->hwcg_reg) & b->hwcg_mask);
+}
+
 void __branch_clk_enable_reg(const struct branch *clk, const char *name)
 {
 	u32 reg_val;
@@ -291,6 +299,10 @@
 	 */
 	mb();
 
+	/* Skip checking halt bit if the clock is in hardware gated mode */
+	if (branch_in_hwcg_mode(clk))
+		return;
+
 	/* Wait for clock to enable before returning. */
 	if (clk->halt_check == DELAY)
 		udelay(HALT_CHECK_DELAY_US);
@@ -362,6 +374,10 @@
 	 */
 	mb();
 
+	/* Skip checking halt bit if the clock is in hardware gated mode */
+	if (branch_in_hwcg_mode(clk))
+		return reg_val;
+
 	/* Wait for clock to disable before continuing. */
 	if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED
 				     || clk->halt_check == HALT_VOTED)
@@ -584,12 +600,32 @@
 	return to_rcg_clk(clk)->current_freq->src_clk;
 }
 
+/* Disable hw clock gating if not set at boot */
+static void branch_handoff(struct branch *clk, struct clk *c)
+{
+	if (!branch_in_hwcg_mode(clk)) {
+		clk->hwcg_mask = 0;
+		c->flags &= ~CLKFLAG_HWCG;
+	} else {
+		c->flags |= CLKFLAG_HWCG;
+	}
+}
+
+int branch_clk_handoff(struct clk *c)
+{
+	struct branch_clk *clk = to_branch_clk(c);
+	branch_handoff(&clk->b, &clk->c);
+	return 0;
+}
+
 int rcg_clk_handoff(struct clk *c)
 {
 	struct rcg_clk *clk = to_rcg_clk(c);
 	uint32_t ctl_val, ns_val, md_val, ns_mask;
 	struct clk_freq_tbl *freq;
 
+	branch_handoff(&clk->b, &clk->c);
+
 	ctl_val = readl_relaxed(clk->b.ctl_reg);
 	if (!(ctl_val & clk->root_en_mask))
 		return 0;
@@ -859,35 +895,100 @@
 	return branch->enabled;
 }
 
-int branch_reset(struct branch *clk, enum clk_reset_action action)
+static void branch_enable_hwcg(struct branch *b)
+{
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(b->hwcg_reg);
+	reg_val |= b->hwcg_mask;
+	writel_relaxed(reg_val, b->hwcg_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static void branch_disable_hwcg(struct branch *b)
+{
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(b->hwcg_reg);
+	reg_val &= ~b->hwcg_mask;
+	writel_relaxed(reg_val, b->hwcg_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+void branch_clk_enable_hwcg(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	branch_enable_hwcg(&branch->b);
+}
+
+void branch_clk_disable_hwcg(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	branch_disable_hwcg(&branch->b);
+}
+
+int branch_clk_in_hwcg_mode(struct clk *c)
+{
+	struct branch_clk *clk = to_branch_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
+void rcg_clk_enable_hwcg(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	branch_enable_hwcg(&rcg->b);
+}
+
+void rcg_clk_disable_hwcg(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	branch_disable_hwcg(&rcg->b);
+}
+
+int rcg_clk_in_hwcg_mode(struct clk *c)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
+int branch_reset(struct branch *b, enum clk_reset_action action)
 {
 	int ret = 0;
 	u32 reg_val;
 	unsigned long flags;
 
-	if (!clk->reset_reg)
+	if (!b->reset_reg)
 		return -EPERM;
 
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/* Disable hw gating when asserting a reset */
+	if (b->hwcg_mask && action == CLK_RESET_ASSERT)
+		branch_disable_hwcg(b);
 
-	reg_val = readl_relaxed(clk->reset_reg);
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/* Assert/Deassert reset */
+	reg_val = readl_relaxed(b->reset_reg);
 	switch (action) {
 	case CLK_RESET_ASSERT:
-		reg_val |= clk->reset_mask;
+		reg_val |= b->reset_mask;
 		break;
 	case CLK_RESET_DEASSERT:
-		reg_val &= ~(clk->reset_mask);
+		reg_val &= ~b->reset_mask;
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	writel_relaxed(reg_val, clk->reset_reg);
-
+	writel_relaxed(reg_val, b->reset_reg);
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
+	/* Enable hw gating when deasserting a reset */
+	if (b->hwcg_mask && action == CLK_RESET_DEASSERT)
+		branch_enable_hwcg(b);
 	/* Make sure write is issued before returning. */
 	mb();
-
 	return ret;
 }
 
@@ -896,6 +997,11 @@
 	return branch_reset(&to_branch_clk(clk)->b, action);
 }
 
+int rcg_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	return branch_reset(&to_rcg_clk(clk)->b, action);
+}
+
 static int cdiv_clk_enable(struct clk *c)
 {
 	unsigned long flags;
@@ -967,6 +1073,8 @@
 	struct cdiv_clk *clk = to_cdiv_clk(c);
 	u32 reg_val;
 
+	branch_handoff(&clk->b, &clk->c);
+
 	reg_val = readl_relaxed(clk->ns_reg);
 	if (reg_val & clk->ext_mask) {
 		clk->cur_div = 0;
@@ -978,9 +1086,30 @@
 	return 0;
 }
 
+static void cdiv_clk_enable_hwcg(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	branch_enable_hwcg(&clk->b);
+}
+
+static void cdiv_clk_disable_hwcg(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	branch_disable_hwcg(&clk->b);
+}
+
+static int cdiv_clk_in_hwcg_mode(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
 struct clk_ops clk_ops_cdiv = {
 	.enable = cdiv_clk_enable,
 	.disable = cdiv_clk_disable,
+	.in_hwcg_mode = cdiv_clk_in_hwcg_mode,
+	.enable_hwcg = cdiv_clk_enable_hwcg,
+	.disable_hwcg = cdiv_clk_disable_hwcg,
 	.auto_off = cdiv_clk_disable,
 	.handoff = cdiv_clk_handoff,
 	.set_rate = cdiv_clk_set_rate,
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 2123513..a561802d 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -90,6 +90,8 @@
  * struct branch - branch on/off
  * @ctl_reg: clock control register
  * @en_mask: ORed with @ctl_reg to enable the clock
+ * @hwcg_reg: hardware clock gating register
+ * @hwcg_mask: ORed with @hwcg_reg to enable hardware clock gating
  * @halt_reg: halt register
  * @halt_check: type of halt check to perform
  * @halt_bit: ANDed with @halt_reg to test for clock halted
@@ -100,6 +102,9 @@
 	void __iomem *const ctl_reg;
 	const u32 en_mask;
 
+	void __iomem *hwcg_reg;
+	u32 hwcg_mask;
+
 	void __iomem *const halt_reg;
 	const u16 halt_check;
 	const u16 halt_bit;
@@ -108,9 +113,10 @@
 	const u32 reset_mask;
 };
 
-int branch_reset(struct branch *clk, enum clk_reset_action action);
+int branch_reset(struct branch *b, enum clk_reset_action action);
 void __branch_clk_enable_reg(const struct branch *clk, const char *name);
 u32 __branch_clk_disable_reg(const struct branch *clk, const char *name);
+int branch_clk_handoff(struct clk *c);
 
 /*
  * Generic clock-definition struct and macros
@@ -150,6 +156,10 @@
 long rcg_clk_round_rate(struct clk *clk, unsigned long rate);
 struct clk *rcg_clk_get_parent(struct clk *c);
 int rcg_clk_handoff(struct clk *c);
+int rcg_clk_reset(struct clk *clk, enum clk_reset_action action);
+void rcg_clk_enable_hwcg(struct clk *clk);
+void rcg_clk_disable_hwcg(struct clk *clk);
+int rcg_clk_in_hwcg_mode(struct clk *c);
 
 /**
  * struct cdiv_clk - integer divider clock with external source selection
@@ -286,6 +296,9 @@
 int branch_clk_set_parent(struct clk *clk, struct clk *parent);
 int branch_clk_is_enabled(struct clk *clk);
 int branch_clk_reset(struct clk *c, enum clk_reset_action action);
+void branch_clk_enable_hwcg(struct clk *clk);
+void branch_clk_disable_hwcg(struct clk *clk);
+int branch_clk_in_hwcg_mode(struct clk *c);
 
 /**
  * struct measure_clk - for rate measurement debug use
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index ec8ff6c..91121e6 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -29,6 +29,7 @@
 #define CLKFLAG_NONEST			0x00000004
 #define CLKFLAG_NORESET			0x00000008
 #define CLKFLAG_HANDOFF_RATE		0x00000010
+#define CLKFLAG_HWCG			0x00000020
 #define CLKFLAG_SKIP_AUTO_OFF		0x00000200
 #define CLKFLAG_MIN			0x00000400
 #define CLKFLAG_MAX			0x00000800
@@ -63,6 +64,9 @@
 	int (*enable)(struct clk *clk);
 	void (*disable)(struct clk *clk);
 	void (*auto_off)(struct clk *clk);
+	void (*enable_hwcg)(struct clk *clk);
+	void (*disable_hwcg)(struct clk *clk);
+	int (*in_hwcg_mode)(struct clk *clk);
 	int (*handoff)(struct clk *clk);
 	int (*reset)(struct clk *clk, enum clk_reset_action action);
 	int (*set_rate)(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 7420bc0..b0f4c9f 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -22,6 +22,8 @@
 #include <mach/usbdiag.h>
 #include <mach/msm_sps.h>
 #include <mach/dma.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/apr_audio.h>
 #include "clock.h"
 #include "devices.h"
 #include "msm_watchdog.h"
@@ -206,6 +208,134 @@
 	.resource	= resources_qup_spi_gsbi5,
 };
 
+struct platform_device apq_pcm = {
+	.name	= "msm-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device apq_pcm_routing = {
+	.name	= "msm-pcm-routing",
+	.id	= -1,
+};
+
+struct platform_device apq_cpudai0 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4000,
+};
+
+struct platform_device apq_cpudai1 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4001,
+};
+
+struct platform_device apq_cpudai_hdmi_rx = {
+	.name	= "msm-dai-q6",
+	.id	= 8,
+};
+
+struct platform_device apq_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3000,
+};
+
+struct platform_device apq_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3001,
+};
+
+struct platform_device apq_cpudai_fm_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3004,
+};
+
+struct platform_device apq_cpudai_fm_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3005,
+};
+
+/*
+ * Machine specific data for AUX PCM Interface
+ * which the driver will  be unware of.
+ */
+struct msm_dai_auxpcm_pdata apq_auxpcm_rx_pdata = {
+	.clk = "pcm_clk",
+	.mode = AFE_PCM_CFG_MODE_PCM,
+	.sync = AFE_PCM_CFG_SYNC_INT,
+	.frame = AFE_PCM_CFG_FRM_256BPF,
+	.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+	.slot = 0,
+	.data = AFE_PCM_CFG_CDATAOE_MASTER,
+	.pcm_clk_rate = 2048000,
+};
+
+struct platform_device apq_cpudai_auxpcm_rx = {
+	.name = "msm-dai-q6",
+	.id = 2,
+	.dev = {
+		.platform_data = &apq_auxpcm_rx_pdata,
+	},
+};
+
+struct platform_device apq_cpudai_auxpcm_tx = {
+	.name = "msm-dai-q6",
+	.id = 3,
+};
+
+struct platform_device apq_cpu_fe = {
+	.name	= "msm-dai-fe",
+	.id	= -1,
+};
+
+struct platform_device apq_stub_codec = {
+	.name	= "msm-stub-codec",
+	.id	= 1,
+};
+
+struct platform_device apq_voice = {
+	.name	= "msm-pcm-voice",
+	.id	= -1,
+};
+
+struct platform_device apq_voip = {
+	.name	= "msm-voip-dsp",
+	.id	= -1,
+};
+
+struct platform_device apq_lpa_pcm = {
+	.name   = "msm-pcm-lpa",
+	.id     = -1,
+};
+
+struct platform_device apq_pcm_hostless = {
+	.name	= "msm-pcm-hostless",
+	.id	= -1,
+};
+
+struct platform_device apq_cpudai_afe_01_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xE0,
+};
+
+struct platform_device apq_cpudai_afe_01_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xF0,
+};
+
+struct platform_device apq_cpudai_afe_02_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xF1,
+};
+
+struct platform_device apq_cpudai_afe_02_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xE1,
+};
+
+struct platform_device apq_pcm_afe = {
+	.name	= "msm-pcm-afe",
+	.id	= -1,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 72fdcf7..aa9e380 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -188,6 +188,23 @@
 	}
 }
 
+#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+
+static struct resource msm_8660_q6_resources[] = {
+	{
+		.start  = MSM_LPASS_QDSP6SS_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_pil_q6v3 = {
+	.name = "pil_qdsp6v3",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8660_q6_resources),
+	.resource       = msm_8660_q6_resources,
+};
+
 static struct resource msm_uart1_dm_resources[] = {
 	{
 		.start = MSM_UART1DM_PHYS,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index ffe22f8..264e9a9 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -174,10 +174,34 @@
 extern struct platform_device msm_pcm_afe;
 extern struct platform_device msm_compr_dsp;
 
+extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_8960_q6_lpass;
 extern struct platform_device msm_8960_q6_mss_fw;
 extern struct platform_device msm_8960_q6_mss_sw;
 
+extern struct platform_device apq_pcm;
+extern struct platform_device apq_pcm_routing;
+extern struct platform_device apq_cpudai0;
+extern struct platform_device apq_cpudai1;
+extern struct platform_device apq_cpudai_hdmi_rx;
+extern struct platform_device apq_cpudai_bt_rx;
+extern struct platform_device apq_cpudai_bt_tx;
+extern struct platform_device apq_cpudai_fm_rx;
+extern struct platform_device apq_cpudai_fm_tx;
+extern struct platform_device apq_cpudai_auxpcm_rx;
+extern struct platform_device apq_cpudai_auxpcm_tx;
+extern struct platform_device apq_cpu_fe;
+extern struct platform_device apq_stub_codec;
+extern struct platform_device apq_voice;
+extern struct platform_device apq_voip;
+extern struct platform_device apq_lpa_pcm;
+extern struct platform_device apq_pcm_hostless;
+extern struct platform_device apq_cpudai_afe_01_rx;
+extern struct platform_device apq_cpudai_afe_01_tx;
+extern struct platform_device apq_cpudai_afe_02_rx;
+extern struct platform_device apq_cpudai_afe_02_tx;
+extern struct platform_device apq_pcm_afe;
+
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
 
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 40e13fa..e855357 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -212,8 +212,17 @@
 	mcr     p15, 0, r3, c8, c7, 0   /* UTLBIALL */
 	mcr     p15, 0, r3, c7, c5, 6   /* BPIALL */
 	dsb
-
 	isb
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	mrc	p15, 0, r1, c0, c0, 0
+	ldr	r3, =0xff00fc00
+	and	r3, r1, r3
+	ldr 	r1, =0x51000400
+	cmp	r3, r1
+	mrceq	p15, 7, r3, c15, c0, 2
+	biceq	r3, r3, #0x400
+	mcreq	p15, 7, r3, c15, c0, 2
+#endif
 	stmfd   sp!, {lr}
 	bl      v7_flush_kern_cache_all
 #ifdef CONFIG_MSM_TRACE_ACROSS_PC
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 753a47c..830e36b 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2007-2009,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
@@ -17,7 +17,6 @@
 int msm_arch_idle(void);
 int msm_pm_collapse(void);
 void msm_pm_collapse_exit(void);
-void msm_warmboot_entry(void);
 
 #ifdef CONFIG_CPU_V7
 void msm_pm_boot_entry(void);
@@ -31,5 +30,4 @@
 }
 #endif
 
-
 #endif
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index ce89c14..ae1f753 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -324,7 +324,8 @@
 
 struct msm_actuator_ctrl {
 	int (*a_init_table)(void);
-	int (*a_power_down)(void);
+	int (*a_power_up)(void *);
+	int (*a_power_down)(void *);
 	int (*a_create_subdevice)(void *, void *);
 	int (*a_config)(void __user *);
 };
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 54566dc..d8a3e60 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -20,6 +20,7 @@
 	USB_GADGET_XPORT_SDIO,
 	USB_GADGET_XPORT_SMD,
 	USB_GADGET_XPORT_BAM,
+	USB_GADGET_XPORT_BAM2BAM,
 	USB_GADGET_XPORT_HSIC,
 	USB_GADGET_XPORT_NONE,
 };
@@ -37,6 +38,8 @@
 		return "SMD";
 	case USB_GADGET_XPORT_BAM:
 		return "BAM";
+	case USB_GADGET_XPORT_BAM2BAM:
+		return "BAM2BAM";
 	case USB_GADGET_XPORT_HSIC:
 		return "HSIC";
 	case USB_GADGET_XPORT_NONE:
@@ -56,6 +59,8 @@
 		return USB_GADGET_XPORT_SMD;
 	if (!strncasecmp("BAM", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_BAM;
+	if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_BAM2BAM;
 	if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_HSIC;
 	if (!strncasecmp("", name, XPORT_STR_LEN))
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
index fc91291..296c6dc 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
@@ -140,8 +140,8 @@
 		.tier = tiered_slave_ebi,
 		.num_tiers = ARRAY_SIZE(tiered_slave_ebi),
 		.buswidth = 8,
-		.slaveclk[DUAL_CTX] = "ebi1_msmbus_clk",
-		.slaveclk[ACTIVE_CTX] = "ebi1_a_clk",
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_AMPSS_L2,
@@ -848,8 +848,8 @@
 	.info = apps_fabric_info,
 	.len = ARRAY_SIZE(apps_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "afab_clk",
-	.fabclk[ACTIVE_CTX] = "afab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_APPS_FABRIC_HALT_0,
 	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
 	.nmasters = 4,
@@ -864,8 +864,8 @@
 	system_fabric_info,
 	ARRAY_SIZE(system_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "sfab_clk",
-	.fabclk[ACTIVE_CTX] = "sfab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_SYSTEM_FABRIC_HALT_0,
 	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
 	.nmasters = 17,
@@ -880,8 +880,8 @@
 	mmss_fabric_info,
 	ARRAY_SIZE(mmss_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "mmfab_clk",
-	.fabclk[ACTIVE_CTX] = "mmfab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_MM_FABRIC_HALT_0,
 	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
 	.nmasters = 14,
@@ -896,8 +896,8 @@
 	sys_fpb_fabric_info,
 	ARRAY_SIZE(sys_fpb_fabric_info),
 	.ahb = 1,
-	.fabclk[DUAL_CTX] = "sfpb_clk",
-	.fabclk[ACTIVE_CTX] = "sfpb_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.nmasters = 0,
 	.nslaves = 0,
 	.ntieredslaves = 0,
@@ -910,8 +910,8 @@
 	cpss_fpb_fabric_info,
 	ARRAY_SIZE(cpss_fpb_fabric_info),
 	.ahb = 1,
-	.fabclk[DUAL_CTX] = "cfpb_clk",
-	.fabclk[ACTIVE_CTX] = "cfpb_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.nmasters = 0,
 	.nslaves = 0,
 	.ntieredslaves = 0,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 97a3145..0d265c7 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -154,8 +154,8 @@
 		.tier = tiered_slave_ebi1_ch0,
 		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
 		.buswidth = 8,
-		.slaveclk[DUAL_CTX] = "ebi1_msmbus_clk",
-		.slaveclk[ACTIVE_CTX] = "ebi1_a_clk",
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_EBI_CH1,
@@ -164,8 +164,8 @@
 		.tier = tiered_slave_ebi1_ch1,
 		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch1),
 		.buswidth = 8,
-		.slaveclk[DUAL_CTX] = "ebi1_msmbus_clk",
-		.slaveclk[ACTIVE_CTX] = "ebi1_a_clk",
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_AMPSS_L2,
@@ -875,8 +875,8 @@
 	.info = apps_fabric_info,
 	.len = ARRAY_SIZE(apps_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "afab_clk",
-	.fabclk[ACTIVE_CTX] = "afab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
 	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
 	.nmasters = 6,
@@ -891,8 +891,8 @@
 	system_fabric_info,
 	ARRAY_SIZE(system_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "sfab_clk",
-	.fabclk[ACTIVE_CTX] = "sfab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
 	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
 	.nmasters = 15,
@@ -907,8 +907,8 @@
 	mmss_fabric_info,
 	ARRAY_SIZE(mmss_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "mmfab_clk",
-	.fabclk[ACTIVE_CTX] = "mmfab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
 	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
 	.nmasters = 14,
@@ -923,8 +923,8 @@
 	sys_fpb_fabric_info,
 	ARRAY_SIZE(sys_fpb_fabric_info),
 	.ahb = 1,
-	.fabclk[DUAL_CTX] = "sfpb_clk",
-	.fabclk[ACTIVE_CTX] = "sfpb_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.nmasters = 0,
 	.nslaves = 0,
 	.ntieredslaves = 0,
@@ -937,8 +937,8 @@
 	cpss_fpb_fabric_info,
 	ARRAY_SIZE(cpss_fpb_fabric_info),
 	.ahb = 1,
-	.fabclk[DUAL_CTX] = "cfpb_clk",
-	.fabclk[ACTIVE_CTX] = "cfpb_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.nmasters = 0,
 	.nslaves = 0,
 	.ntieredslaves = 0,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
index a941a89..5b52cb9 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
@@ -192,8 +192,8 @@
 		.tier = tiered_slave_ebi1_ch0,
 		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
 		.buswidth = 8,
-		.slaveclk[DUAL_CTX] = "ebi1_msmbus_clk",
-		.slaveclk[ACTIVE_CTX] = "ebi1_a_clk",
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
@@ -285,8 +285,8 @@
 	system_fabric_info,
 	ARRAY_SIZE(system_fabric_info),
 	.ahb = 0,
-	.fabclk[DUAL_CTX] = "sfab_clk",
-	.fabclk[ACTIVE_CTX] = "sfab_a_clk",
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
 	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
 	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
 	.nmasters = 12,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index fd82111..02dfed6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -71,7 +71,7 @@
 			SLAVE_NODE);
 
 	if (info->node_info->slaveclk[DUAL_CTX]) {
-		info->nodeclk[DUAL_CTX].clk = clk_get(NULL,
+		info->nodeclk[DUAL_CTX].clk = clk_get_sys("msm_bus",
 			info->node_info->slaveclk[DUAL_CTX]);
 		if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
 			MSM_BUS_ERR("Could not get clock for %s\n",
@@ -144,8 +144,8 @@
 
 		for (ctx = 0; ctx < NUM_CTX; ctx++) {
 			if (info->node_info->slaveclk[ctx]) {
-				info->nodeclk[ctx].clk = clk_get(NULL,
-						info->node_info->slaveclk[ctx]);
+				info->nodeclk[ctx].clk = clk_get_sys("msm_bus",
+					info->node_info->slaveclk[ctx]);
 				if (IS_ERR(info->nodeclk[ctx].clk)) {
 					MSM_BUS_ERR("Couldn't get clk %s\n",
 						info->node_info->slaveclk[ctx]);
@@ -156,7 +156,7 @@
 			}
 		}
 		if (info->node_info->memclk) {
-			info->memclk.clk = clk_get(NULL,
+			info->memclk.clk = clk_get_sys("msm_bus",
 					info->node_info->memclk);
 			if (IS_ERR(info->memclk.clk)) {
 				MSM_BUS_ERR("Couldn't get clk %s\n",
@@ -652,10 +652,21 @@
 		fabric->fabdev.id);
 	fabric->fabdev.board_algo = fabric->pdata->board_algo;
 
+	/*
+	 * clk and bw for fabric->info will contain the max bw and clk
+	 * it will allow. This info will come from the boards file.
+	 */
+	ret = msm_bus_fabric_device_register(&fabric->fabdev);
+	if (ret) {
+		MSM_BUS_ERR("Error registering fabric %d ret %d\n",
+			fabric->fabdev.id, ret);
+		goto err;
+	}
+
 	for (ctx = 0; ctx < NUM_CTX; ctx++) {
 		if (pdata->fabclk[ctx]) {
-			fabric->info.nodeclk[ctx].clk = clk_get(NULL,
-							pdata->fabclk[ctx]);
+			fabric->info.nodeclk[ctx].clk = clk_get(
+				&fabric->fabdev.dev, pdata->fabclk[ctx]);
 			if (IS_ERR(fabric->info.nodeclk[ctx].clk)) {
 				MSM_BUS_ERR("Couldn't get clock %s\n",
 					pdata->fabclk[ctx]);
@@ -687,16 +698,6 @@
 			}
 		}
 	}
-	/*
-	 * clk and bw for fabric->info will contain the max bw and clk
-	 * it will allow. This info will come from the boards file.
-	 */
-	ret = msm_bus_fabric_device_register(&fabric->fabdev);
-	if (ret) {
-		MSM_BUS_ERR("Error registering fabric %d ret %d\n",
-			fabric->fabdev.id, ret);
-		goto err;
-	}
 
 	return ret;
 err:
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
index f3f5388..2d60a7e 100644
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ b/arch/arm/mach-msm/peripheral-reset.c
@@ -34,7 +34,6 @@
 #define PROXY_VOTE_TIMEOUT		10000
 
 #define MSM_MMS_REGS_BASE		0x10200000
-#define MSM_LPASS_QDSP6SS_BASE		0x28800000
 
 #define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
 #define MARM_BOOT_CONTROL		(msm_mms_regs_base + 0x0010)
@@ -58,18 +57,12 @@
 #define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
 #define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
 
-#define LCC_Q6_FUNC			(MSM_LPASS_CLK_CTL_BASE + 0x001C)
-#define QDSP6SS_RST_EVB			(msm_lpass_qdsp6ss_base + 0x0000)
-#define QDSP6SS_STRAP_TCM		(msm_lpass_qdsp6ss_base + 0x001C)
-#define QDSP6SS_STRAP_AHB		(msm_lpass_qdsp6ss_base + 0x0020)
-
 #define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
 #define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
 #define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
 
-static int modem_start, q6_start, dsps_start;
+static int modem_start, dsps_start;
 static void __iomem *msm_mms_regs_base;
-static void __iomem *msm_lpass_qdsp6ss_base;
 
 static int init_image_modem_trusted(struct pil_desc *pil, const u8 *metadata,
 				    size_t size)
@@ -85,20 +78,6 @@
 	return 0;
 }
 
-static int init_image_q6_trusted(struct pil_desc *pil,
-				 const u8 *metadata, size_t size)
-{
-	return pas_init_image(PAS_Q6, metadata, size);
-}
-
-static int init_image_q6_untrusted(struct pil_desc *pil, const u8 *metadata,
-				   size_t size)
-{
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	q6_start = ehdr->e_entry;
-	return 0;
-}
-
 static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
 				   size_t size)
 {
@@ -291,154 +270,6 @@
 	return 0;
 }
 
-#define LV_EN 			BIT(27)
-#define STOP_CORE		BIT(26)
-#define CLAMP_IO 		BIT(25)
-#define Q6SS_PRIV_ARES		BIT(24)
-#define Q6SS_SS_ARES		BIT(23)
-#define Q6SS_ISDB_ARES		BIT(22)
-#define Q6SS_ETM_ARES		BIT(21)
-#define Q6_JTAG_CRC_EN		BIT(20)
-#define Q6_JTAG_INV_EN		BIT(19)
-#define Q6_JTAG_CXC_EN		BIT(18)
-#define Q6_PXO_CRC_EN		BIT(17)
-#define Q6_PXO_INV_EN		BIT(16)
-#define Q6_PXO_CXC_EN		BIT(15)
-#define Q6_PXO_SLEEP_EN		BIT(14)
-#define Q6_SLP_CRC_EN		BIT(13)
-#define Q6_SLP_INV_EN		BIT(12)
-#define Q6_SLP_CXC_EN		BIT(11)
-#define CORE_ARES		BIT(10)
-#define CORE_L1_MEM_CORE_EN	BIT(9)
-#define CORE_TCM_MEM_CORE_EN	BIT(8)
-#define CORE_TCM_MEM_PERPH_EN	BIT(7)
-#define CORE_GFM4_CLK_EN	BIT(2)
-#define CORE_GFM4_RES		BIT(1)
-#define RAMP_PLL_SRC_SEL	BIT(0)
-
-#define Q6_STRAP_AHB_UPPER	(0x290 << 12)
-#define Q6_STRAP_AHB_LOWER	0x280
-#define Q6_STRAP_TCM_BASE	(0x28C << 15)
-#define Q6_STRAP_TCM_CONFIG	0x28B
-
-static struct clk *pll4;
-
-static void remove_q6_proxy_votes(unsigned long data)
-{
-	clk_disable(pll4);
-}
-static DEFINE_TIMER(q6_timer, remove_q6_proxy_votes, 0, 0);
-
-static void make_q6_proxy_votes(void)
-{
-	/* Make proxy votes for Q6 and set up timer to disable it. */
-	clk_enable(pll4);
-	mod_timer(&q6_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
-}
-
-static void remove_q6_proxy_votes_now(void)
-{
-	/*
-	 * If the Q6 proxy vote hasn't been removed yet, them remove the
-	 * votes immediately.
-	 */
-	if (del_timer(&q6_timer))
-		remove_q6_proxy_votes(0);
-}
-
-static int reset_q6_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-
-	make_q6_proxy_votes();
-
-	/* Put Q6 into reset */
-	reg = __raw_readl(LCC_Q6_FUNC);
-	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
-		CORE_ARES;
-	reg &= ~CORE_GFM4_CLK_EN;
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
-	usleep_range(20, 30);
-
-	/* Turn on Q6 memory */
-	reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
-		CORE_TCM_MEM_PERPH_EN;
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	/* Turn on Q6 core clocks and take core out of reset */
-	reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
-			CORE_ARES);
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	/* Wait for clocks to be enabled */
-	mb();
-	/* Program boot address */
-	__raw_writel((q6_start >> 12) & 0xFFFFF, QDSP6SS_RST_EVB);
-
-	__raw_writel(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
-			QDSP6SS_STRAP_TCM);
-	__raw_writel(Q6_STRAP_AHB_UPPER | Q6_STRAP_AHB_LOWER,
-			QDSP6SS_STRAP_AHB);
-
-	/* Wait for addresses to be programmed before starting Q6 */
-	mb();
-
-	/* Start Q6 instruction execution */
-	reg &= ~STOP_CORE;
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	return 0;
-}
-
-static int reset_q6_trusted(struct pil_desc *pil)
-{
-	make_q6_proxy_votes();
-
-	return pas_auth_and_reset(PAS_Q6);
-}
-
-static int shutdown_q6_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-
-	/* Put Q6 into reset */
-	reg = __raw_readl(LCC_Q6_FUNC);
-	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
-		CORE_ARES;
-	reg &= ~CORE_GFM4_CLK_EN;
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
-	usleep_range(20, 30);
-
-	/* Turn off Q6 memory */
-	reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
-		CORE_TCM_MEM_PERPH_EN);
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	reg |= CLAMP_IO;
-	__raw_writel(reg, LCC_Q6_FUNC);
-
-	remove_q6_proxy_votes_now();
-
-	return 0;
-}
-
-static int shutdown_q6_trusted(struct pil_desc *pil)
-{
-	int ret;
-
-	ret = pas_shutdown(PAS_Q6);
-	if (ret)
-		return ret;
-
-	remove_q6_proxy_votes_now();
-
-	return 0;
-}
-
 static int reset_dsps_untrusted(struct pil_desc *pil)
 {
 	__raw_writel(0x10, PPSS_PROC_CLK_CTL);
@@ -490,13 +321,6 @@
 	.shutdown = shutdown_modem_untrusted,
 };
 
-struct pil_reset_ops pil_q6_ops = {
-	.init_image = init_image_q6_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_q6_untrusted,
-	.shutdown = shutdown_q6_untrusted,
-};
-
 struct pil_reset_ops pil_dsps_ops = {
 	.init_image = init_image_dsps_untrusted,
 	.verify_blob = verify_blob,
@@ -522,16 +346,6 @@
 	.ops = &pil_modem_ops,
 };
 
-static struct platform_device pil_q6 = {
-	.name = "pil_q6",
-};
-
-static struct pil_desc pil_q6_desc = {
-	.name = "q6",
-	.dev = &pil_q6.dev,
-	.ops = &pil_q6_ops,
-};
-
 static struct platform_device pil_playready = {
 	.name = "pil_playready",
 };
@@ -558,38 +372,22 @@
 	if (!msm_mms_regs_base)
 		goto err;
 
-	msm_lpass_qdsp6ss_base = ioremap(MSM_LPASS_QDSP6SS_BASE, SZ_256);
-	if (!msm_lpass_qdsp6ss_base)
-		goto err_lpass;
-
 	pxo = msm_xo_get(MSM_XO_PXO, "pil");
 	if (IS_ERR(pxo))
 		goto err_pxo;
 
-	pll4 = clk_get_sys("peripheral-reset", "pll4");
-	if (IS_ERR(pll4))
-		goto err_clk;
-
 	if (pas_supported(PAS_MODEM) > 0) {
 		pil_modem_ops.init_image = init_image_modem_trusted;
 		pil_modem_ops.auth_and_reset = reset_modem_trusted;
 		pil_modem_ops.shutdown = shutdown_modem_trusted;
 	}
 
-	if (pas_supported(PAS_Q6) > 0) {
-		pil_q6_ops.init_image = init_image_q6_trusted;
-		pil_q6_ops.auth_and_reset = reset_q6_trusted;
-		pil_q6_ops.shutdown = shutdown_q6_trusted;
-	}
-
 	if (pas_supported(PAS_DSPS) > 0) {
 		pil_dsps_ops.init_image = init_image_dsps_trusted;
 		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
 		pil_dsps_ops.shutdown = shutdown_dsps_trusted;
 	}
 
-	BUG_ON(platform_device_register(&pil_q6));
-	BUG_ON(msm_pil_register(&pil_q6_desc));
 	BUG_ON(platform_device_register(&pil_modem));
 	BUG_ON(msm_pil_register(&pil_modem_desc));
 	BUG_ON(platform_device_register(&pil_playready));
@@ -602,11 +400,7 @@
 
 	return 0;
 
-err_clk:
-	msm_xo_put(pxo);
 err_pxo:
-	iounmap(msm_lpass_qdsp6ss_base);
-err_lpass:
 	iounmap(msm_mms_regs_base);
 err:
 	return -ENOMEM;
@@ -615,7 +409,6 @@
 static void __exit msm_peripheral_reset_exit(void)
 {
 	iounmap(msm_mms_regs_base);
-	iounmap(msm_lpass_qdsp6ss_base);
 }
 
 arch_initcall(msm_peripheral_reset_init);
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
new file mode 100644
index 0000000..7354d93
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -0,0 +1,299 @@
+/* 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
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define QDSP6SS_RST_EVB		0x0000
+#define QDSP6SS_STRAP_TCM	0x001C
+#define QDSP6SS_STRAP_AHB	0x0020
+
+#define LCC_Q6_FUNC		(MSM_LPASS_CLK_CTL_BASE + 0x001C)
+#define LV_EN			BIT(27)
+#define STOP_CORE		BIT(26)
+#define CLAMP_IO		BIT(25)
+#define Q6SS_PRIV_ARES		BIT(24)
+#define Q6SS_SS_ARES		BIT(23)
+#define Q6SS_ISDB_ARES		BIT(22)
+#define Q6SS_ETM_ARES		BIT(21)
+#define Q6_JTAG_CRC_EN		BIT(20)
+#define Q6_JTAG_INV_EN		BIT(19)
+#define Q6_JTAG_CXC_EN		BIT(18)
+#define Q6_PXO_CRC_EN		BIT(17)
+#define Q6_PXO_INV_EN		BIT(16)
+#define Q6_PXO_CXC_EN		BIT(15)
+#define Q6_PXO_SLEEP_EN		BIT(14)
+#define Q6_SLP_CRC_EN		BIT(13)
+#define Q6_SLP_INV_EN		BIT(12)
+#define Q6_SLP_CXC_EN		BIT(11)
+#define CORE_ARES		BIT(10)
+#define CORE_L1_MEM_CORE_EN	BIT(9)
+#define CORE_TCM_MEM_CORE_EN	BIT(8)
+#define CORE_TCM_MEM_PERPH_EN	BIT(7)
+#define CORE_GFM4_CLK_EN	BIT(2)
+#define CORE_GFM4_RES		BIT(1)
+#define RAMP_PLL_SRC_SEL	BIT(0)
+
+#define Q6_STRAP_AHB_UPPER	(0x290 << 12)
+#define Q6_STRAP_AHB_LOWER	0x280
+#define Q6_STRAP_TCM_BASE	(0x28C << 15)
+#define Q6_STRAP_TCM_CONFIG	0x28B
+
+#define PROXY_VOTE_TIMEOUT	10000
+
+struct q6v3_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct clk *pll;
+	struct timer_list timer;
+};
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static void q6v3_remove_proxy_votes(unsigned long data)
+{
+	struct q6v3_data *drv = (struct q6v3_data *)data;
+	clk_disable(drv->pll);
+}
+
+static void q6v3_make_proxy_votes(struct device *dev)
+{
+	int ret;
+	struct q6v3_data *drv = dev_get_drvdata(dev);
+
+	ret = clk_enable(drv->pll);
+	if (ret)
+		dev_err(dev, "Failed to enable PLL\n");
+	mod_timer(&drv->timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void q6v3_remove_proxy_votes_now(struct q6v3_data *drv)
+{
+	/* If the proxy vote hasn't been removed yet, remove it immediately. */
+	if (del_timer(&drv->timer))
+		q6v3_remove_proxy_votes((unsigned long)drv);
+}
+
+static int pil_q6v3_reset(struct pil_desc *pil)
+{
+	u32 reg;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+
+	q6v3_make_proxy_votes(pil->dev);
+
+	/* Put Q6 into reset */
+	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
+		CORE_ARES;
+	reg &= ~CORE_GFM4_CLK_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	usleep_range(20, 30);
+
+	/* Turn on Q6 memory */
+	reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
+		CORE_TCM_MEM_PERPH_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Turn on Q6 core clocks and take core out of reset */
+	reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
+			CORE_ARES);
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait for clocks to be enabled */
+	mb();
+	/* Program boot address */
+	writel_relaxed((drv->start_addr >> 12) & 0xFFFFF,
+			drv->base + QDSP6SS_RST_EVB);
+
+	writel_relaxed(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
+			drv->base + QDSP6SS_STRAP_TCM);
+	writel_relaxed(Q6_STRAP_AHB_UPPER | Q6_STRAP_AHB_LOWER,
+			drv->base + QDSP6SS_STRAP_AHB);
+
+	/* Wait for addresses to be programmed before starting Q6 */
+	mb();
+
+	/* Start Q6 instruction execution */
+	reg &= ~STOP_CORE;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	return 0;
+}
+
+static int pil_q6v3_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Put Q6 into reset */
+	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
+		CORE_ARES;
+	reg &= ~CORE_GFM4_CLK_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	usleep_range(20, 30);
+
+	/* Turn off Q6 memory */
+	reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
+		CORE_TCM_MEM_PERPH_EN);
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	reg |= CLAMP_IO;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	q6v3_remove_proxy_votes_now(drv);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_q6v3_ops = {
+	.init_image = pil_q6v3_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_q6v3_reset,
+	.shutdown = pil_q6v3_shutdown,
+};
+
+static int pil_q6v3_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_Q6, metadata, size);
+}
+
+static int pil_q6v3_reset_trusted(struct pil_desc *pil)
+{
+	q6v3_make_proxy_votes(pil->dev);
+	return pas_auth_and_reset(PAS_Q6);
+}
+
+static int pil_q6v3_shutdown_trusted(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = pas_shutdown(PAS_Q6);
+	if (ret)
+		return ret;
+
+	q6v3_remove_proxy_votes_now(drv);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_q6v3_ops_trusted = {
+	.init_image = pil_q6v3_init_image_trusted,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_q6v3_reset_trusted,
+	.shutdown = pil_q6v3_shutdown_trusted,
+};
+
+static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
+{
+	struct q6v3_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	drv->pll = clk_get(&pdev->dev, "pll4");
+	if (IS_ERR(drv->pll))
+		return PTR_ERR(drv->pll);
+
+	setup_timer(&drv->timer, q6v3_remove_proxy_votes, (unsigned long)drv);
+	desc->name = "q6";
+	desc->dev = &pdev->dev;
+
+	if (pas_supported(PAS_Q6) > 0) {
+		desc->ops = &pil_q6v3_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_q6v3_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	if (msm_pil_register(desc))
+		return -EINVAL;
+	return 0;
+}
+
+static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
+{
+	struct q6v3_data *drv = platform_get_drvdata(pdev);
+	del_timer_sync(&drv->timer);
+	return 0;
+}
+
+static struct platform_driver pil_q6v3_driver = {
+	.probe = pil_q6v3_driver_probe,
+	.remove = __devexit_p(pil_q6v3_driver_exit),
+	.driver = {
+		.name = "pil_qdsp6v3",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_q6v3_init(void)
+{
+	return platform_driver_register(&pil_q6v3_driver);
+}
+module_init(pil_q6v3_init);
+
+static void __exit pil_q6v3_exit(void)
+{
+	platform_driver_unregister(&pil_q6v3_driver);
+}
+module_exit(pil_q6v3_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v3 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 8db21f9..f479daf 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -33,6 +33,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/hardware/cache-l2x0.h>
 #ifdef CONFIG_VFP
 #include <asm/vfp.h>
 #endif
@@ -636,6 +637,24 @@
 	msm_arch_idle();
 }
 
+#ifdef CONFIG_CACHE_L2X0
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	bool collapsed = 0;
+
+	l2x0_suspend();
+	collapsed = msm_pm_collapse();
+	l2x0_resume(collapsed);
+
+	return collapsed;
+}
+#else
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	return msm_pm_collapse();
+}
+#endif
+
 static bool msm_pm_spm_power_collapse(
 	struct msm_pm_device *dev, bool from_idle, bool notify_rpm)
 {
@@ -663,7 +682,7 @@
 	vfp_flush_context();
 #endif
 
-	collapsed = msm_pm_collapse();
+	collapsed = msm_pm_l2x0_power_collapse();
 
 	msm_pm_boot_config_after_pc(dev->cpu);
 
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index bcc4c64..6b92d1e 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -15,6 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <asm/mach-types.h>
+#include <asm/sizes.h>
 #include "scm-boot.h"
 #include "idle.h"
 #include "pm-boot.h"
@@ -55,7 +59,8 @@
 
 static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
 {
-	WARN_ON(!reset_vector);
+	if (!reset_vector)
+		return -ENODEV;
 	msm_pm_reset_vector = reset_vector;
 	mb();
 
@@ -88,19 +93,47 @@
 	if (msm_pm_boot_after_pc)
 		msm_pm_boot_after_pc(cpu);
 }
+#define BOOT_REMAP_ENABLE  BIT(0)
 
-int __init msm_pm_boot_init(int tz_available, uint32_t* address)
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
 {
 	int ret = 0;
 
-	switch (tz_available) {
+	switch (pdata->mode) {
 	case MSM_PM_BOOT_CONFIG_TZ:
 		ret = msm_pm_tz_boot_init();
 		msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
 		msm_pm_boot_after_pc = NULL;
 		break;
-	case MSM_PM_BOOT_CONFIG_RESET_VECTOR:
-		ret = msm_pm_boot_reset_vector_init(address);
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
+		if (!pdata->p_addr)
+			return -ENODEV;
+		pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
+		/* Fall through */
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
+
+		if (!pdata->v_addr)
+			return -ENODEV;
+
+		ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
+		msm_pm_boot_before_pc
+			= msm_pm_config_rst_vector_before_pc;
+		msm_pm_boot_after_pc
+			= msm_pm_config_rst_vector_after_pc;
+		break;
+	case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
+		/*
+		 * Set the boot remap address and enable remapping of
+		 * reset vector
+		 */
+		if (!pdata->p_addr || !pdata->v_addr)
+			return -ENODEV;
+
+		__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
+				pdata->v_addr);
+
+		ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
+
 		msm_pm_boot_before_pc
 			= msm_pm_config_rst_vector_before_pc;
 		msm_pm_boot_after_pc
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 2234192..8a7238a 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -14,18 +14,28 @@
 #define _ARCH_ARM_MACH_MSM_PM_BOOT_H
 
 enum {
-	MSM_PM_BOOT_CONFIG_TZ		= 0,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR	= 1,
+	MSM_PM_BOOT_CONFIG_TZ		     = 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+};
+
+struct msm_pm_boot_platform_data {
+	int mode;
+	phys_addr_t  p_addr;
+	void __iomem *v_addr;
 };
 
 #ifdef CONFIG_PM
-int __init msm_pm_boot_init(int boot_config, uint32_t* address);
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata);
 #else
-static inline int __init msm_pm_boot_init(int boot_config, uint32_t* address)
+static inline int __init msm_pm_boot_init(
+		struct msm_pm_boot_platform_data *pdata);
 {
 	return 0;
 }
 #endif
+
 void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry);
 void msm_pm_boot_config_after_pc(unsigned int cpu);
 
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
index 2519bb7..41d3ff3 100644
--- a/arch/arm/mach-msm/qdsp6v2/aac_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/aac_in.c
@@ -214,7 +214,10 @@
 			rc = -EINVAL;
 			break;
 		}
-		if ((cfg.bit_rate < 24000) || (cfg.bit_rate > 192000)) {
+		/* For aac-lc, min_bit_rate = min(24Kbps, 0.5*SR*num_chan);
+		max_bi_rate = min(192Kbps, 6*SR*num_chan);
+		min_sample_rate = 8000Hz, max_rate=48000 */
+		if ((cfg.bit_rate < 4000) || (cfg.bit_rate > 192000)) {
 			pr_err("%s: ERROR in setting bitrate = %d\n",
 				__func__, cfg.bit_rate);
 			rc = -EINVAL;
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
index 11687ac..51a209d 100644
--- a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -315,10 +315,10 @@
 		}
 
 		gpio_direction_output(SNDDEV_GPIO_CLASS_D1_EN, 1);
-		gpio_set_value(SNDDEV_GPIO_CLASS_D1_EN, 1);
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D1_EN, 1);
 
 	} else {
-		gpio_set_value(SNDDEV_GPIO_CLASS_D1_EN, 0);
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D1_EN, 0);
 		gpio_free(SNDDEV_GPIO_CLASS_D1_EN);
 	}
 	return 0;
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 28bf064..06e3d37 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -122,9 +122,6 @@
 #endif
 	pm8xxx_reset_pwr_off(0);
 
-	if (cpu_is_msm8x60())
-		pm8901_reset_pwr_off(0);
-
 	if (lower_pshold) {
 		__raw_writel(0, PSHOLD_CTL_SU);
 		mdelay(10000);
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 855482b..d7602f2 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -431,7 +431,8 @@
 	return i;
 }
 
-static int debug_read_ch_v1(char *buf, int max)
+#if (!defined(CONFIG_MSM_SMD_PKG4) && !defined(CONFIG_MSM_SMD_PKG3))
+static int debug_read_ch(char *buf, int max)
 {
 	void *shared;
 	int n, i = 0;
@@ -450,8 +451,8 @@
 
 	return i;
 }
-
-static int debug_read_ch_v2(char *buf, int max)
+#else
+static int debug_read_ch(char *buf, int max)
 {
 	void *shared, *buffer;
 	unsigned buffer_sz;
@@ -476,20 +477,7 @@
 
 	return i;
 }
-
-static int debug_read_ch(char *buf, int max)
-{
-	uint32_t *smd_ver;
-
-	smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
-
-	if (smd_ver && (((smd_ver[VERSION_MODEM] >> 16) >= 1) ||
-			((smd_ver[VERSION_QDSP6] >> 16) >= 1) ||
-			((smd_ver[VERSION_DSPS] >> 16) >= 1)))
-		return debug_read_ch_v2(buf, max);
-	else
-		return debug_read_ch_v1(buf, max);
-}
+#endif
 
 static int debug_read_smem_version(char *buf, int max)
 {
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index dc6ba5c..c8248a7 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -59,33 +59,38 @@
 	int is_open;
 	wait_queue_head_t ch_opened_wait_queue;
 	spinlock_t reset_lock;
+	struct smd_config *smd;
 };
 
+/**
+ * SMD port configuration.
+ *
+ * @tty_dev_index   Index into smd_tty[]
+ * @port_name       Name of the SMD port
+ * @dev_name        Name of the TTY Device (if NULL, @port_name is used)
+ * @edge            SMD edge
+ */
+struct smd_config {
+	uint32_t tty_dev_index;
+	const char *port_name;
+	const char *dev_name;
+	uint32_t edge;
+};
+
+static struct smd_config smd_configs[] = {
+	{0, "DS", NULL, SMD_APPS_MODEM},
+	{1, "APPS_FM", NULL, SMD_APPS_WCNSS},
+	{2, "APPS_RIVA_BT_ACL", NULL, SMD_APPS_WCNSS},
+	{3, "APPS_RIVA_BT_CMD", NULL, SMD_APPS_WCNSS},
+	{4, "MBALBRIDGE", NULL, SMD_APPS_MODEM},
+	{7, "DATA1", NULL, SMD_APPS_MODEM},
+	{11, "DATA11", NULL, SMD_APPS_MODEM},
+	{21, "DATA21", NULL, SMD_APPS_MODEM},
+	{27, "GPSNMEA", NULL, SMD_APPS_MODEM},
+	{36, "LOOPBACK", "LOOPBACK_TTY", SMD_APPS_MODEM},
+};
+#define DS_IDX 0
 #define LOOPBACK_IDX 36
-static char *smd_ch_name[] = {
-	[0] = "DS",
-	[1] = "APPS_FM",
-	[2] = "APPS_RIVA_BT_ACL",
-	[3] = "APPS_RIVA_BT_CMD",
-	[4] = "MBALBRIDGE",
-	[7] = "DATA1",
-	[21] = "DATA21",
-	[27] = "GPSNMEA",
-	[36] = "LOOPBACK",
-};
-
-static uint32_t smd_ch_edge[] = {
-	[0] = SMD_APPS_MODEM,
-	[1] = SMD_APPS_WCNSS,
-	[2] = SMD_APPS_WCNSS,
-	[3] = SMD_APPS_WCNSS,
-	[4] = SMD_APPS_MODEM,
-	[7] = SMD_APPS_MODEM,
-	[21] = SMD_APPS_MODEM,
-	[27] = SMD_APPS_MODEM,
-	[36] = SMD_APPS_MODEM,
-};
-
 
 static struct delayed_work loopback_work;
 static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
@@ -228,12 +233,12 @@
 static int smd_tty_open(struct tty_struct *tty, struct file *f)
 {
 	int res = 0;
-	int n = tty->index;
+	unsigned int n = tty->index;
 	struct smd_tty_info *info;
 	char *peripheral = NULL;
 
 
-	if (!smd_ch_name[n])
+	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
 		return -ENODEV;
 
 	info = smd_tty + n;
@@ -242,11 +247,11 @@
 	tty->driver_data = info;
 
 	if (info->open_count++ == 0) {
-		if (smd_ch_edge[n] == SMD_APPS_MODEM)
+		if (smd_tty[n].smd->edge == SMD_APPS_MODEM)
 			peripheral = "modem";
 
 		if (peripheral) {
-			info->pil = pil_get("modem");
+			info->pil = pil_get(peripheral);
 			if (IS_ERR(info->pil)) {
 				res = PTR_ERR(info->pil);
 				goto out;
@@ -257,7 +262,7 @@
 			 * the wait need to be done atmost once, using msleep
 			 * doesn't degrade the performance.
 			 */
-			if (n == 36) {
+			if (n == LOOPBACK_IDX) {
 				if (!is_modem_smsm_inited())
 					msleep(5000);
 				smsm_change_state(SMSM_APPS_STATE,
@@ -297,15 +302,15 @@
 		tasklet_init(&info->tty_tsklt, smd_tty_read,
 			     (unsigned long)info);
 		wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
-				smd_ch_name[n]);
+				smd_tty[n].smd->port_name);
 		if (!info->ch) {
-			res = smd_named_open_on_edge(smd_ch_name[n],
-							smd_ch_edge[n],
+			res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
+							smd_tty[n].smd->edge,
 							&info->ch, info,
 							smd_tty_notify);
 			if (res < 0) {
 				pr_err("%s: %s open failed %d\n", __func__,
-					smd_ch_name[n], res);
+					smd_tty[n].smd->port_name, res);
 				goto release_pil;
 			}
 
@@ -316,7 +321,8 @@
 				res = -ETIMEDOUT;
 			if (res < 0) {
 				pr_err("%s: wait for %s smd_open failed %d\n",
-					__func__, smd_ch_name[n], res);
+					__func__, smd_tty[n].smd->port_name,
+					res);
 				goto release_pil;
 			}
 			res = 0;
@@ -474,35 +480,24 @@
 
 static int smd_tty_dummy_probe(struct platform_device *pdev)
 {
-	if (!strncmp(pdev->name, smd_ch_name[0],
-				strnlen(smd_ch_name[0], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[0].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[1],
-				strnlen(smd_ch_name[1], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[1].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[2],
-				strnlen(smd_ch_name[2], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[2].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[3],
-				strnlen(smd_ch_name[3], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[3].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[4],
-				strnlen(smd_ch_name[4], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[4].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[7],
-				strnlen(smd_ch_name[7], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[7].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[21],
-				strnlen(smd_ch_name[21], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[21].ch_allocated);
-	else if (!strncmp(pdev->name, smd_ch_name[27],
-				strnlen(smd_ch_name[27], SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[27].ch_allocated);
-	else if (!strncmp(pdev->name, "LOOPBACK_TTY",
-				strnlen("LOOPBACK_TTY", SMD_MAX_CH_NAME_LEN)))
-		complete_all(&smd_tty[36].ch_allocated);
+	int n;
+	int idx;
 
-	return 0;
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (!smd_configs[n].dev_name)
+			continue;
+
+		if (!strncmp(pdev->name, smd_configs[n].dev_name,
+					SMD_MAX_CH_NAME_LEN)) {
+			complete_all(&smd_tty[idx].ch_allocated);
+			return 0;
+		}
+	}
+	pr_err("%s: unknown device '%s'\n", __func__, pdev->name);
+
+	return -ENODEV;
 }
 
 static struct tty_driver *smd_tty_driver;
@@ -510,7 +505,8 @@
 static int __init smd_tty_init(void)
 {
 	int ret;
-	int ds_registered = 0;
+	int n;
+	int idx;
 
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
 	if (smd_tty_driver == 0)
@@ -533,150 +529,69 @@
 	tty_set_operations(smd_tty_driver, &smd_tty_ops);
 
 	ret = tty_register_driver(smd_tty_driver);
-	if (ret) return ret;
-
-	/* this should be dynamic */
-	tty_register_device(smd_tty_driver, 0, 0);
-	tty_register_device(smd_tty_driver, 1, 0);
-	tty_register_device(smd_tty_driver, 2, 0);
-	tty_register_device(smd_tty_driver, 3, 0);
-	tty_register_device(smd_tty_driver, 4, 0);
-	tty_register_device(smd_tty_driver, 7, 0);
-	tty_register_device(smd_tty_driver, 21, 0);
-	tty_register_device(smd_tty_driver, 27, 0);
-	tty_register_device(smd_tty_driver, 36, 0);
-
-	init_completion(&smd_tty[0].ch_allocated);
-	init_completion(&smd_tty[1].ch_allocated);
-	init_completion(&smd_tty[2].ch_allocated);
-	init_completion(&smd_tty[3].ch_allocated);
-	init_completion(&smd_tty[4].ch_allocated);
-	init_completion(&smd_tty[7].ch_allocated);
-	init_completion(&smd_tty[21].ch_allocated);
-	init_completion(&smd_tty[27].ch_allocated);
-	init_completion(&smd_tty[36].ch_allocated);
-
-	smd_tty[0].driver.probe = smd_tty_dummy_probe;
-	smd_tty[0].driver.driver.name = smd_ch_name[0];
-	smd_tty[0].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[0].reset_lock);
-	smd_tty[0].is_open = 0;
-	init_waitqueue_head(&smd_tty[0].ch_opened_wait_queue);
-	/*
-	 * DS port is opened in the kernel starting with 8660 fusion.
-	 * Only register the platform driver for targets older than that.
-	 */
-	if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
-			cpu_is_msm7x30() || cpu_is_qsd8x50() ||
-			cpu_is_msm8x55() ||  (cpu_is_msm8x60() &&
-			socinfo_get_platform_subtype() == 0x1)) {
-		ret = platform_driver_register(&smd_tty[0].driver);
-		if (ret)
-			goto out;
-		ds_registered = 1;
+	if (ret) {
+		put_tty_driver(smd_tty_driver);
+		pr_err("%s: driver registration failed %d\n", __func__, ret);
+		return ret;
 	}
-	smd_tty[1].driver.probe = smd_tty_dummy_probe;
-	smd_tty[1].driver.driver.name = smd_ch_name[1];
-	smd_tty[1].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[1].reset_lock);
-	smd_tty[1].is_open = 0;
-	init_waitqueue_head(&smd_tty[1].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[1].driver);
-	if (ret)
-		goto unreg0;
-	smd_tty[2].driver.probe = smd_tty_dummy_probe;
-	smd_tty[2].driver.driver.name = smd_ch_name[2];
-	smd_tty[2].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[2].reset_lock);
-	smd_tty[2].is_open = 0;
-	init_waitqueue_head(&smd_tty[2].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[2].driver);
-	if (ret)
-		goto unreg1;
-	smd_tty[3].driver.probe = smd_tty_dummy_probe;
-	smd_tty[3].driver.driver.name = smd_ch_name[3];
-	smd_tty[3].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[3].reset_lock);
-	smd_tty[3].is_open = 0;
-	init_waitqueue_head(&smd_tty[3].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[3].driver);
-	if (ret)
-		goto unreg2;
-	smd_tty[4].driver.probe = smd_tty_dummy_probe;
-	smd_tty[4].driver.driver.name = smd_ch_name[4];
-	smd_tty[4].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[4].reset_lock);
-	smd_tty[4].is_open = 0;
-	init_waitqueue_head(&smd_tty[4].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[4].driver);
-	if (ret)
-		goto unreg3;
-	smd_tty[7].driver.probe = smd_tty_dummy_probe;
-	smd_tty[7].driver.driver.name = smd_ch_name[7];
-	smd_tty[7].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[7].reset_lock);
-	smd_tty[7].is_open = 0;
-	init_waitqueue_head(&smd_tty[7].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[7].driver);
-	if (ret)
-		goto unreg4;
-	smd_tty[21].driver.probe = smd_tty_dummy_probe;
-	smd_tty[21].driver.driver.name = smd_ch_name[21];
-	smd_tty[21].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[21].reset_lock);
-	smd_tty[21].is_open = 0;
-	init_waitqueue_head(&smd_tty[21].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[21].driver);
-	if (ret)
-		goto unreg7;
-	smd_tty[27].driver.probe = smd_tty_dummy_probe;
-	smd_tty[27].driver.driver.name = smd_ch_name[27];
-	smd_tty[27].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[27].reset_lock);
-	smd_tty[27].is_open = 0;
-	init_waitqueue_head(&smd_tty[27].ch_opened_wait_queue);
-	ret = platform_driver_register(&smd_tty[27].driver);
-	if (ret)
-		goto unreg21;
-	smd_tty[36].driver.probe = smd_tty_dummy_probe;
-	smd_tty[36].driver.driver.name = "LOOPBACK_TTY";
-	smd_tty[36].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[36].reset_lock);
-	smd_tty[36].is_open = 0;
-	init_waitqueue_head(&smd_tty[36].ch_opened_wait_queue);
-	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
-	ret = platform_driver_register(&smd_tty[36].driver);
-	if (ret)
-		goto unreg27;
 
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (smd_configs[n].dev_name == NULL)
+			smd_configs[n].dev_name = smd_configs[n].port_name;
+
+		if (idx == DS_IDX) {
+			/*
+			 * DS port uses the kernel API starting with
+			 * 8660 Fusion.  Only register the userspace
+			 * platform device for older targets.
+			 */
+			int legacy_ds = 0;
+
+			legacy_ds |= cpu_is_msm7x01() || cpu_is_msm7x25();
+			legacy_ds |= cpu_is_msm7x27() || cpu_is_msm7x30();
+			legacy_ds |= cpu_is_qsd8x50() || cpu_is_msm8x55();
+			legacy_ds |= cpu_is_msm8x60() &&
+					(socinfo_get_platform_subtype() == 0x1);
+
+			if (!legacy_ds)
+				continue;
+		}
+
+		tty_register_device(smd_tty_driver, idx, 0);
+		init_completion(&smd_tty[idx].ch_allocated);
+
+		/* register platform device */
+		smd_tty[idx].driver.probe = smd_tty_dummy_probe;
+		smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
+		smd_tty[idx].driver.driver.owner = THIS_MODULE;
+		spin_lock_init(&smd_tty[idx].reset_lock);
+		smd_tty[idx].is_open = 0;
+		init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
+		ret = platform_driver_register(&smd_tty[idx].driver);
+
+		if (ret) {
+			pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
+			smd_tty[idx].driver.probe = NULL;
+			goto out;
+		}
+		smd_tty[idx].smd = &smd_configs[n];
+	}
+	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 	return 0;
 
-unreg27:
-	platform_driver_unregister(&smd_tty[27].driver);
-unreg21:
-	platform_driver_unregister(&smd_tty[21].driver);
-unreg7:
-	platform_driver_unregister(&smd_tty[7].driver);
-unreg4:
-	platform_driver_unregister(&smd_tty[4].driver);
-unreg3:
-	platform_driver_unregister(&smd_tty[3].driver);
-unreg2:
-	platform_driver_unregister(&smd_tty[2].driver);
-unreg1:
-	platform_driver_unregister(&smd_tty[1].driver);
-unreg0:
-	if (ds_registered)
-		platform_driver_unregister(&smd_tty[0].driver);
 out:
-	tty_unregister_device(smd_tty_driver, 0);
-	tty_unregister_device(smd_tty_driver, 1);
-	tty_unregister_device(smd_tty_driver, 2);
-	tty_unregister_device(smd_tty_driver, 3);
-	tty_unregister_device(smd_tty_driver, 7);
-	tty_unregister_device(smd_tty_driver, 21);
-	tty_unregister_device(smd_tty_driver, 27);
-	tty_unregister_device(smd_tty_driver, 36);
+	/* unregister platform devices */
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (smd_tty[idx].driver.probe) {
+			platform_driver_unregister(&smd_tty[idx].driver);
+			tty_unregister_device(smd_tty_driver, idx);
+		}
+	}
+
 	tty_unregister_driver(smd_tty_driver);
 	put_tty_driver(smd_tty_driver);
 	return ret;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 90a1c7e..7e61e8b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -939,15 +939,17 @@
  * Store the most recent timestamp read from hardware
  * in last_ns. This is useful for debugging crashes.
  */
-static u64 last_ns;
+static atomic64_t last_ns;
 
 unsigned long long notrace sched_clock(void)
 {
 	struct msm_clock *clock = &msm_clocks[msm_global_timer];
 	struct clocksource *cs = &clock->clocksource;
-	u32 cyc = cs->read(cs);
-	last_ns = cyc_to_sched_clock(&cd, cyc, ((u32)~0 >> clock->shift));
-	return last_ns;
+	u64 cyc = cs->read(cs);
+	u64 last_ns_local;
+	last_ns_local = cyc_to_sched_clock(&cd, cyc, ((u32)~0 >> clock->shift));
+	atomic64_set(&last_ns, last_ns_local);
+	return last_ns_local;
 }
 
 static void notrace msm_update_sched_clock(void)
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index af92d22..07a9241 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -59,14 +59,33 @@
 						MODULE_NAME);
 		return;
 	}
-	if (new_state & SMSM_RESET)
+	if (new_state & SMSM_RESET) {
+		ss_restart_inprogress = true;
 		schedule_work(&riva_smsm_cb_work);
+	}
 }
 
 static void riva_fatal_fn(struct work_struct *work)
 {
-	if (!ss_restart_inprogress)
+	if (!enable_riva_ssr)
 		panic(MODULE_NAME ": Watchdog bite received from Riva");
+	else
+		subsystem_restart("riva");
+}
+
+static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+	int ret;
+
+	if (ss_restart_inprogress) {
+		pr_err("%s: Ignoring riva bite irq, restart in progress\n",
+						MODULE_NAME);
+		return IRQ_HANDLED;
+	}
+	disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+	ss_restart_inprogress = true;
+	ret = schedule_work(&riva_fatal_work);
+	return IRQ_HANDLED;
 }
 
 /* SMSM reset Riva */
@@ -106,6 +125,9 @@
 	if (!ret)
 		pil_force_boot("wcnss");
 
+	ss_restart_inprogress = false;
+	enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+
 	return ret;
 }
 
@@ -128,8 +150,6 @@
 /* Riva crash handler */
 static void riva_crash_shutdown(const struct subsys_data *subsys)
 {
-	ss_restart_inprogress = true;
-
 	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
 	if (riva_crash != true)
 		smsm_riva_reset();
@@ -176,6 +196,15 @@
 				" (%d)\n", MODULE_NAME, ret);
 		goto out;
 	}
+	ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+			riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
+				"riva_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to register for Riva bite interrupt"
+				" (%d)\n", MODULE_NAME, ret);
+		goto out;
+	}
 	ret = riva_restart_init();
 	if (ret < 0) {
 		pr_err("%s: Unable to register with ssr. (%d)\n",
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e5e3486..db80bd3 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -491,6 +491,17 @@
 	return pages;
 }
 
+/*
+ * Poison init memory with an undefined instruction (ARM) or a branch to an
+ * undefined instruction (Thumb).
+ */
+static inline void poison_init_mem(void *s, size_t count)
+{
+	u32 *p = (u32 *)s;
+	for (; count != 0; count -= 4)
+		*p++ = 0xe7fddef0;
+}
+
 static inline void
 free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -799,12 +810,14 @@
 #ifdef CONFIG_HAVE_TCM
 	extern char __tcm_start, __tcm_end;
 
+	poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
 	totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)),
 				    __phys_to_pfn(__pa(&__tcm_end)),
 				    "TCM link");
 #endif
 
 	if (!machine_is_integrator() && !machine_is_cintegrator()) {
+		poison_init_mem(__init_begin, __init_end - __init_begin);
 		reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
 					    __phys_to_pfn(__pa(__init_end)),
 					    "init");
@@ -850,6 +863,7 @@
 {
 	unsigned long reclaimed_initrd_mem;
 	if (!keep_initrd) {
+		poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
 		reclaimed_initrd_mem = free_area(__phys_to_pfn(__pa(start)),
 					    __phys_to_pfn(__pa(end)),
 					    "initrd");
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 0f79b76..6d589e2 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -797,11 +797,12 @@
 
 #if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
 	void *v_movable_start;
+	if (movable_reserved_size) {
+		v_movable_start = __va(movable_reserved_start);
 
-	v_movable_start = __va(movable_reserved_start);
-
-	if (vmalloc_min > v_movable_start)
-		vmalloc_min = v_movable_start;
+		if (vmalloc_min > v_movable_start)
+			vmalloc_min = v_movable_start;
+	}
 #endif
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index a321849..3c4aa8f 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -36,8 +36,6 @@
 #define RX_Q_MONITOR		(1)	/* 1 milli second */
 
 
-static unsigned int driver_state;
-
 static int hcismd_set;
 static DEFINE_MUTEX(hci_smd_enable);
 
@@ -127,7 +125,8 @@
 
 static void hci_smd_destruct(struct hci_dev *hdev)
 {
-	kfree(hdev->driver_data);
+	if (NULL != hdev->driver_data)
+		kfree(hdev->driver_data);
 }
 
 static void hci_smd_recv_data(unsigned long arg)
@@ -388,33 +387,25 @@
 	int rc;
 
 	/* Initialize and register HCI device */
-	if (!driver_state) {
-		hdev = hci_alloc_dev();
-		if (!hdev) {
-			BT_ERR("Can't allocate HCI device");
-			return -ENOMEM;
-		}
-
-		hsmd->hdev = hdev;
-		hdev->bus = HCI_SMD;
-		hdev->driver_data = hsmd;
-		hdev->open  = hci_smd_open;
-		hdev->close = hci_smd_close;
-		hdev->send  = hci_smd_send_frame;
-		hdev->destruct = hci_smd_destruct;
-		hdev->owner = THIS_MODULE;
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		BT_ERR("Can't allocate HCI device");
+		return -ENOMEM;
 	}
 
+	hsmd->hdev = hdev;
+	hdev->bus = HCI_SMD;
+	hdev->driver_data = NULL;
+	hdev->open  = hci_smd_open;
+	hdev->close = hci_smd_close;
+	hdev->send  = hci_smd_send_frame;
+	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);
-	if (!driver_state) {
-		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");
-	}
 	/*
 	 * Setup the timer to monitor whether the Rx queue is empty,
 	 * to control the wake lock release
@@ -442,29 +433,32 @@
 	/* Disable the read interrupts on the channel */
 	smd_disable_read_intr(hsmd->event_channel);
 	smd_disable_read_intr(hsmd->data_channel);
-	if (!driver_state) {
-		if (hci_register_dev(hdev) < 0) {
-			BT_ERR("Can't register HCI device");
-			hci_free_dev(hdev);
-			return -ENODEV;
-		}
-		driver_state = 1;
+	if (hci_register_dev(hdev) < 0) {
+		BT_ERR("Can't register HCI device");
+		hci_free_dev(hdev);
+		return -ENODEV;
 	}
 	return 0;
 }
 
-static void hci_smd_deregister_dev(void)
+static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
 {
 	smd_close(hs.event_channel);
 	smd_close(hs.data_channel);
 
 	if (wake_lock_active(&hs.wake_lock_rx))
 		wake_unlock(&hs.wake_lock_rx);
+	if (wake_lock_active(&hs.wake_lock_tx))
+		wake_unlock(&hs.wake_lock_tx);
 
 	/*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);
+	if (hci_unregister_dev(hsmd->hdev) < 0)
+		BT_ERR("Can't unregister HCI device %s", hsmd->hdev->name);
+
+	hci_free_dev(hsmd->hdev);
 }
 
 static int hcismd_set_enable(const char *val, struct kernel_param *kp)
@@ -484,7 +478,7 @@
 		hci_smd_register_dev(&hs);
 	break;
 	case 0:
-		hci_smd_deregister_dev();
+		hci_smd_deregister_dev(&hs);
 	break;
 	default:
 		ret = -EFAULT;
@@ -494,7 +488,22 @@
 	mutex_unlock(&hci_smd_enable);
 	return ret;
 }
+static int  __init hci_smd_init(void)
+{
+	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");
+	return 0;
+}
+module_init(hci_smd_init);
 
+static void __exit hci_smd_exit(void)
+{
+	wake_lock_destroy(&hs.wake_lock_rx);
+	wake_lock_destroy(&hs.wake_lock_tx);
+}
+module_exit(hci_smd_exit);
 
 MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
 MODULE_DESCRIPTION("Bluetooth SMD driver");
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 2681263..d2e4e4b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -905,6 +905,7 @@
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 	unsigned int rbbm_status;
 
+	WARN_ON(!(rb->flags & KGSL_FLAGS_STARTED));
 	if (rb->flags & KGSL_FLAGS_STARTED) {
 		/* Is the ring buffer is empty? */
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
@@ -916,8 +917,8 @@
 				status = true;
 		}
 	} else {
-		KGSL_DRV_ERR(device, "ringbuffer not started\n");
-		BUG();
+		/* if the ringbuffer isn't started we are VERY idle */
+		status = true;
 	}
 	return status;
 }
@@ -987,28 +988,27 @@
 
 	while (1) {
 		struct adreno_context *adreno_context = NULL;
-		struct kgsl_memdesc *gpustate;
-		struct kgsl_memdesc *gmemshadow;
 		context = idr_get_next(&device->context_idr, &next);
 		if (context == NULL)
 			break;
 
 		adreno_context = (struct adreno_context *)context->devctxt;
 
-		if (!kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base))
-			continue;
+		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+			struct kgsl_memdesc *desc;
 
-		gpustate = &adreno_context->gpustate;
-		if (kgsl_gpuaddr_in_memdesc(gpustate, gpuaddr, size)) {
-			result = gpustate;
-			return result;
-		}
-		gmemshadow = &adreno_context->context_gmem_shadow.gmemshadow;
-		if (kgsl_gpuaddr_in_memdesc(gmemshadow, gpuaddr, size)) {
-			result = gmemshadow;
-			return result;
-		}
+			desc = &adreno_context->gpustate;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
+				result = desc;
+				return result;
+			}
 
+			desc = &adreno_context->context_gmem_shadow.gmemshadow;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
+				result = desc;
+				return result;
+			}
+		}
 		next = next + 1;
 	}
 
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index c6b850e..9e49e6a 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -470,23 +470,8 @@
 
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
 	mb();
 
-	KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
-			pwr->power_flags, pwr->active_pwrlevel);
-
-	KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
-		pwr->interval_timeout);
-
-	KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
-				  kgsl_get_clkrate(pwr->grp_clks[0]));
-
-	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
-		kgsl_get_clkrate(pwr->ebi1_clk));
-
-
 	kgsl_regread(device, REG_RBBM_STATUS, &rbbm_status);
 	kgsl_regread(device, REG_RBBM_PM_OVERRIDE1, &r2);
 	kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, &r3);
@@ -810,6 +795,7 @@
 int adreno_postmortem_dump(struct kgsl_device *device, int manual)
 {
 	bool saved_nap;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
 	BUG_ON(device == NULL);
 
@@ -828,9 +814,26 @@
 			kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
 
 	}
+	KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
+			pwr->power_flags, pwr->active_pwrlevel);
+
+	KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
+		pwr->interval_timeout);
+
+	KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
+				  kgsl_get_clkrate(pwr->grp_clks[0]));
+
+	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
+		kgsl_get_clkrate(pwr->ebi1_clk));
+
 	/* Disable the idle timer so we don't get interrupted */
 	del_timer_sync(&device->idle_timer);
 
+	mutex_unlock(&device->mutex);
+	flush_workqueue(device->work_queue);
+	mutex_lock(&device->mutex);
+	adreno_dump(device);
+
 	/* Turn off napping to make sure we have the clocks full
 	   attention through the following process */
 	saved_nap = device->pwrctrl.nap_allowed;
@@ -852,13 +855,6 @@
 				device->id);
 	}
 
-	KGSL_DRV_ERR(device,
-			"wait for work in workqueue to complete\n");
-	mutex_unlock(&device->mutex);
-	flush_workqueue(device->work_queue);
-	mutex_lock(&device->mutex);
-	adreno_dump(device);
-
 	/* Restore nap mode */
 	device->pwrctrl.nap_allowed = saved_nap;
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e8bad9d..dbbe4d5 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -722,6 +722,8 @@
 			return 0;
 		if (device->ftbl->isidle(device))
 			goto slumber;
+		else
+			device->pwrctrl.restore_slumber = true;
 	}
 
 	device->requested_state = KGSL_STATE_NONE;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 114053c..928ea65 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -267,7 +267,6 @@
 	sysfs_remove_group(&pwrscale->kobj, attr_group);
 	kobject_del(&pwrscale->kobj);
 	kobject_put(&pwrscale->kobj);
-	pwrscale->kobj.state_initialized = 0;
 }
 
 static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device)
diff --git a/drivers/hwmon/pm8xxx-adc-scale.c b/drivers/hwmon/pm8xxx-adc-scale.c
index 7b27f72..fb2f1d5 100644
--- a/drivers/hwmon/pm8xxx-adc-scale.c
+++ b/drivers/hwmon/pm8xxx-adc-scale.c
@@ -17,230 +17,222 @@
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #define KELVINMIL_DEGMIL	273160
 
-static const struct pm8xxx_adc_map_pt adcmap_batttherm[] = {
-	{41001,	-30},
-	{40017,	-20},
-	{38721,	-10},
-	{37186,	  0},
-	{35554,	 10},
-	{33980,	 20},
-	{33253,	 25},
-	{32580,	 30},
-	{31412,	 40},
-	{30481,	 50},
-	{29759,	 60},
-	{29209,	 70},
-	{28794,	 80}
-};
-
+/* Units for temperature below (on x axis) is in 0.1DegC as
+   required by the battery driver. Note the resolution used
+   here to compute the table was done for DegC to milli-volts.
+   In consideration to limit the size of the table for the given
+   temperature range below, the result is linearly interpolated
+   and provided to the battery driver in the units desired for
+   their framework which is 0.1DegC. True resolution of 0.1DegC
+   will result in the below table size to increase by 10 times */
 static const struct pm8xxx_adc_map_pt adcmap_btm_threshold[] = {
-	{-30,	1642},
-	{-20,	1544},
-	{-10,	1414},
+	{-300,	1642},
+	{-200,	1544},
+	{-100,	1414},
 	{0,	1260},
-	{1,	1244},
-	{2,	1228},
-	{3,	1212},
-	{4,	1195},
-	{5,	1179},
-	{6,	1162},
-	{7,	1146},
-	{8,	1129},
-	{9,	1113},
-	{10,	1097},
-	{11,	1080},
-	{12,	1064},
-	{13,	1048},
-	{14,	1032},
-	{15,	1016},
-	{16,	1000},
-	{17,	985},
-	{18,	969},
-	{19,	954},
-	{20,	939},
-	{21,	924},
-	{22,	909},
-	{23,	894},
-	{24,	880},
-	{25,	866},
-	{26,	852},
-	{27,	838},
-	{28,	824},
-	{29,	811},
-	{30,	798},
-	{31,	785},
-	{32,	773},
-	{33,	760},
-	{34,	748},
-	{35,	736},
-	{36,	725},
-	{37,	713},
-	{38,	702},
-	{39,	691},
-	{40,	681},
-	{41,	670},
-	{42,	660},
-	{43,	650},
-	{44,	640},
-	{45,	631},
-	{46,	622},
-	{47,	613},
-	{48,	604},
-	{49,	595},
-	{50,	587},
-	{51,	579},
-	{52,	571},
-	{53,	563},
-	{54,	556},
-	{55,	548},
-	{56,	541},
-	{57,	534},
-	{58,	527},
-	{59,	521},
-	{60,	514},
-	{61,	508},
-	{62,	502},
-	{63,	496},
-	{64,	490},
-	{65,	485},
-	{66,	281},
-	{67,	274},
-	{68,	267},
-	{69,	260},
-	{70,	254},
-	{71,	247},
-	{72,	241},
-	{73,	235},
-	{74,	229},
-	{75,	224},
-	{76,	218},
-	{77,	213},
-	{78,	208},
-	{79,	203}
+	{10,	1244},
+	{20,	1228},
+	{30,	1212},
+	{40,	1195},
+	{50,	1179},
+	{60,	1162},
+	{70,	1146},
+	{80,	1129},
+	{90,	1113},
+	{100,	1097},
+	{110,	1080},
+	{120,	1064},
+	{130,	1048},
+	{140,	1032},
+	{150,	1016},
+	{160,	1000},
+	{170,	985},
+	{180,	969},
+	{190,	954},
+	{200,	939},
+	{210,	924},
+	{220,	909},
+	{230,	894},
+	{240,	880},
+	{250,	866},
+	{260,	852},
+	{270,	838},
+	{280,	824},
+	{290,	811},
+	{300,	798},
+	{310,	785},
+	{320,	773},
+	{330,	760},
+	{340,	748},
+	{350,	736},
+	{360,	725},
+	{370,	713},
+	{380,	702},
+	{390,	691},
+	{400,	681},
+	{410,	670},
+	{420,	660},
+	{430,	650},
+	{440,	640},
+	{450,	631},
+	{460,	622},
+	{470,	613},
+	{480,	604},
+	{490,	595},
+	{500,	587},
+	{510,	579},
+	{520,	571},
+	{530,	563},
+	{540,	556},
+	{550,	548},
+	{560,	541},
+	{570,	534},
+	{580,	527},
+	{590,	521},
+	{600,	514},
+	{610,	508},
+	{620,	502},
+	{630,	496},
+	{640,	490},
+	{650,	485},
+	{660,	281},
+	{670,	274},
+	{680,	267},
+	{690,	260},
+	{700,	254},
+	{710,	247},
+	{720,	241},
+	{730,	235},
+	{740,	229},
+	{750,	224},
+	{760,	218},
+	{770,	213},
+	{780,	208},
+	{790,	203}
 };
 
 static const struct pm8xxx_adc_map_pt adcmap_pa_therm[] = {
-	{41350,	-30},
-	{41282,	-29},
-	{41211,	-28},
-	{41137,	-27},
-	{41060,	-26},
-	{40980,	-25},
-	{40897,	-24},
-	{40811,	-23},
-	{40721,	-22},
-	{40629,	-21},
-	{40533,	-20},
-	{40434,	-19},
-	{40331,	-18},
-	{40226,	-17},
-	{40116,	-16},
-	{40004,	-15},
-	{39888,	-14},
-	{39769,	-13},
-	{39647,	-12},
-	{39521,	-11},
-	{39392,	-10},
-	{39260,	-9},
-	{39124,	-8},
-	{38986,	-7},
-	{38845,	-6},
-	{38700,	-5},
-	{38553,	-4},
-	{38403,	-3},
-	{38250,	-2},
-	{38094,	-1},
-	{37936,	0},
-	{37776,	1},
-	{37613,	2},
-	{37448,	3},
-	{37281,	4},
-	{37112,	5},
-	{36942,	6},
-	{36770,	7},
-	{36596,	8},
-	{36421,	9},
-	{36245,	10},
-	{36068,	11},
-	{35890,	12},
-	{35712,	13},
-	{35532,	14},
-	{35353,	15},
-	{35173,	16},
-	{34993,	17},
-	{34813,	18},
-	{34634,	19},
-	{34455,	20},
-	{34276,	21},
-	{34098,	22},
-	{33921,	23},
-	{33745,	24},
-	{33569,	25},
-	{33395,	26},
-	{33223,	27},
-	{33051,	28},
-	{32881,	29},
-	{32713,	30},
-	{32547,	31},
-	{32382,	32},
-	{32219,	33},
-	{32058,	34},
-	{31899,	35},
-	{31743,	36},
-	{31588,	37},
-	{31436,	38},
-	{31285,	39},
-	{31138,	40},
-	{30992,	41},
-	{30849,	42},
-	{30708,	43},
-	{30570,	44},
-	{30434,	45},
-	{30300,	46},
-	{30169,	47},
-	{30041,	48},
-	{29915,	49},
-	{29791,	50},
-	{29670,	51},
-	{29551,	52},
-	{29435,	53},
-	{29321,	54},
-	{29210,	55},
-	{29101,	56},
-	{28994,	57},
-	{28890,	58},
-	{28788,	59},
-	{28688,	60},
-	{28590,	61},
-	{28495,	62},
-	{28402,	63},
-	{28311,	64},
-	{28222,	65},
-	{28136,	66},
-	{28051,	67},
-	{27968,	68},
-	{27888,	69},
-	{27809,	70},
-	{27732,	71},
-	{27658,	72},
-	{27584,	73},
-	{27513,	74},
-	{27444,	75},
-	{27376,	76},
-	{27310,	77},
-	{27245,	78},
-	{27183,	79},
-	{27121,	80},
-	{27062,	81},
-	{27004,	82},
-	{26947,	83},
-	{26892,	84},
-	{26838,	85},
-	{26785,	86},
-	{26734,	87},
-	{26684,	88},
-	{26636,	89},
-	{26588,	90}
+	{1677,	-30},
+	{1671,	-29},
+	{1663,	-28},
+	{1656,	-27},
+	{1648,	-26},
+	{1640,	-25},
+	{1632,	-24},
+	{1623,	-23},
+	{1615,	-22},
+	{1605,	-21},
+	{1596,	-20},
+	{1586,	-19},
+	{1576,	-18},
+	{1565,	-17},
+	{1554,	-16},
+	{1543,	-15},
+	{1531,	-14},
+	{1519,	-13},
+	{1507,	-12},
+	{1494,	-11},
+	{1482,	-10},
+	{1468,	-9},
+	{1455,	-8},
+	{1441,	-7},
+	{1427,	-6},
+	{1412,	-5},
+	{1398,	-4},
+	{1383,	-3},
+	{1367,	-2},
+	{1352,	-1},
+	{1336,	0},
+	{1320,	1},
+	{1304,	2},
+	{1287,	3},
+	{1271,	4},
+	{1254,	5},
+	{1237,	6},
+	{1219,	7},
+	{1202,	8},
+	{1185,	9},
+	{1167,	10},
+	{1149,	11},
+	{1131,	12},
+	{1114,	13},
+	{1096,	14},
+	{1078,	15},
+	{1060,	16},
+	{1042,	17},
+	{1024,	18},
+	{1006,	19},
+	{988,	20},
+	{970,	21},
+	{952,	22},
+	{934,	23},
+	{917,	24},
+	{899,	25},
+	{882,	26},
+	{865,	27},
+	{848,	28},
+	{831,	29},
+	{814,	30},
+	{797,	31},
+	{781,	32},
+	{764,	33},
+	{748,	34},
+	{732,	35},
+	{717,	36},
+	{701,	37},
+	{686,	38},
+	{671,	39},
+	{656,	40},
+	{642,	41},
+	{627,	42},
+	{613,	43},
+	{599,	44},
+	{586,	45},
+	{572,	46},
+	{559,	47},
+	{546,	48},
+	{534,	49},
+	{522,	50},
+	{509,	51},
+	{498,	52},
+	{486,	53},
+	{475,	54},
+	{463,	55},
+	{452,	56},
+	{442,	57},
+	{431,	58},
+	{421,	59},
+	{411,	60},
+	{401,	61},
+	{392,	62},
+	{383,	63},
+	{374,	64},
+	{365,	65},
+	{356,	66},
+	{348,	67},
+	{339,	68},
+	{331,	69},
+	{323,	70},
+	{316,	71},
+	{308,	72},
+	{301,	73},
+	{294,	74},
+	{287,	75},
+	{280,	76},
+	{273,	77},
+	{267,	78},
+	{261,	79},
+	{255,	80},
+	{249,	81},
+	{243,	82},
+	{237,	83},
+	{232,	84},
+	{226,	85},
+	{221,	86},
+	{216,	87},
+	{211,	88},
+	{206,	89},
+	{201,	90}
 };
 
 static const struct pm8xxx_adc_map_pt adcmap_ntcg_104ef_104fb[] = {
@@ -458,42 +450,91 @@
 	return 0;
 }
 
+static int32_t pm8xxx_adc_map_batt_therm(const struct pm8xxx_adc_map_pt *pts,
+		uint32_t tablesize, int32_t input, int64_t *output)
+{
+	bool descending = 1;
+	uint32_t i = 0;
+
+	if ((pts == NULL) || (output == NULL))
+		return -EINVAL;
+
+	/* Check if table is descending or ascending */
+	if (tablesize > 1) {
+		if (pts[0].y < pts[1].y)
+			descending = 0;
+	}
+
+	while (i < tablesize) {
+		if ((descending == 1) && (pts[i].y < input)) {
+			/* table entry is less than measured
+				value and table is descending, stop */
+			break;
+		} else if ((descending == 0) && (pts[i].y > input)) {
+			/* table entry is greater than measured
+				value and table is ascending, stop */
+			break;
+		} else {
+			i++;
+		}
+	}
+
+	if (i == 0) {
+		*output = pts[0].x;
+	} else if (i == tablesize) {
+		*output = pts[tablesize-1].x;
+	} else {
+		/* result is between search_index and search_index-1 */
+		/* interpolate linearly */
+		*output = (((int32_t) ((pts[i].x - pts[i-1].x)*
+			(input - pts[i-1].y))/
+			(pts[i].y - pts[i-1].y))+
+			pts[i-1].x);
+	}
+
+	return 0;
+}
+
 int32_t pm8xxx_adc_scale_default(int32_t adc_code,
 		const struct pm8xxx_adc_properties *adc_properties,
 		const struct pm8xxx_adc_chan_properties *chan_properties,
 		struct pm8xxx_adc_chan_result *adc_chan_result)
 {
-	bool negative_rawfromoffset = 0;
-	int32_t rawfromoffset = 0;
+	bool negative_rawfromoffset = 0, negative_offset = 0;
+	int64_t scale_voltage = 0;
 
 	if (!chan_properties || !chan_properties->offset_gain_numerator ||
 		!chan_properties->offset_gain_denominator || !adc_properties
 		|| !adc_chan_result)
 		return -EINVAL;
 
-	rawfromoffset = adc_code -
-			chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
+	scale_voltage = (adc_code -
+		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
+	if (scale_voltage < 0) {
+		negative_offset = 1;
+		scale_voltage = -scale_voltage;
+	}
+	do_div(scale_voltage,
+		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		scale_voltage = -scale_voltage;
+	scale_voltage += chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
 
-	adc_chan_result->adc_code = adc_code;
-	if (rawfromoffset < 0) {
+	if (scale_voltage < 0) {
 		if (adc_properties->bipolar) {
-			rawfromoffset = -rawfromoffset;
+			scale_voltage = -scale_voltage;
 			negative_rawfromoffset = 1;
 		} else {
-			rawfromoffset = 0;
+			scale_voltage = 0;
 		}
 	}
 
-	if (rawfromoffset >= 1 << adc_properties->bitresolution)
-		rawfromoffset = (1 << adc_properties->bitresolution) - 1;
-
-	adc_chan_result->measurement = (int64_t)rawfromoffset *
-		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
+	adc_chan_result->measurement = scale_voltage *
 				chan_properties->offset_gain_denominator;
 
 	/* do_div only perform positive integer division! */
 	do_div(adc_chan_result->measurement,
-		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
 				chan_properties->offset_gain_numerator);
 
 	if (negative_rawfromoffset)
@@ -503,25 +544,52 @@
 	 * adc_properties.adc_reference. For generic channel processing,
 	 * channel measurement is a scale/ratio relative to the adc
 	 * reference input */
-	adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
+	adc_chan_result->physical = adc_chan_result->measurement;
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_default);
 
+static int64_t pm8xxx_adc_scale_ratiometric_calib(int32_t adc_code,
+		const struct pm8xxx_adc_properties *adc_properties,
+		const struct pm8xxx_adc_chan_properties *chan_properties)
+{
+	int64_t adc_voltage = 0;
+	bool negative_offset = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties)
+		return -EINVAL;
+
+	adc_voltage = (adc_code -
+		chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd)
+		* adc_properties->adc_vdd_reference;
+	if (adc_voltage < 0) {
+		negative_offset = 1;
+		adc_voltage = -adc_voltage;
+	}
+	do_div(adc_voltage,
+		chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy);
+	if (negative_offset)
+		adc_voltage = -adc_voltage;
+
+	return adc_voltage;
+}
+
 int32_t pm8xxx_adc_scale_batt_therm(int32_t adc_code,
 		const struct pm8xxx_adc_properties *adc_properties,
 		const struct pm8xxx_adc_chan_properties *chan_properties,
 		struct pm8xxx_adc_chan_result *adc_chan_result)
 {
-	/* Note: adc_chan_result->measurement is in the unit of
-		adc_properties.adc_reference */
-	adc_chan_result->measurement = adc_code;
-	/* convert mV ---> degC using the table */
-	return pm8xxx_adc_map_linear(
-			adcmap_batttherm,
-			ARRAY_SIZE(adcmap_batttherm),
-			adc_code,
+	int64_t bat_voltage = 0;
+
+	bat_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return pm8xxx_adc_map_batt_therm(
+			adcmap_btm_threshold,
+			ARRAY_SIZE(adcmap_btm_threshold),
+			bat_voltage,
 			&adc_chan_result->physical);
 }
 EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_batt_therm);
@@ -531,54 +599,74 @@
 		const struct pm8xxx_adc_chan_properties *chan_properties,
 		struct pm8xxx_adc_chan_result *adc_chan_result)
 {
-	/* Note: adc_chan_result->measurement is in the unit of
-		adc_properties.adc_reference */
-	adc_chan_result->measurement = adc_code;
-	/* convert mV ---> degC using the table */
+	int64_t pa_voltage = 0;
+
+	pa_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
 	return pm8xxx_adc_map_linear(
 			adcmap_pa_therm,
 			ARRAY_SIZE(adcmap_pa_therm),
-			adc_code,
+			pa_voltage,
 			&adc_chan_result->physical);
 }
 EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_pa_therm);
 
+int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
+		const struct pm8xxx_adc_properties *adc_properties,
+		const struct pm8xxx_adc_chan_properties *chan_properties,
+		struct pm8xxx_adc_chan_result *adc_chan_result)
+{
+	int64_t batt_id_voltage = 0;
+
+	batt_id_voltage = pm8xxx_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	adc_chan_result->physical = batt_id_voltage;
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_batt_id);
+
 int32_t pm8xxx_adc_scale_pmic_therm(int32_t adc_code,
 		const struct pm8xxx_adc_properties *adc_properties,
 		const struct pm8xxx_adc_chan_properties *chan_properties,
 		struct pm8xxx_adc_chan_result *adc_chan_result)
 {
-	int32_t rawfromoffset;
+	int64_t pmic_voltage = 0;
+	bool negative_offset = 0;
 
 	if (!chan_properties || !chan_properties->offset_gain_numerator ||
 		!chan_properties->offset_gain_denominator || !adc_properties
 		|| !adc_chan_result)
 		return -EINVAL;
 
-	adc_chan_result->adc_code = adc_code;
-	rawfromoffset = adc_code -
-			chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
-	if (rawfromoffset > 0) {
-		if (rawfromoffset >= 1 << adc_properties->bitresolution)
-			rawfromoffset = (1 << adc_properties->bitresolution)
-									- 1;
+	pmic_voltage = (adc_code -
+		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
+	if (pmic_voltage < 0) {
+		negative_offset = 1;
+		pmic_voltage = -pmic_voltage;
+	}
+	do_div(pmic_voltage,
+		chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		pmic_voltage = -pmic_voltage;
+	pmic_voltage += chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx;
+
+	if (pmic_voltage > 0) {
 		/* 2mV/K */
-		adc_chan_result->measurement = (int64_t)rawfromoffset*
-			chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
-			chan_properties->offset_gain_denominator * 1000;
+		adc_chan_result->measurement = pmic_voltage*
+			chan_properties->offset_gain_denominator;
 
 		do_div(adc_chan_result->measurement,
-			chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
-			chan_properties->offset_gain_numerator*2);
+			chan_properties->offset_gain_numerator * 2);
 	} else {
 		adc_chan_result->measurement = 0;
 	}
-	/* Note: adc_chan_result->measurement is in the unit of
-		adc_properties.adc_reference */
-	adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
 	/* Change to .001 deg C */
-	adc_chan_result->physical -= KELVINMIL_DEGMIL;
-	adc_chan_result->measurement <<= 1;
+	adc_chan_result->measurement -= KELVINMIL_DEGMIL;
+	adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
 
 	return 0;
 }
@@ -592,14 +680,19 @@
 		const struct pm8xxx_adc_chan_properties *chan_properties,
 		struct pm8xxx_adc_chan_result *adc_chan_result)
 {
-	int32_t rt_r25;
-	int32_t offset = chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
+	int64_t xo_thm = 0;
 
-	rt_r25 = adc_code - offset;
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
 
+	xo_thm = pm8xxx_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	xo_thm <<= 4;
 	pm8xxx_adc_map_linear(adcmap_ntcg_104ef_104fb,
 		ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
-		rt_r25, &adc_chan_result->physical);
+		xo_thm, &adc_chan_result->physical);
 
 	return 0;
 }
@@ -614,7 +707,7 @@
 	rc = pm8xxx_adc_map_linear(
 		adcmap_btm_threshold,
 		ARRAY_SIZE(adcmap_btm_threshold),
-		btm_param->low_thr_temp,
+		(btm_param->low_thr_temp),
 		&btm_param->low_thr_voltage);
 	if (rc)
 		return rc;
@@ -628,7 +721,7 @@
 	rc = pm8xxx_adc_map_linear(
 		adcmap_btm_threshold,
 		ARRAY_SIZE(adcmap_btm_threshold),
-		btm_param->high_thr_temp,
+		(btm_param->high_thr_temp),
 		&btm_param->high_thr_voltage);
 	if (rc)
 		return rc;
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 6b3aa0c..57d34b9 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -122,6 +122,7 @@
 #define PM8XXX_ADC_PA_THERM_VREG_UV_MAX			1800000
 #define PM8XXX_ADC_PA_THERM_VREG_UA_LOAD		100000
 #define PM8XXX_ADC_HWMON_NAME_LENGTH			32
+#define PM8XXX_ADC_BTM_INTERVAL_MAX			0x14
 
 struct pm8xxx_adc {
 	struct device				*dev;
@@ -344,12 +345,16 @@
 	if (rc < 0)
 		return rc;
 
+	rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_RSV, &data_arb_rsv);
+	if (rc < 0)
+		return rc;
+
 	data_arb_rsv &= (PM8XXX_ADC_ARB_USRP_RSV_RST |
 		PM8XXX_ADC_ARB_USRP_RSV_DTEST0 |
 		PM8XXX_ADC_ARB_USRP_RSV_DTEST1 |
-		PM8XXX_ADC_ARB_USRP_RSV_OP |
-		PM8XXX_ADC_ARB_USRP_RSV_TRM);
-	data_arb_rsv |= chan_prop->amux_ip_rsv << PM8XXX_ADC_RSV_IP_SEL;
+		PM8XXX_ADC_ARB_USRP_RSV_OP);
+	data_arb_rsv |= (chan_prop->amux_ip_rsv << PM8XXX_ADC_RSV_IP_SEL |
+				PM8XXX_ADC_ARB_USRP_RSV_TRM);
 
 	rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_RSV, data_arb_rsv);
 	if (rc < 0)
@@ -501,7 +506,7 @@
 {
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	struct pm8xxx_adc_amux_properties conv;
-	int rc, offset_adc, slope_adc, calib_read_1, calib_read_2;
+	int rc, calib_read_1, calib_read_2;
 	u8 data_arb_usrp_cntrl1 = 0;
 
 	conv.amux_channel = CHANNEL_125V;
@@ -564,18 +569,14 @@
 	}
 	pm8xxx_adc_calib_first_adc = false;
 
-	slope_adc = (((calib_read_1 - calib_read_2) << PM8XXX_ADC_MUL)/
-					PM8XXX_CHANNEL_ADC_625_MV);
-	offset_adc = calib_read_2 -
-			((slope_adc * PM8XXX_CHANNEL_ADC_625_MV) >>
-							PM8XXX_ADC_MUL);
-
-	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].offset
-								= offset_adc;
 	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dy =
 					(calib_read_1 - calib_read_2);
 	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dx
-						= PM8XXX_CHANNEL_ADC_625_MV;
+						= PM8XXX_CHANNEL_ADC_625_UV;
+	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_vref =
+					calib_read_1;
+	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd =
+					calib_read_2;
 	rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
 	if (rc < 0) {
 		pr_err("%s: Configuring ADC Arbiter disable"
@@ -643,14 +644,6 @@
 	}
 	pm8xxx_adc_calib_first_adc = false;
 
-	slope_adc = (((calib_read_1 - calib_read_2) << PM8XXX_ADC_MUL)/
-				adc_pmic->adc_prop->adc_vdd_reference);
-	offset_adc = calib_read_2 -
-			((slope_adc * adc_pmic->adc_prop->adc_vdd_reference)
-							>> PM8XXX_ADC_MUL);
-
-	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].offset
-								= offset_adc;
 	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dy =
 					(calib_read_1 - calib_read_2);
 	adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dx =
@@ -843,6 +836,12 @@
 		return rc;
 	}
 
+	if (btm_param->interval > PM8XXX_ADC_BTM_INTERVAL_MAX) {
+		pr_info("Bug in PMIC BTM interval time and cannot set"
+		" a value greater than 0x14 %x\n", btm_param->interval);
+		btm_param->interval = PM8XXX_ADC_BTM_INTERVAL_MAX;
+	}
+
 	spin_lock_irqsave(&adc_pmic->btm_lock, flags);
 
 	data_btm_cool_thr0 = ((btm_param->low_thr_voltage << 24) >> 24);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 8a65df4..fd5fcd2 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2979,9 +2979,11 @@
 {
 	int retval;
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
-	if (tuner->index > 0)
-		return -EINVAL;
 
+	if (tuner->index > 0) {
+		FMDERR("Invalid Tuner Index");
+		return -EINVAL;
+	}
 	if (radio->mode == FM_RECV) {
 		retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
 		if (retval < 0) {
@@ -3057,16 +3059,12 @@
 		struct v4l2_frequency *freq)
 {
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
-
-	freq->type = V4L2_TUNER_RADIO;
-	retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
-	if (retval < 0)
-		FMDERR("get frequency failed %d\n", retval);
-	else
+	if ((freq != NULL) && (radio != NULL)) {
 		freq->frequency =
 			radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
-	return retval;
+	} else
+		return -EINVAL;
+	return 0;
 }
 
 static int iris_vidioc_s_frequency(struct file *file, void *priv,
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 251f12d..579c4d5 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -2407,6 +2407,7 @@
 	adapter = NULL;
 probe_fail:
 	actctrl->a_init_table = NULL;
+	actctrl->a_power_up = NULL;
 	actctrl->a_power_down = NULL;
 	actctrl->a_config = NULL;
 	actctrl->a_create_subdevice = NULL;
diff --git a/drivers/media/video/msm/msm_io_vfe31.c b/drivers/media/video/msm/msm_io_vfe31.c
index 91dbc8f..0f93882 100644
--- a/drivers/media/video/msm/msm_io_vfe31.c
+++ b/drivers/media/video/msm/msm_io_vfe31.c
@@ -480,7 +480,6 @@
 int msm_camio_enable(struct platform_device *pdev)
 {
 	int rc = 0;
-	uint32_t val;
 	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
 	msm_camio_clk_enable(CAMIO_VFE_PBDG_CLK);
 	if (!sinfo->csi_if)
@@ -507,23 +506,6 @@
 		msm_camio_clk_enable(CAMIO_CSI0_PCLK);
 		msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
 		msm_camio_clk_enable(CAMIO_CSI0_CLK);
-
-		msleep(10);
-		val = (20 <<
-			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
-			(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
-			(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
-			(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
-		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
-
-		val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
-			(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
-		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
-		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
 	}
 	return 0;
 csi_irq_fail:
@@ -536,42 +518,37 @@
 	return rc;
 }
 
+static void msm_camio_csi_disable(void)
+{
+	uint32_t val;
+	val = 0x0;
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+	usleep_range(9000, 10000);
+	free_irq(camio_ext.csiirq, 0);
+	iounmap(csibase);
+	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+}
+
 void msm_camio_disable(struct platform_device *pdev)
 {
 	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	uint32_t val;
 	if (!sinfo->csi_if) {
 		msm_camio_clk_disable(CAMIO_VFE_CAMIF_CLK);
 	} else {
-		val = (0x0 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
-		(0x0<<MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT)|
-		(0x0 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
-		(0x0 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
-		CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
-		msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
-
-		val = (20 <<
-			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
-			(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
-			(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
-			(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
-		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
-		msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
-		val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
-			(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
-		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
-		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
-		msleep(10);
-		free_irq(camio_ext.csiirq, 0);
+		CDBG("disable mipi\n");
+		msm_camio_csi_disable();
+		CDBG("disable clocks\n");
 		msm_camio_clk_disable(CAMIO_CSI0_PCLK);
 		msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
 		msm_camio_clk_disable(CAMIO_CSI0_CLK);
 		msm_camio_clk_disable(CAMIO_VFE_CLK);
-		iounmap(csibase);
-		release_mem_region(camio_ext.csiphy, camio_ext.csisz);
 	}
 	msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
 }
@@ -725,8 +702,9 @@
 {
 	int rc = 0;
 	uint32_t val = 0;
+	int i;
 
-	CDBG("msm_camio_csi_config \n");
+	CDBG("msm_camio_csi_config\n");
 
 	/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
 	msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
@@ -763,11 +741,8 @@
 		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
 		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
 	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
-
+	for (i = 0; i < csi_params->lane_cnt; i++)
+		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2 + i * 4);
 
 	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
 		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 8d502da..689a614 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -543,6 +543,15 @@
 			goto msm_open_done;
 		}
 
+		if (sync->actctrl.a_power_up)
+			rc = sync->actctrl.a_power_up(
+				sync->sdata->actuator_info);
+
+		if (rc < 0) {
+			pr_err("%s: act power failed:%d\n", __func__, rc);
+			goto msm_open_done;
+		}
+
 		pm_qos_add_request(&p_mctl->pm_qos_req_list,
 					PM_QOS_CPU_DMA_LATENCY,
 					PM_QOS_DEFAULT_VALUE);
@@ -576,7 +585,7 @@
 		VIDIOC_MSM_CSIPHY_RELEASE, NULL);
 
 	if (p_mctl->sync.actctrl.a_power_down)
-		p_mctl->sync.actctrl.a_power_down();
+		p_mctl->sync.actctrl.a_power_down(sync->sdata->actuator_info);
 
 	if (p_mctl->sync.sctrl.s_release)
 		p_mctl->sync.sctrl.s_release();
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 16bec18..3a7faa2 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -543,6 +543,7 @@
 	vpe_ctrl->fs_vpe = NULL;
 vpe_fs_failed:
 	disable_irq(vpe_ctrl->vpeirq->start);
+	vpe_ctrl->state = VPE_STATE_IDLE;
 	return rc;
 }
 
@@ -578,9 +579,11 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&vpe_ctrl->lock, flags);
-	if (vpe_ctrl->state == VPE_STATE_ACTIVE) {
+	if (vpe_ctrl->state == VPE_STATE_ACTIVE ||
+		 vpe_ctrl->state == VPE_STATE_IDLE) {
 		spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
-		pr_err(" =====VPE is busy!!!  Wrong!========\n");
+		pr_err(" =====VPE in wrong state:%d!!!  Wrong!========\n",
+		vpe_ctrl->state);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index a73a695..7314c7e 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/delay.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/misc.h>
 
@@ -131,6 +132,10 @@
 #define UART_PATH_SEL_MASK			0x60
 #define UART_PATH_SEL_SHIFT			0x5
 
+/* Shutdown/restart delays to allow for LDO 7/dVdd regulator load settling. */
+#define PM8901_DELAY_AFTER_REG_DISABLE_MS	4
+#define PM8901_DELAY_BEFORE_SHUTDOWN_MS		8
+
 struct pm8xxx_misc_chip {
 	struct list_head			link;
 	struct pm8xxx_misc_platform_data	pdata;
@@ -420,10 +425,12 @@
 					"rc=%d\n", rc);
 				goto read_write_err;
 			}
+			mdelay(PM8901_DELAY_AFTER_REG_DISABLE_MS);
 		}
 	}
 
 read_write_err:
+	mdelay(PM8901_DELAY_BEFORE_SHUTDOWN_MS);
 	return rc;
 }
 
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index ae721e4..7c56dd6 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -42,15 +42,6 @@
 #define REG_TEMP_ALRM_CTRL		0x1B
 #define REG_TEMP_ALRM_PWM		0x9B
 
-/* PON CNTL 1 register */
-#define SSBI_REG_ADDR_PON_CNTL_1	0x01C
-
-#define PM8058_PON_PUP_MASK		0xF0
-
-#define PM8058_PON_WD_EN_MASK		0x08
-#define PM8058_PON_WD_EN_RESET		0x08
-#define PM8058_PON_WD_EN_PWR_OFF	0x00
-
 /* PON CNTL 4 register */
 #define SSBI_REG_ADDR_PON_CNTL_4 0x98
 #define PM8058_PON_RESET_EN_MASK 0x01
@@ -59,60 +50,6 @@
 #define SSBI_REG_ADDR_PON_CNTL_5 0x7B
 #define PM8058_HARD_RESET_EN_MASK 0x08
 
-/* Regulator master enable addresses */
-#define SSBI_REG_ADDR_VREG_EN_MSM	0x018
-#define SSBI_REG_ADDR_VREG_EN_GRP_5_4	0x1C8
-
-/* Regulator control registers for shutdown/reset */
-#define SSBI_REG_ADDR_S0_CTRL		0x004
-#define SSBI_REG_ADDR_S1_CTRL		0x005
-#define SSBI_REG_ADDR_S3_CTRL		0x111
-#define SSBI_REG_ADDR_L21_CTRL		0x120
-#define SSBI_REG_ADDR_L22_CTRL		0x121
-
-#define REGULATOR_ENABLE_MASK		0x80
-#define REGULATOR_ENABLE		0x80
-#define REGULATOR_DISABLE		0x00
-#define REGULATOR_PULL_DOWN_MASK	0x40
-#define REGULATOR_PULL_DOWN_EN		0x40
-#define REGULATOR_PULL_DOWN_DIS		0x00
-
-/* Buck CTRL register */
-#define SMPS_LEGACY_VREF_SEL		0x20
-#define SMPS_LEGACY_VPROG_MASK		0x1F
-#define SMPS_ADVANCED_BAND_MASK		0xC0
-#define SMPS_ADVANCED_BAND_SHIFT	6
-#define SMPS_ADVANCED_VPROG_MASK	0x3F
-
-/* Buck TEST2 registers for shutdown/reset */
-#define SSBI_REG_ADDR_S0_TEST2		0x084
-#define SSBI_REG_ADDR_S1_TEST2		0x085
-#define SSBI_REG_ADDR_S3_TEST2		0x11A
-
-#define REGULATOR_BANK_WRITE		0x80
-#define REGULATOR_BANK_MASK		0x70
-#define REGULATOR_BANK_SHIFT		4
-#define REGULATOR_BANK_SEL(n)		((n) << REGULATOR_BANK_SHIFT)
-
-/* Buck TEST2 register bank 1 */
-#define SMPS_LEGACY_VLOW_SEL		0x01
-
-/* Buck TEST2 register bank 7 */
-#define SMPS_ADVANCED_MODE_MASK		0x02
-#define SMPS_ADVANCED_MODE		0x02
-#define SMPS_LEGACY_MODE		0x00
-
-/* SLEEP CNTL register */
-#define SSBI_REG_ADDR_SLEEP_CNTL	0x02B
-
-#define PM8058_SLEEP_SMPL_EN_MASK	0x04
-#define PM8058_SLEEP_SMPL_EN_RESET	0x04
-#define PM8058_SLEEP_SMPL_EN_PWR_OFF	0x00
-
-#define PM8058_SLEEP_SMPL_SEL_MASK	0x03
-#define PM8058_SLEEP_SMPL_SEL_MIN	0
-#define PM8058_SLEEP_SMPL_SEL_MAX	3
-
 /* GP_TEST1 register */
 #define SSBI_REG_ADDR_GP_TEST_1		0x07A
 
@@ -154,322 +91,6 @@
 	return msm_ssbi_write(dev->parent, addr, buf, len);
 }
 
-static int pm8058_masked_write(u16 addr, u8 val, u8 mask)
-{
-	int rc;
-	u8 reg;
-
-	if (pmic_chip == NULL)
-		return -ENODEV;
-
-	rc = ssbi_read(pmic_chip->dev, addr, &reg, 1);
-	if (rc) {
-		pr_err("%s: ssbi_read(0x%03X) failed: rc=%d\n", __func__, addr,
-			rc);
-		goto done;
-	}
-
-	reg &= ~mask;
-	reg |= val & mask;
-
-	rc = ssbi_write(pmic_chip->dev, addr, &reg, 1);
-	if (rc)
-		pr_err("%s: ssbi_write(0x%03X)=0x%02X failed: rc=%d\n",
-			__func__, addr, reg, rc);
-done:
-	return rc;
-}
-
-/**
- * pm8058_smpl_control - enables/disables SMPL detection
- * @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
- *
- * This function enables or disables the Sudden Momentary Power Loss detection
- * module.  If SMPL detection is enabled, then when a sufficiently long power
- * loss event occurs, the PMIC will automatically reset itself.  If SMPL
- * detection is disabled, then the PMIC will shutdown when power loss occurs.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_smpl_control(int enable)
-{
-	return pm8058_masked_write(SSBI_REG_ADDR_SLEEP_CNTL,
-				   (enable ? PM8058_SLEEP_SMPL_EN_RESET
-					   : PM8058_SLEEP_SMPL_EN_PWR_OFF),
-				   PM8058_SLEEP_SMPL_EN_MASK);
-}
-EXPORT_SYMBOL(pm8058_smpl_control);
-
-/**
- * pm8058_smpl_set_delay - sets the SMPL detection time delay
- * @delay: enum value corresponding to delay time
- *
- * This function sets the time delay of the SMPL detection module.  If power
- * is reapplied within this interval, then the PMIC reset automatically.  The
- * SMPL detection module must be enabled for this delay time to take effect.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_smpl_set_delay(enum pm8058_smpl_delay delay)
-{
-	if (delay < PM8058_SLEEP_SMPL_SEL_MIN
-	    || delay > PM8058_SLEEP_SMPL_SEL_MAX) {
-		pr_err("%s: invalid delay specified: %d\n", __func__, delay);
-		return -EINVAL;
-	}
-
-	return pm8058_masked_write(SSBI_REG_ADDR_SLEEP_CNTL, delay,
-				   PM8058_SLEEP_SMPL_SEL_MASK);
-}
-EXPORT_SYMBOL(pm8058_smpl_set_delay);
-
-/**
- * pm8058_watchdog_reset_control - enables/disables watchdog reset detection
- * @enable: 0 = shutdown when PS_HOLD goes low, 1 = reset when PS_HOLD goes low
- *
- * This function enables or disables the PMIC watchdog reset detection feature.
- * If watchdog reset detection is enabled, then the PMIC will reset itself
- * when PS_HOLD goes low.  If it is not enabled, then the PMIC will shutdown
- * when PS_HOLD goes low.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_watchdog_reset_control(int enable)
-{
-	return pm8058_masked_write(SSBI_REG_ADDR_PON_CNTL_1,
-				   (enable ? PM8058_PON_WD_EN_RESET
-					   : PM8058_PON_WD_EN_PWR_OFF),
-				   PM8058_PON_WD_EN_MASK);
-}
-EXPORT_SYMBOL(pm8058_watchdog_reset_control);
-
-/*
- * Set an SMPS regulator to be disabled in its CTRL register, but enabled
- * in the master enable register.  Also set it's pull down enable bit.
- * Take care to make sure that the output voltage doesn't change if switching
- * from advanced mode to legacy mode.
- */
-static int disable_smps_locally_set_pull_down(u16 ctrl_addr, u16 test2_addr,
-		u16 master_enable_addr, u8 master_enable_bit)
-{
-	int rc = 0;
-	u8 vref_sel, vlow_sel, band, vprog, bank, reg;
-
-	if (pmic_chip == NULL)
-		return -ENODEV;
-
-	bank = REGULATOR_BANK_SEL(7);
-	rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
-			test2_addr, rc);
-		goto done;
-	}
-
-	rc = ssbi_read(pmic_chip->dev, test2_addr, &reg, 1);
-	if (rc) {
-		pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
-		       __func__, test2_addr, rc);
-		goto done;
-	}
-
-	/* Check if in advanced mode. */
-	if ((reg & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE) {
-		/* Determine current output voltage. */
-		rc = ssbi_read(pmic_chip->dev, ctrl_addr, &reg, 1);
-		if (rc) {
-			pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
-			       __func__, ctrl_addr, rc);
-			goto done;
-		}
-
-		band = (reg & SMPS_ADVANCED_BAND_MASK)
-			>> SMPS_ADVANCED_BAND_SHIFT;
-		switch (band) {
-		case 3:
-			vref_sel = 0;
-			vlow_sel = 0;
-			break;
-		case 2:
-			vref_sel = SMPS_LEGACY_VREF_SEL;
-			vlow_sel = 0;
-			break;
-		case 1:
-			vref_sel = SMPS_LEGACY_VREF_SEL;
-			vlow_sel = SMPS_LEGACY_VLOW_SEL;
-			break;
-		default:
-			pr_err("%s: regulator already disabled\n", __func__);
-			return -EPERM;
-		}
-		vprog = (reg & SMPS_ADVANCED_VPROG_MASK);
-		/* Round up if fine step is in use. */
-		vprog = (vprog + 1) >> 1;
-		if (vprog > SMPS_LEGACY_VPROG_MASK)
-			vprog = SMPS_LEGACY_VPROG_MASK;
-
-		/* Set VLOW_SEL bit. */
-		bank = REGULATOR_BANK_SEL(1);
-		rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
-		if (rc) {
-			pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n",
-			       __func__, test2_addr, rc);
-			goto done;
-		}
-		rc = pm8058_masked_write(test2_addr,
-			REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1)
-				| vlow_sel,
-			REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
-				| SMPS_LEGACY_VLOW_SEL);
-		if (rc)
-			goto done;
-
-		/* Switch to legacy mode */
-		bank = REGULATOR_BANK_SEL(7);
-		rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
-		if (rc) {
-			pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
-				test2_addr, rc);
-			goto done;
-		}
-		rc = pm8058_masked_write(test2_addr,
-				REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7)
-					| SMPS_LEGACY_MODE,
-				REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
-					| SMPS_ADVANCED_MODE_MASK);
-		if (rc)
-			goto done;
-
-		/* Enable locally, enable pull down, keep voltage the same. */
-		rc = pm8058_masked_write(ctrl_addr,
-			REGULATOR_ENABLE | REGULATOR_PULL_DOWN_EN
-				| vref_sel | vprog,
-			REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK
-			       | SMPS_LEGACY_VREF_SEL | SMPS_LEGACY_VPROG_MASK);
-		if (rc)
-			goto done;
-	}
-
-	/* Enable in master control register. */
-	rc = pm8058_masked_write(master_enable_addr, master_enable_bit,
-				 master_enable_bit);
-	if (rc)
-		goto done;
-
-	/* Disable locally and enable pull down. */
-	rc = pm8058_masked_write(ctrl_addr,
-		REGULATOR_DISABLE | REGULATOR_PULL_DOWN_EN,
-		REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK);
-
-done:
-	return rc;
-}
-
-static int disable_ldo_locally_set_pull_down(u16 ctrl_addr,
-		u16 master_enable_addr, u8 master_enable_bit)
-{
-	int rc;
-
-	/* Enable LDO in master control register. */
-	rc = pm8058_masked_write(master_enable_addr, master_enable_bit,
-				 master_enable_bit);
-	if (rc)
-		goto done;
-
-	/* Disable LDO in CTRL register and set pull down */
-	rc = pm8058_masked_write(ctrl_addr,
-		REGULATOR_DISABLE | REGULATOR_PULL_DOWN_EN,
-		REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK);
-
-done:
-	return rc;
-}
-
-int pm8058_reset_pwr_off(int reset)
-{
-	int rc;
-	u8 pon, ctrl, smpl;
-
-	if (pmic_chip == NULL)
-		return -ENODEV;
-
-	/* When shutting down, enable active pulldowns on important rails. */
-	if (!reset) {
-		/* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */
-		disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S0_CTRL,
-		     SSBI_REG_ADDR_S0_TEST2, SSBI_REG_ADDR_VREG_EN_MSM, BIT(7));
-		disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S1_CTRL,
-		     SSBI_REG_ADDR_S1_TEST2, SSBI_REG_ADDR_VREG_EN_MSM, BIT(6));
-		disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S3_CTRL,
-		     SSBI_REG_ADDR_S3_TEST2, SSBI_REG_ADDR_VREG_EN_GRP_5_4,
-		     BIT(7) | BIT(4));
-		/* Disable LDO 21 locally and set pulldown enable bit. */
-		disable_ldo_locally_set_pull_down(SSBI_REG_ADDR_L21_CTRL,
-		     SSBI_REG_ADDR_VREG_EN_GRP_5_4, BIT(1));
-	}
-
-	/* Set regulator L22 to 1.225V in high power mode. */
-	rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n", __func__,
-			SSBI_REG_ADDR_L22_CTRL, rc);
-		goto get_out3;
-	}
-	/* Leave pull-down state intact. */
-	ctrl &= 0x40;
-	ctrl |= 0x93;
-	rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
-	if (rc)
-		pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n", __func__,
-			SSBI_REG_ADDR_L22_CTRL, ctrl, rc);
-
-get_out3:
-	if (!reset) {
-		/* Only modify the SLEEP_CNTL reg if shutdown is desired. */
-		rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_SLEEP_CNTL,
-			       &smpl, 1);
-		if (rc) {
-			pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
-			       __func__, SSBI_REG_ADDR_SLEEP_CNTL, rc);
-			goto get_out2;
-		}
-
-		smpl &= ~PM8058_SLEEP_SMPL_EN_MASK;
-		smpl |= PM8058_SLEEP_SMPL_EN_PWR_OFF;
-
-		rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_SLEEP_CNTL,
-				&smpl, 1);
-		if (rc)
-			pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
-			       __func__, SSBI_REG_ADDR_SLEEP_CNTL, smpl, rc);
-	}
-
-get_out2:
-	rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_1, rc);
-		goto get_out;
-	}
-
-	pon &= ~PM8058_PON_WD_EN_MASK;
-	pon |= reset ? PM8058_PON_WD_EN_RESET : PM8058_PON_WD_EN_PWR_OFF;
-
-	/* Enable all pullups */
-	pon |= PM8058_PON_PUP_MASK;
-
-	rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_1, pon, rc);
-		goto get_out;
-	}
-
-get_out:
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_reset_pwr_off);
-
 /**
  * pm8058_stay_on - enables stay_on feature
  *
diff --git a/drivers/mfd/pmic8901.c b/drivers/mfd/pmic8901.c
index 9e8786e..080a3e3 100644
--- a/drivers/mfd/pmic8901.c
+++ b/drivers/mfd/pmic8901.c
@@ -13,7 +13,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
 #include <linux/mfd/core.h>
 #include <linux/msm_ssbi.h>
 #include <linux/mfd/pmic8901.h>
@@ -31,19 +30,6 @@
 #define REG_TEMP_ALRM_CTRL		0x23
 #define REG_TEMP_ALRM_PWM		0x24
 
-/* FTS regulator PMR registers */
-#define SSBI_REG_ADDR_S1_PMR		(0xA7)
-#define SSBI_REG_ADDR_S2_PMR		(0xA8)
-#define SSBI_REG_ADDR_S3_PMR		(0xA9)
-#define SSBI_REG_ADDR_S4_PMR		(0xAA)
-
-#define REGULATOR_PMR_STATE_MASK	0x60
-#define REGULATOR_PMR_STATE_OFF		0x20
-
-/* Shutdown/restart delays to allow for LDO 7/dVdd regulator load settling. */
-#define DELAY_AFTER_REG_DISABLE_MS	4
-#define DELAY_BEFORE_SHUTDOWN_MS	8
-
 #define SINGLE_IRQ_RESOURCE(_name, _irq) \
 { \
 	.name	= _name, \
@@ -60,63 +46,6 @@
 	u8				revision;
 };
 
-static struct pm8901_chip *pmic_chip;
-
-static inline int
-ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
-	return msm_ssbi_read(dev->parent, addr, buf, len);
-}
-
-static inline int
-ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
-	return msm_ssbi_write(dev->parent, addr, buf, len);
-}
-
-int pm8901_reset_pwr_off(int reset)
-{
-	int rc = 0, i;
-	u8 pmr;
-	u8 pmr_addr[4] = {
-		SSBI_REG_ADDR_S2_PMR,
-		SSBI_REG_ADDR_S3_PMR,
-		SSBI_REG_ADDR_S4_PMR,
-		SSBI_REG_ADDR_S1_PMR,
-	};
-
-	if (pmic_chip == NULL)
-		return -ENODEV;
-
-	/* Turn off regulators S1, S2, S3, S4 when shutting down. */
-	if (!reset) {
-		for (i = 0; i < 4; i++) {
-			rc = ssbi_read(pmic_chip->dev, pmr_addr[i], &pmr, 1);
-			if (rc) {
-				pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
-				       __func__, pmr_addr[i], rc);
-				goto get_out;
-			}
-
-			pmr &= ~REGULATOR_PMR_STATE_MASK;
-			pmr |= REGULATOR_PMR_STATE_OFF;
-
-			rc = ssbi_write(pmic_chip->dev, pmr_addr[i], &pmr, 1);
-			if (rc) {
-				pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d"
-				       "\n", __func__, pmr_addr[i], pmr, rc);
-				goto get_out;
-			}
-			mdelay(DELAY_AFTER_REG_DISABLE_MS);
-		}
-	}
-
-get_out:
-	mdelay(DELAY_BEFORE_SHUTDOWN_MS);
-	return rc;
-}
-EXPORT_SYMBOL(pm8901_reset_pwr_off);
-
 static int pm8901_readb(const struct device *dev, u16 addr, u8 *val)
 {
 	const struct pm8xxx_drvdata *pm8901_drvdata = dev_get_drvdata(dev);
@@ -191,6 +120,11 @@
 	.pmic_get_revision	= pm8901_get_revision,
 };
 
+static struct mfd_cell misc_cell = {
+	.name		= PM8XXX_MISC_DEV_NAME,
+	.id		= 1,
+};
+
 static struct mfd_cell debugfs_cell = {
 	.name		= "pm8xxx-debug",
 	.id		= 1,
@@ -315,6 +249,17 @@
 		goto bail;
 	}
 
+	if (pdata->misc_pdata) {
+		misc_cell.platform_data = pdata->misc_pdata;
+		misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
+		rc = mfd_add_devices(pmic->dev, 0, &misc_cell, 1, NULL,
+				      irq_base);
+		if (rc) {
+			pr_err("Failed to add  misc subdevice ret=%d\n", rc);
+			goto bail;
+		}
+	}
+
 	return rc;
 
 bail:
@@ -346,7 +291,6 @@
 
 	pm8901_drvdata.pm_chip_data = pmic;
 	platform_set_drvdata(pdev, &pm8901_drvdata);
-	pmic_chip = pmic;
 
 	/* Read PMIC chip revision */
 	rc = pm8901_readb(pmic->dev, PM8901_REG_REV, &pmic->revision);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index eeca25a..0410473 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -138,8 +138,7 @@
 	unsigned short ret = NR_SG;
 
 	if (host->is_sps_mode) {
-		if (NR_SG > MAX_NR_SG_SPS)
-			ret = MAX_NR_SG_SPS;
+		ret = SPS_MAX_DESCS;
 	} else { /* DMA or PIO mode */
 		if (NR_SG > MAX_NR_SG_DMA_PIO)
 			ret = MAX_NR_SG_DMA_PIO;
@@ -148,28 +147,6 @@
 	return ret;
 }
 
-static inline unsigned int msmsdcc_get_max_seg_size(struct msmsdcc_host *host)
-{
-	unsigned int max_seg_size;
-
-	/*
-	 * SPS BAM has limitation of max. number of descriptors.
-	 * max. # of descriptors = SPS_MAX_DESCS
-	 * each descriptor can point to SPS_MAX_DESC_SIZE (16KB)
-	 * So (nr_sg * max_seg_size) should be limited to the
-	 * max. size that all of the descriptors can point to.
-	 * i.e., (nr_sg * max_seg_size) = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE).
-	 */
-	if (host->is_sps_mode) {
-		max_seg_size = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE) /
-			msmsdcc_get_nr_sg(host);
-	} else { /* DMA or PIO mode */
-		max_seg_size = MMC_MAX_REQ_SIZE;
-	}
-
-	return max_seg_size;
-}
-
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
 				struct msmsdcc_sps_ep_conn_data *ep);
@@ -4009,7 +3986,7 @@
 	mmc->max_blk_count = MMC_MAX_BLK_CNT;
 
 	mmc->max_req_size = MMC_MAX_REQ_SIZE;
-	mmc->max_seg_size = msmsdcc_get_max_seg_size(host);
+	mmc->max_seg_size = mmc->max_req_size;
 
 	writel_relaxed(0, host->base + MMCIMASK0);
 	writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
@@ -4661,7 +4638,7 @@
 		       size_t count, loff_t *ppos)
 {
 	struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
-	char buf[1024];
+	char buf[200];
 	int max, i;
 
 	i = 0;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index a8332e51..d128984 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -242,8 +242,6 @@
 /* Each descriptor is of length 8 bytes */
 #define SPS_MAX_DESC_LENGTH	8
 #define SPS_MAX_DESCS		(SPS_MAX_DESC_FIFO_SIZE / SPS_MAX_DESC_LENGTH)
-#define SPS_MAX_SG_DESCS	(MAX_SG_SIZE / SPS_MAX_DESC_SIZE)
-#define MAX_NR_SG_SPS		(SPS_MAX_DESCS / SPS_MAX_SG_DESCS)
 
 /*
  * DMA limitations
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 3f92731..f1af222 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1192,7 +1192,7 @@
 static void __exit cleanup_mtdchar(void)
 {
 	unregister_mtd_user(&mtdchar_notifier);
-	mntput(mtd_inode_mnt);
+	kern_unmount(mtd_inode_mnt);
 	unregister_filesystem(&mtd_inodefs_type);
 	__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
 }
diff --git a/drivers/net/qfec.c b/drivers/net/qfec.c
index d554fec..fc27837 100644
--- a/drivers/net/qfec.c
+++ b/drivers/net/qfec.c
@@ -33,17 +33,20 @@
 #include "qfec.h"
 
 #define QFEC_NAME       "qfec"
-#define QFEC_DRV_VER    "July 14 2011"
+#define QFEC_DRV_VER    "Nov 29 2011"
 
 #define ETH_BUF_SIZE    0x600
 #define MAX_N_BD        50
 #define MAC_ADDR_SIZE	6
 
 #define RX_TX_BD_RATIO  8
-#define RX_BD_NUM       32
-#define TX_BD_NUM       (RX_BD_NUM * RX_TX_BD_RATIO)
+#define TX_BD_NUM       256
+#define RX_BD_NUM       256
 #define TX_BD_TI_RATIO  4
+#define MAX_MDIO_REG    32
 
+#define H_DPLX     0
+#define F_DPLX     1
 /*
  * logging macros
  */
@@ -52,6 +55,8 @@
 #define QFEC_LOG_DBG2   4
 #define QFEC_LOG_MDIO_W 8
 #define QFEC_LOG_MDIO_R 16
+#define QFEC_MII_EXP_MASK (EXPANSION_LCWP | EXPANSION_ENABLENPAGE \
+							| EXPANSION_NPCAPABLE)
 
 static int qfec_debug = QFEC_LOG_PR;
 
@@ -297,13 +302,15 @@
 
 static inline void qfec_ring_head_adv(struct ring *p_ring)
 {
-	p_ring->head = ++p_ring->head % p_ring->len;
+	if (++p_ring->head == p_ring->len)
+		p_ring->head = 0;
 	p_ring->n_free--;
 };
 
 static inline void qfec_ring_tail_adv(struct ring *p_ring)
 {
-	p_ring->tail = ++p_ring->tail % p_ring->len;
+	if (++p_ring->tail == p_ring->len)
+		p_ring->tail = 0;
 	p_ring->n_free++;
 };
 
@@ -809,6 +816,13 @@
 	qfec_reg_write(priv, STATUS_REG, INTRP_EN_REG_NIE | INTRP_EN_REG_RIE
 		| INTRP_EN_REG_TIE | INTRP_EN_REG_TUE | INTRP_EN_REG_ETE);
 
+	if (priv->mii.supports_gmii) {
+		/* Clear RGMII */
+		qfec_reg_read(priv, SG_RG_SMII_STATUS_REG);
+		/* Disable RGMII int */
+		qfec_reg_write(priv, INTRP_MASK_REG, 1);
+	}
+
 	return res;
 }
 
@@ -874,9 +888,9 @@
  * configure the PHY interface and clock routing and signal bits
  */
 enum phy_intfc  {
-	intfc_mii     = 0,
-	intfc_rgmii   = 1,
-	intfc_revmii  = 2,
+	INTFC_MII     = 0,
+	INTFC_RGMII   = 1,
+	INTFC_REVMII  = 2,
 };
 
 static int qfec_intf_sel(struct qfec_priv *priv, unsigned int intfc)
@@ -885,7 +899,7 @@
 
 	QFEC_LOG(QFEC_LOG_DBG2, "%s: %d\n", __func__, intfc);
 
-	if (intfc > intfc_revmii)  {
+	if (intfc > INTFC_REVMII)  {
 		QFEC_LOG_ERR("%s: range\n", __func__);
 		return -ENXIO;
 	}
@@ -972,9 +986,9 @@
 };
 
 enum speed  {
-	spd_10   = 0,
-	spd_100  = 1,
-	spd_1000 = 2,
+	SPD_10   = 0,
+	SPD_100  = 1,
+	SPD_1000 = 2,
 };
 
 /*
@@ -988,7 +1002,7 @@
 
 	QFEC_LOG(QFEC_LOG_DBG2, "%s: %d spd, %d dplx\n", __func__, spd, dplx);
 
-	if (spd > spd_1000)  {
+	if (spd > SPD_1000)  {
 		QFEC_LOG_ERR("%s: range\n", __func__);
 		return -ENODEV;
 	}
@@ -999,7 +1013,7 @@
 	qfec_reg_write(priv, MAC_CONFIG_REG,
 	(qfec_reg_read(priv, MAC_CONFIG_REG)
 		& ~(MAC_CONFIG_REG_SPD | MAC_CONFIG_REG_DM))
-			| p->spd | (dplx ? MAC_CONFIG_REG_DM : 0));
+			| p->spd | (dplx ? MAC_CONFIG_REG_DM : H_DPLX));
 
 	qfec_clkreg_write(priv, ETH_MD_REG, p->eth_md);
 	qfec_clkreg_write(priv, ETH_NS_REG, p->eth_ns);
@@ -1146,9 +1160,33 @@
 }
 
 /*
+ * MDIO show
+ */
+static int qfec_mdio_show(struct device *dev, struct device_attribute *attr,
+					char *buf)
+{
+	struct qfec_priv        *priv = netdev_priv(to_net_dev(dev));
+	int                      n;
+	int                      l = 0;
+	int                      count = PAGE_SIZE;
+
+	QFEC_LOG(QFEC_LOG_DBG2, "%s:\n", __func__);
+
+	for (n = 0; n < MAX_MDIO_REG; n++) {
+		if (!(n % 8))
+			l += snprintf(&buf[l], count - l, "\n   %02x: ", n);
+
+		l += snprintf(&buf[l], count - l, " %04x",
+			qfec_mdio_read(to_net_dev(dev), priv->phy_id, n));
+	}
+	l += snprintf(&buf[l], count - l, "\n");
+
+	return  l;
+}
+
+/*
  * get auto-negotiation results
  */
-
 #define QFEC_100        (LPA_100HALF | LPA_100FULL | LPA_100HALF)
 #define QFEC_100_FD     (LPA_100FULL | LPA_100BASE4)
 #define QFEC_10         (LPA_10HALF  | LPA_10FULL)
@@ -1157,28 +1195,45 @@
 static void qfec_get_an(struct net_device *dev, uint32_t *spd, uint32_t *dplx)
 {
 	struct qfec_priv   *priv = netdev_priv(dev);
-	uint32_t            status;
-	uint32_t            advert;
-	uint32_t            lpa;
-	uint32_t            flow;
+	uint32_t  advert   = qfec_mdio_read(dev, priv->phy_id, MII_ADVERTISE);
+	uint32_t  lpa      = qfec_mdio_read(dev, priv->phy_id, MII_LPA);
+	uint32_t  mastCtrl = qfec_mdio_read(dev, priv->phy_id, MII_CTRL1000);
+	uint32_t  mastStat = qfec_mdio_read(dev, priv->phy_id, MII_STAT1000);
+	uint32_t  anExp    = qfec_mdio_read(dev, priv->phy_id, MII_EXPANSION);
+	uint32_t  status   = advert & lpa;
+	uint32_t  flow;
 
-	advert = qfec_mdio_read(dev, priv->phy_id, MII_ADVERTISE);
-	lpa    = qfec_mdio_read(dev, priv->phy_id, MII_LPA);
-	status = advert & lpa;
+	if (priv->mii.supports_gmii) {
+		if (((anExp & QFEC_MII_EXP_MASK) == QFEC_MII_EXP_MASK)
+			&& (mastCtrl & ADVERTISE_1000FULL)
+			&& (mastStat & LPA_1000FULL)) {
+			*spd  = SPD_1000;
+			*dplx = F_DPLX;
+			goto pause;
+		}
 
-	/* todo: check extended status register for 1G abilities */
+		else if (((anExp & QFEC_MII_EXP_MASK) == QFEC_MII_EXP_MASK)
+			&& (mastCtrl & ADVERTISE_1000HALF)
+			&& (mastStat & LPA_1000HALF)) {
+			*spd  = SPD_1000;
+			*dplx = H_DPLX;
+			goto pause;
+		}
+	}
 
+	/* mii speeds */
 	if (status & QFEC_100)  {
-		*spd  = spd_100;
-		*dplx = status & QFEC_100_FD ? 1 : 0;
+		*spd  = SPD_100;
+		*dplx = status & QFEC_100_FD ? F_DPLX : H_DPLX;
 	}
 
 	else if (status & QFEC_10)  {
-		*spd  = spd_10;
-		*dplx = status & QFEC_10_FD ? 1 : 0;
+		*spd  = SPD_10;
+		*dplx = status & QFEC_10_FD ? F_DPLX : H_DPLX;
 	}
 
 	/* check pause */
+pause:
 	flow  = qfec_reg_read(priv, FLOW_CONTROL_REG);
 	flow &= ~(FLOW_CONTROL_TFE | FLOW_CONTROL_RFE);
 
@@ -1202,8 +1257,8 @@
 {
 	struct net_device  *dev  = (struct net_device *) data;
 	struct qfec_priv   *priv = netdev_priv(dev);
-	unsigned int        spd  = 0;
-	unsigned int        dplx = 1;
+	unsigned int        spd  = H_DPLX;
+	unsigned int        dplx = F_DPLX;
 
 	mod_timer(&priv->phy_tmr, jiffies + HZ);
 
@@ -1609,15 +1664,8 @@
 	CNTR_INC(priv, rx_int);
 
 	/* check that valid interrupt occurred */
-	if (unlikely(desc_status & BUF_OWN)) {
-		char  s[100];
-
-		qfec_bd_fmt(s, sizeof(s), p_bd);
-		QFEC_LOG_ERR("%s: owned by DMA, %08x, %s\n", __func__,
-			qfec_reg_read(priv, CUR_HOST_RX_DES_REG), s);
-		CNTR_INC(priv, rx_owned);
+	if (unlikely(desc_status & BUF_OWN))
 		return;
-	}
 
 	/* accumulate missed-frame count (reg reset when read) */
 	priv->stats.rx_missed_errors += mis_fr_reg
@@ -1691,6 +1739,8 @@
 			break;
 		qfec_ring_tail_adv(p_ring);
 	}
+
+	qfec_reg_write(priv, STATUS_REG, STATUS_REG_RI);
 }
 
 /*
@@ -1735,7 +1785,7 @@
 		CNTR_INC(priv, norm_int);
 
 	/* receive interrupt */
-	if (status & STATUS_REG_RI)  {
+	if (status & STATUS_REG_RI) {
 		CNTR_INC(priv, rx_isr);
 		qfec_rx_int(dev);
 	}
@@ -1748,8 +1798,10 @@
 
 	/* gmac interrupt */
 	if (status & (STATUS_REG_GPI | STATUS_REG_GMI | STATUS_REG_GLI))  {
+		status &= ~(STATUS_REG_GPI | STATUS_REG_GMI | STATUS_REG_GLI);
 		CNTR_INC(priv, gmac_isr);
-		int_bits |= STATUS_REG_GMI;
+		int_bits |= STATUS_REG_GPI | STATUS_REG_GMI | STATUS_REG_GLI;
+		qfec_reg_read(priv, SG_RG_SMII_STATUS_REG);
 	}
 
 	/* clear interrupts */
@@ -1823,7 +1875,14 @@
 	qfec_ptp_cfg(priv);
 
 	/* configure PHY - must be set before reset/hw_init */
-	qfec_intf_sel(priv, intfc_mii);
+	priv->mii.supports_gmii = mii_check_gmii_support(&priv->mii);
+	if (priv->mii.supports_gmii) {
+		QFEC_LOG_ERR("%s: RGMII\n", __func__);
+		qfec_intf_sel(priv, INTFC_RGMII);
+	} else {
+		QFEC_LOG_ERR("%s: MII\n", __func__);
+		qfec_intf_sel(priv, INTFC_MII);
+	}
 
 	/* initialize controller after BDs allocated */
 	res = qfec_hw_init(priv);
@@ -1923,6 +1982,10 @@
 
 	spin_lock_irqsave(&priv->xmit_lock, flags);
 
+	/* If there is no room, on the ring try to free some up */
+	if (qfec_ring_room(p_ring) == 0)
+		qfec_tx_replenish(dev);
+
 	/* stop queuing if no resources available */
 	if (qfec_ring_room(p_ring) == 0)  {
 		qfec_queue_stop(dev);
@@ -2477,6 +2540,7 @@
 static DEVICE_ATTR(cmd,     0222, NULL,              qfec_cmd);
 static DEVICE_ATTR(cntrs,   0444, qfec_cntrs_show,   NULL);
 static DEVICE_ATTR(reg,     0444, qfec_reg_show,     NULL);
+static DEVICE_ATTR(mdio,    0444, qfec_mdio_show,    NULL);
 static DEVICE_ATTR(stats,   0444, qfec_stats_show,   NULL);
 static DEVICE_ATTR(tstamp,  0444, qfec_tstamp_show,  NULL);
 
@@ -2488,6 +2552,7 @@
 		device_create_file(&(dev->dev), &dev_attr_clk_reg) ||
 		device_create_file(&(dev->dev), &dev_attr_cmd) ||
 		device_create_file(&(dev->dev), &dev_attr_cntrs) ||
+		device_create_file(&(dev->dev), &dev_attr_mdio) ||
 		device_create_file(&(dev->dev), &dev_attr_reg) ||
 		device_create_file(&(dev->dev), &dev_attr_stats) ||
 		device_create_file(&(dev->dev), &dev_attr_tstamp))
diff --git a/drivers/net/wireless/libra/Makefile b/drivers/net/wireless/libra/Makefile
index 3c606ba..849de05 100644
--- a/drivers/net/wireless/libra/Makefile
+++ b/drivers/net/wireless/libra/Makefile
@@ -1,7 +1,7 @@
 
 # Makefile for wlan sdio if driver
 
-librasdioif-objs += libra_sdioif.o
+librasdioif-objs += libra_sdioif.o ../wcnss/qcomwlan_secif.o
 
 ifdef CONFIG_ARCH_MSM8X60
 	librasdioif-objs += qcomwlan_pwrif.o
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index b002657..c2a4b6a 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1203,11 +1203,11 @@
 	mutex_unlock(&sps->lock);
 
 	if (result) {
-		if (virt_addr != NULL)
-			iounmap(bam->props.virt_addr);
-
-		if (bam != NULL)
+		if (bam != NULL) {
+			if (virt_addr != NULL)
+				iounmap(bam->props.virt_addr);
 			kfree(bam);
+		}
 
 		return result;
 	}
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index edd789e..cb5a0ee 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -634,9 +634,16 @@
 		SPS_ERR("Disconnect BAM 0x%x pipe %d with events pending",
 			BAM_ID(dev), pipe_index);
 
-		list_for_each_entry(sps_event, &pipe->sys.events_q, list) {
+		sps_event = list_entry((&pipe->sys.events_q)->next,
+				typeof(*sps_event), list);
+
+		while (&sps_event->list != (&pipe->sys.events_q)) {
+			struct sps_q_event *sps_event_delete = sps_event;
+
 			list_del(&sps_event->list);
-			kfree(sps_event);
+			sps_event = list_entry(sps_event->list.next,
+					typeof(*sps_event), list);
+			kfree(sps_event_delete);
 		}
 	}
 
@@ -1086,11 +1093,17 @@
 			continue;	/* No */
 
 		index = SPS_EVENT_INDEX(opt_event_table[n].event_id);
-		event_reg = &pipe->sys.event_regs[index];
-		event_reg->xfer_done = reg->xfer_done;
-		event_reg->callback = reg->callback;
-		event_reg->mode = reg->mode;
-		event_reg->user = reg->user;
+		if (index < 0)
+			SPS_ERR("Negative event index: "
+			"BAM 0x%x pipe %d mode %d",
+			BAM_ID(dev), pipe_index, reg->mode);
+		else {
+			event_reg = &pipe->sys.event_regs[index];
+			event_reg->xfer_done = reg->xfer_done;
+			event_reg->callback = reg->callback;
+			event_reg->mode = reg->mode;
+			event_reg->user = reg->user;
+		}
 	}
 
 	return 0;
diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c
index b650098..48c7ffd 100644
--- a/drivers/platform/msm/sps/sps_dma.c
+++ b/drivers/platform/msm/sps/sps_dma.c
@@ -291,6 +291,11 @@
 	dev->h = h;
 	dev->bam = sps_h2bam(h);
 
+	if (dev->bam == NULL) {
+		SPS_ERR("BAM-DMA BAM device is not found from the handle.");
+		goto exit_err;
+	}
+
 	/* Map the BAM DMA device into virtual space, if necessary */
 	props = &dev->bam->props;
 	dev->phys_addr = props->periph_phys_addr;
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 31c1314..358dbd3 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -131,6 +131,12 @@
 #endif
 
 	pool = gen_pool_create(min_alloc_order, nid);
+
+	if (!pool) {
+		SPS_ERR("sps:Failed to create a new memory pool.\n");
+		return -ENOMEM;
+	}
+
 #ifndef CONFIG_SPS_SUPPORT_NDP_BAM
 	res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
 	if (res)
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 85d8a08..df2d556 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -52,6 +52,26 @@
 	PM_BMS_MAX_INTS,
 };
 
+struct pm8921_soc_params {
+	uint16_t	ocv_for_rbatt_raw;
+	uint16_t	vsense_for_rbatt_raw;
+	uint16_t	vbatt_for_rbatt_raw;
+	uint16_t	last_good_ocv_raw;
+	int		cc;
+
+	int		ocv_for_rbatt_uv;
+	int		vsense_for_rbatt_uv;
+	int		vbatt_for_rbatt_uv;
+	int		last_good_ocv_uv;
+};
+
+/**
+ * struct pm8921_bms_chip -
+ * @bms_output_lock:	lock to prevent concurrent bms reads
+ * @bms_100_lock:	lock to prevent concurrent updates to values that force
+ *			100% charge
+ *
+ */
 struct pm8921_bms_chip {
 	struct device		*dev;
 	struct dentry		*dent;
@@ -77,6 +97,7 @@
 	unsigned int		pmic_bms_irq[PM_BMS_MAX_INTS];
 	DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
 	spinlock_t		bms_output_lock;
+	spinlock_t		bms_100_lock;
 	struct single_row_lut	*adjusted_fcc_temp_lut;
 	unsigned int		charging_began;
 	unsigned int		start_percent;
@@ -84,6 +105,7 @@
 
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
+	int			max_voltage_uv;
 };
 
 static struct pm8921_bms_chip *the_chip;
@@ -129,6 +151,31 @@
 static int bms_fake_battery;
 module_param(bms_fake_battery, int, 0644);
 
+/* bms_start_XXX and bms_end_XXX are read only */
+static int bms_start_percent;
+static int bms_start_ocv_uv;
+static int bms_start_cc_mah;
+static int bms_end_percent;
+static int bms_end_ocv_uv;
+static int bms_end_cc_mah;
+
+static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
+{
+	return -EINVAL;
+}
+
+static struct kernel_param_ops bms_ro_param_ops = {
+	.set = bms_ro_ops_set,
+	.get = param_get_int,
+};
+module_param_cb(bms_start_percent, &bms_ro_param_ops, &bms_start_percent, 0644);
+module_param_cb(bms_start_ocv_uv, &bms_ro_param_ops, &bms_start_ocv_uv, 0644);
+module_param_cb(bms_start_cc_mah, &bms_ro_param_ops, &bms_start_cc_mah, 0644);
+
+module_param_cb(bms_end_percent, &bms_ro_param_ops, &bms_end_percent, 0644);
+module_param_cb(bms_end_ocv_uv, &bms_ro_param_ops, &bms_end_ocv_uv, 0644);
+module_param_cb(bms_end_cc_mah, &bms_ro_param_ops, &bms_end_cc_mah, 0644);
+
 static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
 static void readjust_fcc_table(void)
 {
@@ -314,9 +361,6 @@
 		return rc;
 	}
 
-	/* Output register data must be held (locked) while reading output */
-	WARN_ON(!(reg && HOLD_OREG_DATA));
-
 	rc = pm_bms_masked_write(chip, BMS_CONTROL, SELECT_OUTPUT_DATA,
 					type << SELECT_OUTPUT_TYPE_SHIFT);
 	if (rc) {
@@ -425,96 +469,28 @@
 	}
 	*result = msw << 16 | lsw;
 	pr_debug("msw = %04x lsw = %04x cc = %d\n", msw, lsw, *result);
-	*result = *result - chip->cc_reading_at_100;
 	pr_debug("cc = %d after subtracting %d\n",
 					*result, chip->cc_reading_at_100);
 	return 0;
 }
 
-static int read_last_good_ocv(struct pm8921_bms_chip *chip, uint *result)
+static int convert_vbatt_raw_to_uv(struct pm8921_bms_chip *chip,
+					uint16_t reading, int *result)
 {
-	int rc;
-	uint16_t reading;
-
-	rc = pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &reading);
-	if (rc) {
-		pr_err("fail to read LAST_GOOD_OCV_VALUE rc = %d\n", rc);
-		return rc;
-	}
-
-	if (chip->ocv_reading_at_100 != reading) {
-		chip->ocv_reading_at_100 = 0;
-		chip->cc_reading_at_100 = 0;
-		*result = xoadc_reading_to_microvolt(reading);
-		pr_debug("raw = %04x ocv_uV = %u\n", reading, *result);
-		*result = adjust_xo_vbatt_reading(chip, *result);
-		pr_debug("after adj ocv_uV = %u\n", *result);
-		if (*result != 0)
-			last_ocv_uv = *result;
-	} else {
-		/*
-		 * force 100% ocv by selecting the highest profiled ocv
-		 * This is the first row last column entry in the ocv
-		 * lookup table
-		 */
-		int cols = chip->pc_temp_ocv_lut->cols;
-
-		pr_debug("Forcing max voltage %d\n",
-				1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1]);
-		*result = 1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1];
-	}
-
-	return 0;
-}
-
-static int read_vbatt_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
-{
-	int rc;
-	uint16_t reading;
-
-	rc = pm_bms_read_output_data(chip, VBATT_FOR_RBATT, &reading);
-	if (rc) {
-		pr_err("fail to read VBATT_FOR_RBATT rc = %d\n", rc);
-		return rc;
-	}
 	*result = xoadc_reading_to_microvolt(reading);
-	pr_debug("raw = %04x vbatt_for_r_microV = %u\n", reading, *result);
+	pr_debug("raw = %04x vbatt = %u\n", reading, *result);
 	*result = adjust_xo_vbatt_reading(chip, *result);
-	pr_debug("after adj vbatt_for_r_uV = %u\n", *result);
+	pr_debug("after adj vbatt = %u\n", *result);
 	return 0;
 }
 
-static int read_vsense_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
+static int convert_vsense_to_uv(struct pm8921_bms_chip *chip,
+					int16_t reading, int *result)
 {
-	int rc;
-	uint16_t reading;
-
-	rc = pm_bms_read_output_data(chip, VSENSE_FOR_RBATT, &reading);
-	if (rc) {
-		pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
-		return rc;
-	}
 	*result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
-	pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
+	pr_debug("raw = %04x vsense = %d\n", reading, *result);
 	*result = pm8xxx_cc_adjust_for_gain(*result);
-	pr_debug("after adj vsense_for_r_uV = %u\n", *result);
-	return 0;
-}
-
-static int read_ocv_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
-{
-	int rc;
-	uint16_t reading;
-
-	rc = pm_bms_read_output_data(chip, OCV_FOR_RBATT, &reading);
-	if (rc) {
-		pr_err("fail to read OCV_FOR_RBATT rc = %d\n", rc);
-		return rc;
-	}
-	*result = xoadc_reading_to_microvolt(reading);
-	pr_debug("raw = %04x ocv_for_r_uV = %u\n", reading, *result);
-	*result = adjust_xo_vbatt_reading(chip, *result);
-	pr_debug("after adj ocv_for_r_uV = %u\n", *result);
+	pr_debug("after adj vsense = %d\n", *result);
 	return 0;
 }
 
@@ -528,11 +504,8 @@
 		pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
 		return rc;
 	}
-	*result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
-								reading);
-	pr_debug("raw = %04x vsense = %d\n", reading, *result);
-	*result = pm8xxx_cc_adjust_for_gain((s64)*result);
-	pr_debug("after adj vsense = %d\n", *result);
+
+	convert_vsense_to_uv(chip, reading, result);
 	return 0;
 }
 
@@ -579,11 +552,15 @@
 
 static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp)
 {
+	/* batt_temp is in tenths of degC - convert it to degC for lookups */
+	batt_temp = batt_temp/10;
 	return interpolate_single_lut(chip->fcc_temp_lut, batt_temp);
 }
 
 static int interpolate_fcc_adjusted(struct pm8921_bms_chip *chip, int batt_temp)
 {
+	/* batt_temp is in tenths of degC - convert it to degC for lookups */
+	batt_temp = batt_temp/10;
 	return interpolate_single_lut(chip->adjusted_fcc_temp_lut, batt_temp);
 }
 
@@ -699,6 +676,9 @@
 	int rows = chip->pc_temp_ocv_lut->rows;
 	int cols = chip->pc_temp_ocv_lut->cols;
 
+	/* batt_temp is in tenths of degC - convert it to degC for lookups */
+	batt_temp = batt_temp/10;
+
 	if (batt_temp < chip->pc_temp_ocv_lut->temp[0]) {
 		pr_debug("batt_temp %d < known temp range for pc\n", batt_temp);
 		batt_temp = chip->pc_temp_ocv_lut->temp[0];
@@ -790,37 +770,59 @@
 	return 100;
 }
 
-static int calculate_rbatt(struct pm8921_bms_chip *chip)
+static int read_soc_params_raw(struct pm8921_bms_chip *chip,
+				struct pm8921_soc_params *raw)
 {
-	int rc;
-	unsigned int ocv, vsense, vbatt, r_batt;
+	unsigned long flags;
 
-	rc = read_ocv_for_rbatt(chip, &ocv);
-	if (rc) {
-		pr_err("fail to read ocv_for_rbatt rc = %d\n", rc);
-		ocv = 0;
-	}
+	spin_lock_irqsave(&chip->bms_output_lock, flags);
+	pm_bms_lock_output_data(chip);
 
-	rc = read_vbatt_for_rbatt(chip, &vbatt);
-	if (rc) {
-		pr_err("fail to read vbatt_for_rbatt rc = %d\n", rc);
-		ocv = 0;
-	}
+	pm_bms_read_output_data(chip,
+			OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
+	pm_bms_read_output_data(chip,
+			VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
+	pm_bms_read_output_data(chip,
+			VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
+	pm_bms_read_output_data(chip,
+			LAST_GOOD_OCV_VALUE, &raw->last_good_ocv_raw);
+	read_cc(chip, &raw->cc);
 
-	rc = read_vsense_for_rbatt(chip, &vsense);
-	if (rc) {
-		pr_err("fail to read vsense_for_rbatt rc = %d\n", rc);
-		ocv = 0;
-	}
-	if (ocv == 0
-		|| ocv == vbatt
-		|| vsense == 0) {
+	pm_bms_unlock_output_data(chip);
+	spin_unlock_irqrestore(&chip->bms_output_lock, flags);
+
+	convert_vbatt_raw_to_uv(chip,
+			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
+	convert_vbatt_raw_to_uv(chip,
+			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
+	convert_vbatt_raw_to_uv(chip,
+			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+	convert_vsense_to_uv(chip,
+			raw->vsense_for_rbatt_raw, &raw->vsense_for_rbatt_uv);
+
+	if (raw->last_good_ocv_uv)
+		last_ocv_uv = raw->last_good_ocv_uv;
+
+	return 0;
+}
+
+static int calculate_rbatt(struct pm8921_bms_chip *chip,
+				struct pm8921_soc_params *raw)
+{
+	unsigned int  r_batt;
+
+	if (raw->ocv_for_rbatt_uv == 0
+		|| raw->ocv_for_rbatt_uv == raw->vbatt_for_rbatt_uv
+		|| raw->vsense_for_rbatt_raw == 0) {
 		pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
 					"vsen = %d\n",
-					ocv, vbatt, vsense);
+					raw->ocv_for_rbatt_uv,
+					raw->vbatt_for_rbatt_uv,
+					raw->vsense_for_rbatt_raw);
 		return -EINVAL;
 	}
-	r_batt = ((ocv - vbatt) * chip->r_sense) / vsense;
+	r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
+			* chip->r_sense) / raw->vsense_for_rbatt_uv;
 	last_rbatt = r_batt;
 	pr_debug("r_batt = %umilliOhms", r_batt);
 	return r_batt;
@@ -859,13 +861,13 @@
 	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;
+	int vbatt, rbatt, ibatt_ua, rc;
+	struct pm8921_soc_params raw;
 
 	rc = get_battery_uvolts(chip, &vbatt);
 	if (rc) {
@@ -873,16 +875,18 @@
 		return rc;
 	}
 
-	rc =  pm8921_bms_get_battery_current(&ibatt);
+	rc =  pm8921_bms_get_battery_current(&ibatt_ua);
 	if (rc) {
 		pr_err("failed to read batt current rc = %d\n", rc);
 		return rc;
 	}
 
-	rbatt = calculate_rbatt(the_chip);
+	read_soc_params_raw(chip, &raw);
+
+	rbatt = calculate_rbatt(the_chip, &raw);
 	if (rbatt < 0)
 		rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
-	*ocv = vbatt + ibatt * rbatt;
+	*ocv = vbatt + (ibatt_ua * rbatt)/1000;
 	return 0;
 }
 
@@ -903,13 +907,13 @@
 	return pc;
 }
 
-static void calculate_cc_mah(struct pm8921_bms_chip *chip, int64_t *val,
+static void calculate_cc_mah(struct pm8921_bms_chip *chip, int cc, int *val,
 			int *coulumb_counter)
 {
-	int rc;
 	int64_t cc_voltage_uv, cc_uvh, cc_mah;
 
-	rc = read_cc(the_chip, coulumb_counter);
+	*coulumb_counter = cc;
+	*coulumb_counter -= chip->cc_reading_at_100;
 	cc_voltage_uv = (int64_t)*coulumb_counter;
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
 	cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
@@ -921,11 +925,12 @@
 }
 
 static int calculate_unusable_charge_mah(struct pm8921_bms_chip *chip,
+					struct pm8921_soc_params *raw,
 				 int fcc, int batt_temp, int chargecycles)
 {
 	int rbatt, voltage_unusable_uv, pc_unusable;
 
-	rbatt = calculate_rbatt(chip);
+	rbatt = calculate_rbatt(chip, raw);
 	if (rbatt < 0) {
 		rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
 		pr_debug("rbatt unavailable assuming %d\n", rbatt);
@@ -942,16 +947,26 @@
 }
 
 /* calculate remainging charge at the time of ocv */
-static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip, int fcc,
-						int batt_temp, int chargecycles)
+static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip,
+						struct pm8921_soc_params *raw,
+						int fcc, int batt_temp,
+						int chargecycles)
 {
-	int rc, ocv, pc;
+	int  ocv, pc;
 
 	/* calculate remainging charge */
 	ocv = 0;
-	rc = read_last_good_ocv(chip, &ocv);
-	if (rc)
-		pr_debug("failed to read ocv rc = %d\n", rc);
+	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+		chip->ocv_reading_at_100 = 0;
+		chip->cc_reading_at_100 = 0;
+		ocv = raw->last_good_ocv_uv;
+	} else {
+		/*
+		 * force 100% ocv by selecting the highest voltage the
+		 * battery could every reach
+		 */
+		ocv = chip->max_voltage_uv;
+	}
 
 	if (ocv == 0) {
 		ocv = last_ocv_uv;
@@ -964,11 +979,12 @@
 }
 
 static void calculate_charging_params(struct pm8921_bms_chip *chip,
+						struct pm8921_soc_params *raw,
 						int batt_temp, int chargecycles,
 						int *fcc,
 						int *unusable_charge,
 						int *remaining_charge,
-						int64_t *cc_mah)
+						int *cc_mah)
 {
 	int coulumb_counter;
 	unsigned long flags;
@@ -977,38 +993,35 @@
 	pr_debug("FCC = %umAh batt_temp = %d, cycles = %d",
 					*fcc, batt_temp, chargecycles);
 
-	/* fcc doesnt need to be read from hardware, lock the bms now */
-	spin_lock_irqsave(&chip->bms_output_lock, flags);
-	pm_bms_lock_output_data(chip);
-
-	*unusable_charge = calculate_unusable_charge_mah(chip, *fcc,
+	*unusable_charge = calculate_unusable_charge_mah(chip, raw, *fcc,
 						batt_temp, chargecycles);
 
 	pr_debug("UUC = %umAh", *unusable_charge);
 
+	spin_lock_irqsave(&chip->bms_100_lock, flags);
 	/* calculate remainging charge */
-	*remaining_charge = calculate_remaining_charge_mah(chip, *fcc,
+	*remaining_charge = calculate_remaining_charge_mah(chip, raw, *fcc,
 						batt_temp, chargecycles);
 	pr_debug("RC = %umAh\n", *remaining_charge);
 
 	/* calculate cc milli_volt_hour */
-	calculate_cc_mah(chip, cc_mah, &coulumb_counter);
-	pr_debug("cc_mah = %lldmAh cc = %d\n", *cc_mah, coulumb_counter);
-
-	pm_bms_unlock_output_data(chip);
-	spin_unlock_irqrestore(&chip->bms_output_lock, flags);
+	calculate_cc_mah(chip, raw->cc, cc_mah, &coulumb_counter);
+	pr_debug("cc_mah = %dmAh raw->cc = %x cc = %x\n",
+					*cc_mah, raw->cc, coulumb_counter);
+	spin_unlock_irqrestore(&chip->bms_100_lock, flags);
 }
 
 static int calculate_real_fcc(struct pm8921_bms_chip *chip,
-						int batt_temp, int chargecycles,
-						int *ret_fcc)
+				struct pm8921_soc_params *raw,
+				int batt_temp, int chargecycles,
+				int *ret_fcc)
 {
 	int fcc, unusable_charge;
 	int remaining_charge;
-	int64_t cc_mah;
+	int cc_mah;
 	int real_fcc;
 
-	calculate_charging_params(chip, batt_temp, chargecycles,
+	calculate_charging_params(chip, raw, batt_temp, chargecycles,
 						&fcc,
 						&unusable_charge,
 						&remaining_charge,
@@ -1016,7 +1029,7 @@
 
 	real_fcc = remaining_charge - cc_mah;
 	*ret_fcc = fcc;
-	pr_debug("real_fcc = %d, RC = %d CC = %lld fcc = %d\n",
+	pr_debug("real_fcc = %d, RC = %d CC = %d fcc = %d\n",
 			real_fcc, remaining_charge, cc_mah, fcc);
 	return real_fcc;
 }
@@ -1028,14 +1041,15 @@
  */
 #define BATTERY_POWER_SUPPLY_SOC	53
 static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
-						int batt_temp, int chargecycles)
+					struct pm8921_soc_params *raw,
+					int batt_temp, int chargecycles)
 {
 	int remaining_usable_charge, fcc, unusable_charge;
 	int remaining_charge, soc;
 	int update_userspace = 1;
-	int64_t cc_mah;
+	int cc_mah;
 
-	calculate_charging_params(chip, batt_temp, chargecycles,
+	calculate_charging_params(chip, raw, batt_temp, chargecycles,
 						&fcc,
 						&unusable_charge,
 						&remaining_charge,
@@ -1057,7 +1071,7 @@
 
 	if (soc < 0) {
 		pr_err("bad rem_usb_chg = %d rem_chg %d,"
-				"cc_mah %lld, unusb_chg %d\n",
+				"cc_mah %d, unusb_chg %d\n",
 				remaining_usable_charge, remaining_charge,
 				cc_mah, unusable_charge);
 		pr_err("for bad rem_usb_chg last_ocv_uv = %d"
@@ -1130,7 +1144,7 @@
 		return;
 	}
 	voltage = calib_hkadc_convert_microvolt(result.adc_code);
-	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_mead = %lld\n",
+	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld\n",
 				result.adc_code, voltage, result.measurement);
 	/* check for valid range */
 	if (voltage > XOADC_MAX_0P625V)
@@ -1178,7 +1192,7 @@
 }
 EXPORT_SYMBOL(pm8921_bms_get_vsense_avg);
 
-int pm8921_bms_get_battery_current(int *result)
+int pm8921_bms_get_battery_current(int *result_ua)
 {
 	unsigned long flags;
 	int vsense;
@@ -1199,7 +1213,7 @@
 	spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
 	pr_debug("vsense=%d\n", vsense);
 	/* cast for signed division */
-	*result = vsense / (int)the_chip->r_sense;
+	*result_ua = vsense * 1000 / (int)the_chip->r_sense;
 
 	return 0;
 }
@@ -1209,6 +1223,7 @@
 {
 	int batt_temp, rc;
 	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
 
 	if (!the_chip) {
 		pr_err("called before initialization\n");
@@ -1224,7 +1239,10 @@
 	pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
 						result.measurement);
 	batt_temp = (int)result.physical;
-	return calculate_state_of_charge(the_chip,
+
+	read_soc_params_raw(the_chip, &raw);
+
+	return calculate_state_of_charge(the_chip, &raw,
 					batt_temp, last_chargecycles);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
@@ -1254,7 +1272,28 @@
 
 void pm8921_bms_charging_began(void)
 {
-	the_chip->start_percent = pm8921_bms_get_percent_charge();
+	int batt_temp, coulumb_counter, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+
+	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+				the_chip->batt_temp_channel, rc);
+		return;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	read_soc_params_raw(the_chip, &raw);
+
+	the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
+					batt_temp, last_chargecycles);
+	bms_start_percent = the_chip->start_percent;
+	bms_start_ocv_uv = raw.last_good_ocv_uv;
+	calculate_cc_mah(the_chip, raw.cc, &bms_start_cc_mah, &coulumb_counter);
+
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1262,22 +1301,27 @@
 #define DELTA_FCC_PERCENT	3
 void pm8921_bms_charging_end(int is_battery_full)
 {
+	int batt_temp, coulumb_counter, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+
+	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+				the_chip->batt_temp_channel, rc);
+		return;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	read_soc_params_raw(the_chip, &raw);
+
 	if (is_battery_full && the_chip != NULL) {
 		unsigned long flags;
-		int batt_temp, rc, cc_reading;
 		int fcc, new_fcc, delta_fcc;
-		struct pm8xxx_adc_chan_result result;
 
-		rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
-		if (rc) {
-			pr_err("error reading adc channel = %d, rc = %d\n",
-					the_chip->batt_temp_channel, rc);
-			goto charge_cycle_calculation;
-		}
-		pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
-							result.measurement);
-		batt_temp = (int)result.physical;
-		new_fcc = calculate_real_fcc(the_chip,
+		new_fcc = calculate_real_fcc(the_chip, &raw,
 						batt_temp, last_chargecycles,
 						&fcc);
 		delta_fcc = new_fcc - fcc;
@@ -1296,21 +1340,22 @@
 					delta_fcc, DELTA_FCC_PERCENT, fcc);
 		}
 
-		spin_lock_irqsave(&the_chip->bms_output_lock, flags);
-		pm_bms_lock_output_data(the_chip);
-		pm_bms_read_output_data(the_chip, LAST_GOOD_OCV_VALUE,
-						&the_chip->ocv_reading_at_100);
-		read_cc(the_chip, &cc_reading);
-		pm_bms_unlock_output_data(the_chip);
-		spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
-		the_chip->cc_reading_at_100 = cc_reading;
-		pr_debug("EOC ocv_reading = 0x%x cc_reading = %d\n",
+		spin_lock_irqsave(&the_chip->bms_100_lock, flags);
+		the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
+		the_chip->cc_reading_at_100 = raw.cc;
+		spin_unlock_irqrestore(&the_chip->bms_100_lock, flags);
+		pr_debug("EOC ocv_reading = 0x%x cc = %d\n",
 				the_chip->ocv_reading_at_100,
 				the_chip->cc_reading_at_100);
 	}
 
-charge_cycle_calculation:
-	the_chip->end_percent = pm8921_bms_get_percent_charge();
+	the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
+					batt_temp, last_chargecycles);
+
+	bms_end_percent = the_chip->end_percent;
+	bms_end_ocv_uv = raw.last_good_ocv_uv;
+	calculate_cc_mah(the_chip, raw.cc, &bms_end_cc_mah, &coulumb_counter);
+
 	if (the_chip->end_percent > the_chip->start_percent) {
 		last_charge_increase =
 			the_chip->end_percent - the_chip->start_percent;
@@ -1472,24 +1517,26 @@
 
 static void check_initial_ocv(struct pm8921_bms_chip *chip)
 {
-	int ocv, rc;
+	int ocv_uv, rc;
+	int16_t ocv_raw;
 
 	/*
 	 * Check if a ocv is available in bms hw,
 	 * if not compute it here at boot time and save it
 	 * in the last_ocv_uv.
 	 */
-	ocv = 0;
-	rc = read_last_good_ocv(chip, &ocv);
-	if (rc || ocv == 0) {
-		rc = adc_based_ocv(chip, &ocv);
+	ocv_uv = 0;
+	pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
+	rc = convert_vbatt_raw_to_uv(chip, ocv_raw, &ocv_uv);
+	if (rc || ocv_uv == 0) {
+		rc = adc_based_ocv(chip, &ocv_uv);
 		if (rc) {
-			pr_err("failed to read adc based ocv rc = %d\n", rc);
-			ocv = DEFAULT_OCV_MICROVOLTS;
+			pr_err("failed to read adc based ocv_uv rc = %d\n", rc);
+			ocv_uv = DEFAULT_OCV_MICROVOLTS;
 		}
-		last_ocv_uv = ocv;
+		last_ocv_uv = ocv_uv;
 	}
-	pr_debug("ocv = %d last_ocv_uv = %d\n", ocv, last_ocv_uv);
+	pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, last_ocv_uv);
 }
 
 static int64_t read_battery_id(struct pm8921_bms_chip *chip)
@@ -1596,13 +1643,16 @@
 {
 	int param = (int)data;
 	int ret = 0;
+	struct pm8921_soc_params raw;
+
+	read_soc_params_raw(the_chip, &raw);
 
 	*val = 0;
 
 	/* global irq number passed in via data */
 	switch (param) {
 	case CALC_RBATT:
-		*val = calculate_rbatt(the_chip);
+		*val = calculate_rbatt(the_chip, &raw);
 		break;
 	case CALC_FCC:
 		*val = calculate_fcc(the_chip, test_batt_temp,
@@ -1613,7 +1663,7 @@
 							test_chargecycle);
 		break;
 	case CALC_SOC:
-		*val = calculate_state_of_charge(the_chip,
+		*val = calculate_state_of_charge(the_chip, &raw,
 					test_batt_temp, test_chargecycle);
 		break;
 	case CALIB_HKADC:
@@ -1637,6 +1687,9 @@
 {
 	int param = (int)data;
 	int ret = 0;
+	struct pm8921_soc_params raw;
+
+	read_soc_params_raw(the_chip, &raw);
 
 	*val = 0;
 
@@ -1644,19 +1697,19 @@
 	switch (param) {
 	case CC_MSB:
 	case CC_LSB:
-		read_cc(the_chip, (int *)val);
+		*val = raw.cc;
 		break;
 	case LAST_GOOD_OCV_VALUE:
-		read_last_good_ocv(the_chip, (uint *)val);
+		*val = raw.last_good_ocv_uv;
 		break;
 	case VBATT_FOR_RBATT:
-		read_vbatt_for_rbatt(the_chip, (uint *)val);
+		*val = raw.vbatt_for_rbatt_uv;
 		break;
 	case VSENSE_FOR_RBATT:
-		read_vsense_for_rbatt(the_chip, (uint *)val);
+		*val = raw.vsense_for_rbatt_uv;
 		break;
 	case OCV_FOR_RBATT:
-		read_ocv_for_rbatt(the_chip, (uint *)val);
+		*val = raw.ocv_for_rbatt_uv;
 		break;
 	case VSENSE_AVG:
 		read_vsense_avg(the_chip, (uint *)val);
@@ -1794,11 +1847,13 @@
 		return -ENOMEM;
 	}
 	spin_lock_init(&chip->bms_output_lock);
+	spin_lock_init(&chip->bms_100_lock);
 	chip->dev = &pdev->dev;
 	chip->r_sense = pdata->r_sense;
 	chip->i_test = pdata->i_test;
 	chip->v_failure = pdata->v_failure;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
+	chip->max_voltage_uv = pdata->max_voltage_uv;
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("%s bad battery data %d\n", __func__, rc);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 47a5d47..ef97389 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -192,16 +192,16 @@
 /**
  * struct pm8921_chg_chip -device information
  * @dev:			device pointer to access the parent
- * @is_usb_path_used:		indicates whether USB charging is used at all
- * @is_usb_path_used:		indicates whether DC charging is used at all
  * @usb_present:		present status of usb
  * @dc_present:			present status of dc
  * @usb_charger_current:	usb current to charge the battery with used when
  *				the usb path is enabled or charging is resumed
  * @safety_time:		max time for which charging will happen
  * @update_time:		how frequently the userland needs to be updated
- * @max_voltage:		the max volts the batt should be charged up to
- * @min_voltage:		the min battery voltage before turning the FETon
+ * @max_voltage_mv:		the max volts the batt should be charged up to
+ * @min_voltage_mv:		the min battery voltage before turning the FETon
+ * @cool_temp_dc:		the cool temp threshold in deciCelcius
+ * @warm_temp_dc:		the warm temp threshold in deciCelcius
  * @resume_voltage_delta:	the voltage delta from vdd max at which the
  *				battery should resume charging
  * @term_current:		The charging based term current
@@ -217,10 +217,10 @@
 	unsigned int			safety_time;
 	unsigned int			ttrkl_time;
 	unsigned int			update_time;
-	unsigned int			max_voltage;
-	unsigned int			min_voltage;
-	unsigned int			cool_temp;
-	unsigned int			warm_temp;
+	unsigned int			max_voltage_mv;
+	unsigned int			min_voltage_mv;
+	unsigned int			cool_temp_dc;
+	unsigned int			warm_temp_dc;
 	unsigned int			temp_check_period;
 	unsigned int			cool_bat_chg_current;
 	unsigned int			warm_bat_chg_current;
@@ -923,7 +923,7 @@
 	POWER_SUPPLY_PROP_ENERGY_FULL,
 };
 
-static int get_prop_battery_mvolts(struct pm8921_chg_chip *chip)
+static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
 {
 	int rc;
 	struct pm8xxx_adc_chan_result result;
@@ -941,16 +941,17 @@
 
 static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
 {
-	unsigned int current_voltage = get_prop_battery_mvolts(chip);
-	unsigned int low_voltage = chip->min_voltage;
-	unsigned int high_voltage = chip->max_voltage;
+	unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
+	unsigned int current_voltage_mv = current_voltage_uv / 1000;
+	unsigned int low_voltage = chip->min_voltage_mv;
+	unsigned int high_voltage = chip->max_voltage_mv;
 
-	if (current_voltage <= low_voltage)
+	if (current_voltage_mv <= low_voltage)
 		return 0;
-	else if (current_voltage >= high_voltage)
+	else if (current_voltage_mv >= high_voltage)
 		return 100;
 	else
-		return (current_voltage - low_voltage) * 100
+		return (current_voltage_mv - low_voltage) * 100
 		    / (high_voltage - low_voltage);
 }
 
@@ -969,18 +970,18 @@
 
 static int get_prop_batt_current(struct pm8921_chg_chip *chip)
 {
-	int result_ma, rc;
+	int result_ua, rc;
 
-	rc = pm8921_bms_get_battery_current(&result_ma);
+	rc = pm8921_bms_get_battery_current(&result_ua);
 	if (rc == -ENXIO) {
-		rc = pm8xxx_ccadc_get_battery_current(&result_ma);
+		rc = pm8xxx_ccadc_get_battery_current(&result_ua);
 	}
 
 	if (rc) {
 		pr_err("unable to get batt current rc = %d\n", rc);
 		return rc;
 	} else {
-		return result_ma;
+		return result_ua;
 	}
 }
 
@@ -1105,13 +1106,13 @@
 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-		val->intval = chip->max_voltage;
+		val->intval = chip->max_voltage_mv * 1000;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-		val->intval = chip->min_voltage;
+		val->intval = chip->min_voltage_mv * 1000;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = get_prop_battery_mvolts(chip);
+		val->intval = get_prop_battery_uvolts(chip);
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_batt_capacity(chip);
@@ -1123,7 +1124,7 @@
 		val->intval = get_prop_batt_temp(chip);
 		break;
 	case POWER_SUPPLY_PROP_ENERGY_FULL:
-		val->intval = get_prop_batt_fcc(chip);
+		val->intval = get_prop_batt_fcc(chip) * 1000;
 		break;
 	default:
 		return -EINVAL;
@@ -1844,8 +1845,8 @@
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, eoc_work);
-	int vbat_meas, vbat_programmed;
-	int ichg_meas, iterm_programmed;
+	int vbat_meas_uv, vbat_meas_mv, vbat_programmed;
+	int ichg_meas_ma, iterm_programmed;
 	int regulation_loop, fast_chg, vcp;
 	int rc;
 	static int count;
@@ -1873,18 +1874,19 @@
 			goto reset_and_reschedule;
 
 		/* reset count if battery voltage is less than vddmax */
-		vbat_meas = get_prop_battery_mvolts(chip);
-		if (vbat_meas < 0)
+		vbat_meas_uv = get_prop_battery_uvolts(chip);
+		if (vbat_meas_uv < 0)
 			goto reset_and_reschedule;
+		vbat_meas_mv = vbat_meas_uv / 1000;
 
 		rc = pm_chg_vddmax_get(chip, &vbat_programmed);
 		if (rc) {
 			pr_err("couldnt read vddmax rc = %d\n", rc);
 			goto reset_and_reschedule;
 		}
-		pr_debug("vddmax = %d vbat_meas=%d\n",
-			 vbat_programmed, vbat_meas);
-		if (vbat_meas < vbat_programmed - VBAT_TOLERANCE_MV)
+		pr_debug("vddmax = %d vbat_meas_mv=%d\n",
+			 vbat_programmed, vbat_meas_mv);
+		if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
 			goto reset_and_reschedule;
 	} /* !is_ext_charging */
 
@@ -1895,17 +1897,17 @@
 		goto reset_and_reschedule;
 	}
 
-	ichg_meas = get_prop_batt_current(chip);
-	pr_debug("iterm_programmed = %d ichg_meas=%d\n",
-				iterm_programmed, ichg_meas);
+	ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
+	pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
+				iterm_programmed, ichg_meas_ma);
 	/*
-	 * ichg_meas < 0 means battery is drawing current
-	 * ichg_meas > 0 means battery is providing current
+	 * ichg_meas_ma < 0 means battery is drawing current
+	 * ichg_meas_ma > 0 means battery is providing current
 	 */
-	if (ichg_meas > 0)
+	if (ichg_meas_ma > 0)
 		goto reset_and_reschedule;
 
-	if (ichg_meas * -1 > iterm_programmed)
+	if (ichg_meas_ma * -1 > iterm_programmed)
 		goto reset_and_reschedule;
 
 	if (!is_ext_charging(chip)) {
@@ -1989,18 +1991,19 @@
 	the_chip->is_bat_cool = enter;
 	if (enter) {
 		btm_config.low_thr_temp =
-			the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
+			the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
 		set_appropriate_battery_current(the_chip);
 		pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
 		pm_chg_vbatdet_set(the_chip,
 			the_chip->cool_bat_voltage
 			- the_chip->resume_voltage_delta);
 	} else {
-		btm_config.low_thr_temp = the_chip->cool_temp;
+		btm_config.low_thr_temp = the_chip->cool_temp_dc;
 		set_appropriate_battery_current(the_chip);
-		pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
 		pm_chg_vbatdet_set(the_chip,
-			the_chip->max_voltage - the_chip->resume_voltage_delta);
+			the_chip->max_voltage_mv
+			- the_chip->resume_voltage_delta);
 	}
 	schedule_work(&btm_config_work);
 }
@@ -2013,18 +2016,19 @@
 	the_chip->is_bat_warm = enter;
 	if (enter) {
 		btm_config.high_thr_temp =
-			the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
+			the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
 		set_appropriate_battery_current(the_chip);
 		pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
 		pm_chg_vbatdet_set(the_chip,
 			the_chip->warm_bat_voltage
 			- the_chip->resume_voltage_delta);
 	} else {
-		btm_config.high_thr_temp = the_chip->warm_temp;
+		btm_config.high_thr_temp = the_chip->warm_temp_dc;
 		set_appropriate_battery_current(the_chip);
-		pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
 		pm_chg_vbatdet_set(the_chip,
-			the_chip->max_voltage - the_chip->resume_voltage_delta);
+			the_chip->max_voltage_mv
+			- the_chip->resume_voltage_delta);
 	}
 	schedule_work(&btm_config_work);
 }
@@ -2035,8 +2039,8 @@
 
 	btm_config.btm_warm_fn = battery_warm;
 	btm_config.btm_cool_fn = battery_cool;
-	btm_config.low_thr_temp = chip->cool_temp;
-	btm_config.high_thr_temp = chip->warm_temp;
+	btm_config.low_thr_temp = chip->cool_temp_dc;
+	btm_config.high_thr_temp = chip->warm_temp_dc;
 	btm_config.interval = chip->temp_check_period;
 	rc = pm8xxx_adc_btm_configure(&btm_config);
 	if (rc)
@@ -2315,24 +2319,25 @@
 		return rc;
 	}
 
-	rc = pm_chg_vddsafe_set(chip, chip->max_voltage);
+	rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
 	if (rc) {
 		pr_err("Failed to set safe voltage to %d rc=%d\n",
-						chip->max_voltage, rc);
+						chip->max_voltage_mv, rc);
 		return rc;
 	}
 	rc = pm_chg_vbatdet_set(chip,
-				chip->max_voltage - chip->resume_voltage_delta);
+				chip->max_voltage_mv
+				- chip->resume_voltage_delta);
 	if (rc) {
 		pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
-			chip->max_voltage - chip->resume_voltage_delta, rc);
+			chip->max_voltage_mv - chip->resume_voltage_delta, rc);
 		return rc;
 	}
 
-	rc = pm_chg_vddmax_set(chip, chip->max_voltage);
+	rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
 	if (rc) {
 		pr_err("Failed to set max voltage to %d rc=%d\n",
-						chip->max_voltage, rc);
+						chip->max_voltage_mv, rc);
 		return rc;
 	}
 	rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
@@ -2677,7 +2682,7 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp == 0 && chip->warm_temp == 0)
+	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
 		&& !(chip->keep_btm_on_suspend)) {
 		rc = pm8xxx_adc_btm_configure(&btm_config);
 		if (rc)
@@ -2695,7 +2700,7 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp == 0 && chip->warm_temp == 0)
+	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
 		&& !(chip->keep_btm_on_suspend)) {
 		rc = pm8xxx_adc_btm_end();
 		if (rc)
@@ -2726,8 +2731,8 @@
 	chip->safety_time = pdata->safety_time;
 	chip->ttrkl_time = pdata->ttrkl_time;
 	chip->update_time = pdata->update_time;
-	chip->max_voltage = pdata->max_voltage;
-	chip->min_voltage = pdata->min_voltage;
+	chip->max_voltage_mv = pdata->max_voltage;
+	chip->min_voltage_mv = pdata->min_voltage;
 	chip->resume_voltage_delta = pdata->resume_voltage_delta;
 	chip->term_current = pdata->term_current;
 	chip->vbat_channel = pdata->charger_cdata.vbat_channel;
@@ -2735,8 +2740,8 @@
 	chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
 	chip->batt_id_min = pdata->batt_id_min;
 	chip->batt_id_max = pdata->batt_id_max;
-	chip->cool_temp = pdata->cool_temp;
-	chip->warm_temp = pdata->warm_temp;
+	chip->cool_temp_dc = pdata->cool_temp * 10;
+	chip->warm_temp_dc = pdata->warm_temp * 10;
 	chip->temp_check_period = pdata->temp_check_period;
 	chip->max_bat_chg_current = pdata->max_bat_chg_current;
 	chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
@@ -2819,10 +2824,10 @@
 	enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
 	/*
-	 * if both the cool_temp and warm_temp are zero the device doesnt
+	 * if both the cool_temp_dc and warm_temp_dc are zero the device doesnt
 	 * care for jeita compliance
 	 */
-	if (!(chip->cool_temp == 0 && chip->warm_temp == 0)) {
+	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)) {
 		rc = configure_btm(chip);
 		if (rc) {
 			pr_err("couldn't register with btm rc=%d\n", rc);
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 5e0f8ec..17cf53a 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -76,6 +76,7 @@
 
 static struct pm8xxx_ccadc_chip *the_chip;
 
+#ifdef DEBUG
 static s64 microvolt_to_ccadc_reading_v1(s64 uv)
 {
 	return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
@@ -98,6 +99,7 @@
 				microvolt_to_ccadc_reading_v1((s64)cc) :
 				microvolt_to_ccadc_reading_v2((s64)cc);
 }
+#endif
 
 static int cc_adjust_for_offset(u16 raw)
 {
@@ -256,7 +258,7 @@
 static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
 						int *gain, u16 *offset)
 {
-	s8 data_msb;
+	u8 data_msb;
 	u8 data_lsb;
 	int rc;
 
@@ -328,7 +330,7 @@
 void pm8xxx_calib_ccadc(void)
 {
 	u8 data_msb, data_lsb, sec_cntrl;
-	int result_offset, voltage_offset, result_gain;
+	int result_offset, result_gain;
 	u16 result;
 	int i, rc;
 
@@ -385,26 +387,11 @@
 
 	result_offset = result_offset / SAMPLE_COUNT;
 
-	voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
-			((s64)result_offset - CCADC_INTRINSIC_OFFSET));
 
-	pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
-				result_offset, voltage_offset);
-
-	/* Sanity Check */
-	if (voltage_offset > CCADC_MAX_0UV) {
-		pr_err("offset voltage = %d is huge limiting to %d\n",
-					voltage_offset, CCADC_MAX_0UV);
-		result_offset = CCADC_INTRINSIC_OFFSET
-			+ microvolt_to_ccadc_reading(the_chip,
-							(s64)CCADC_MAX_0UV);
-	} else if (voltage_offset < CCADC_MIN_0UV) {
-		pr_err("offset voltage = %d is too low limiting to %d\n",
-					voltage_offset, CCADC_MIN_0UV);
-		result_offset = CCADC_INTRINSIC_OFFSET
-			+ microvolt_to_ccadc_reading(the_chip,
-							(s64)CCADC_MIN_0UV);
-	}
+	pr_debug("offset result_offset = 0x%x, voltage = %llduV\n",
+			result_offset,
+			pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+			((s64)result_offset - CCADC_INTRINSIC_OFFSET)));
 
 	the_chip->ccadc_offset = result_offset;
 	data_msb = the_chip->ccadc_offset >> 8;
@@ -474,22 +461,6 @@
 
 	pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
 					result_gain, the_chip->ccadc_gain_uv);
-	/* Sanity Check */
-	if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
-		pr_err("gain voltage = %d is huge limiting to %d\n",
-					the_chip->ccadc_gain_uv,
-					CCADC_MAX_25MV);
-		the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
-		result_gain = result_offset +
-			microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
-	} else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
-		pr_err("gain voltage = %d is too low limiting to %d\n",
-					the_chip->ccadc_gain_uv,
-					CCADC_MIN_25MV);
-		the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
-		result_gain = result_offset +
-			microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
-	}
 
 	data_msb = result_gain >> 8;
 	data_lsb = result_gain;
@@ -568,14 +539,15 @@
 					the_chip->ccadc_offset);
 	*voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
 			((s64)result));
-	pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
+	pr_debug("Vsense before gain of %d = %d uV\n", the_chip->ccadc_gain_uv,
+					*voltage_uv);
 	*voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
 
 	pr_debug("Vsense = %d uV\n", *voltage_uv);
 	return 0;
 }
 
-int pm8xxx_ccadc_get_battery_current(int *bat_current)
+int pm8xxx_ccadc_get_battery_current(int *bat_current_ua)
 {
 	int voltage_uv, rc;
 
@@ -585,13 +557,13 @@
 		return rc;
 	}
 
-	*bat_current = voltage_uv/the_chip->r_sense;
+	*bat_current_ua = voltage_uv * 1000/the_chip->r_sense;
 	/*
 	 * ccadc reads +ve current when the battery is charging
 	 * We need to return -ve if the battery is charging
 	 */
-	*bat_current = -1 * (*bat_current);
-	pr_debug("bat current = %d ma\n", *bat_current);
+	*bat_current_ua = -1 * (*bat_current_ua);
+	pr_debug("bat current = %d ma\n", *bat_current_ua);
 	return 0;
 }
 EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 90e2687..984ab71 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1764,6 +1764,13 @@
 	 */
 	wmb();
 
+	/* Register with framework before enabling frame, clock */
+	ret = slim_add_numbered_controller(&dev->ctrl);
+	if (ret) {
+		dev_err(dev->dev, "error adding controller\n");
+		goto err_ctrl_failed;
+	}
+
 	/* Framer register initialization */
 	writel_relaxed((0xA << REF_CLK_GEAR) | (0xA << CLK_GEAR) |
 		(1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
@@ -1811,11 +1818,6 @@
 	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
 	pm_runtime_set_active(&pdev->dev);
 
-	ret = slim_add_numbered_controller(&dev->ctrl);
-	if (ret) {
-		dev_err(dev->dev, "error adding controller\n");
-		goto err_ctrl_failed;
-	}
 	dev_dbg(dev->dev, "MSM SB controller is up!\n");
 	return 0;
 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index d055412..187d310 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -108,6 +108,8 @@
 
 source "drivers/staging/zcache/Kconfig"
 
+source "drivers/staging/qcache/Kconfig"
+
 source "drivers/staging/wlags49_h2/Kconfig"
 
 source "drivers/staging/wlags49_h25/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ae62e92..a247583 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -46,6 +46,7 @@
 obj-$(CONFIG_ZRAM)		+= zram/
 obj-$(CONFIG_XVMALLOC)		+= zram/
 obj-$(CONFIG_ZCACHE)		+= zcache/
+obj-$(CONFIG_QCACHE)		+= qcache/
 obj-$(CONFIG_WLAGS49_H2)	+= wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)	+= wlags49_h25/
 obj-$(CONFIG_FB_SM7XX)		+= sm7xx/
diff --git a/drivers/staging/qcache/Kconfig b/drivers/staging/qcache/Kconfig
new file mode 100644
index 0000000..389341c
--- /dev/null
+++ b/drivers/staging/qcache/Kconfig
@@ -0,0 +1,8 @@
+config QCACHE
+	tristate "Dynamic compression of clean pagecache pages"
+	depends on CLEANCACHE
+	select LZO_COMPRESS
+	select LZO_DECOMPRESS
+	default n
+	help
+	  Qcache is the backend for fmem
diff --git a/drivers/staging/qcache/Makefile b/drivers/staging/qcache/Makefile
new file mode 100644
index 0000000..4fdf05c
--- /dev/null
+++ b/drivers/staging/qcache/Makefile
@@ -0,0 +1,3 @@
+qcache-y	:=	qcache-main.o tmem.o fmem.o
+
+obj-$(CONFIG_QCACHE)	+=	qcache.o
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
new file mode 100644
index 0000000..9ab21da
--- /dev/null
+++ b/drivers/staging/qcache/fmem.c
@@ -0,0 +1,180 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fmem.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include "tmem.h"
+
+struct fmem_data fmem_data;
+enum fmem_state fmem_state;
+static spinlock_t fmem_state_lock;
+
+static int fmem_probe(struct platform_device *pdev)
+{
+	struct fmem_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata->size)
+		return -ENODEV;
+
+	fmem_data.virt = ioremap_cached(pdata->phys, pdata->size);
+	if (!fmem_data.virt)
+		return -ENOMEM;
+
+	fmem_data.phys = pdata->phys;
+	fmem_data.size = pdata->size;
+
+	pr_info("fmem phys %lx virt %p size %lx\n",
+		fmem_data.phys, fmem_data.virt, fmem_data.size);
+
+	spin_lock_init(&fmem_state_lock);
+
+	return 0;
+}
+
+static int fmem_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver fmem_driver = {
+	.probe = fmem_probe,
+	.remove = fmem_remove,
+	.driver = { .name = "fmem" }
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t fmem_state_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	if (fmem_state == FMEM_T_STATE)
+		return snprintf(buf, 3, "t\n");
+	else if (fmem_state == FMEM_C_STATE)
+		return snprintf(buf, 3, "c\n");
+	else if (fmem_state == FMEM_UNINITIALIZED)
+		return snprintf(buf, 15, "uninitialized\n");
+	return snprintf(buf, 3, "?\n");
+}
+
+static ssize_t fmem_state_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+
+	if (!strncmp(buf, "t", 1))
+		ret = fmem_set_state(FMEM_T_STATE);
+	else if (!strncmp(buf, "c", 1))
+		ret = fmem_set_state(FMEM_C_STATE);
+	if (ret)
+		return ret;
+	return 1;
+}
+
+static struct kobj_attribute fmem_state_attr = {
+		.attr = { .name = "state", .mode = 0644 },
+		.show = fmem_state_show,
+		.store = fmem_state_store,
+};
+
+static struct attribute *fmem_attrs[] = {
+	&fmem_state_attr.attr,
+	NULL,
+};
+
+static struct attribute_group fmem_attr_group = {
+	.attrs = fmem_attrs,
+	.name = "fmem",
+};
+
+static int fmem_create_sysfs(void)
+{
+	int ret = 0;
+
+	ret = sysfs_create_group(mm_kobj, &fmem_attr_group);
+	if (ret)
+		pr_err("fmem: can't create sysfs\n");
+	return ret;
+}
+
+#endif
+
+static int __init fmem_init(void)
+{
+	return platform_driver_register(&fmem_driver);
+}
+
+static void __exit fmem_exit(void)
+{
+	platform_driver_unregister(&fmem_driver);
+}
+
+struct fmem_data *fmem_get_info(void)
+{
+	return &fmem_data;
+}
+EXPORT_SYMBOL(fmem_get_info);
+
+void lock_fmem_state(void)
+{
+	spin_lock(&fmem_state_lock);
+}
+
+void unlock_fmem_state(void)
+{
+	spin_unlock(&fmem_state_lock);
+}
+
+int fmem_set_state(enum fmem_state new_state)
+{
+	int ret = 0;
+	int create_sysfs = 0;
+
+	lock_fmem_state();
+	if (fmem_state == new_state)
+		goto out;
+
+	if (fmem_state == FMEM_UNINITIALIZED) {
+		if (new_state == FMEM_T_STATE) {
+			tmem_enable(false);
+			create_sysfs = 1;
+			goto out_set;
+		}
+		if (new_state == FMEM_C_STATE) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (new_state == FMEM_T_STATE)
+		tmem_enable(true);
+	else
+		tmem_disable();
+
+out_set:
+	fmem_state = new_state;
+out:
+	unlock_fmem_state();
+#ifdef CONFIG_SYSFS
+	if (create_sysfs)
+		fmem_create_sysfs();
+#endif
+	return ret;
+}
+EXPORT_SYMBOL(fmem_set_state);
+
+arch_initcall(fmem_init);
+module_exit(fmem_exit);
diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c
new file mode 100644
index 0000000..b6de268
--- /dev/null
+++ b/drivers/staging/qcache/qcache-main.c
@@ -0,0 +1,1357 @@
+/*
+ * Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2010,2011, Nitin Gupta
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Qcache provides an in-kernel "host implementation" for transcendent memory
+ * and, thus indirectly, for cleancache and frontswap.  Qcache includes a
+ * page-accessible memory [1] interface, utilizing lzo1x compression:
+ * 1) "compression buddies" ("zbud") is used for ephemeral pages
+ * Zbud allows pairs (and potentially,
+ * in the future, more than a pair of) compressed pages to be closely linked
+ * so that reclaiming can be done via the kernel's physical-page-oriented
+ * "shrinker" interface.
+ *
+ * [1] For a definition of page-accessible memory (aka PAM), see:
+ *   http://marc.info/?l=linux-mm&m=127811271605009
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/lzo.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/math64.h>
+#include <linux/bitmap.h>
+#include <linux/fmem.h>
+#include "tmem.h"
+
+#if !defined(CONFIG_CLEANCACHE)
+#error "qcache is useless without CONFIG_CLEANCACHE"
+#endif
+#include <linux/cleancache.h>
+
+#define ZCACHE_GFP_MASK \
+	(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
+
+#define MAX_POOLS_PER_CLIENT 16
+
+#define MAX_CLIENTS 16
+#define LOCAL_CLIENT ((uint16_t)-1)
+
+MODULE_LICENSE("GPL");
+
+struct zcache_client {
+	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
+	struct xv_pool *xvpool;
+	bool allocated;
+	atomic_t refcount;
+};
+
+struct qcache_info {
+	void *addr;
+	unsigned long *bitmap;
+	spinlock_t lock;
+	unsigned pages;
+};
+static struct qcache_info qcache_info;
+static unsigned long zcache_qc_allocated;
+static unsigned long zcache_qc_freed;
+static unsigned long zcache_qc_used;
+static unsigned long zcache_qc_max_used;
+
+static struct zcache_client zcache_host;
+static struct zcache_client zcache_clients[MAX_CLIENTS];
+
+static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
+{
+	BUG_ON(cli == NULL);
+	if (cli == &zcache_host)
+		return LOCAL_CLIENT;
+	return cli - &zcache_clients[0];
+}
+
+static inline bool is_local_client(struct zcache_client *cli)
+{
+	return cli == &zcache_host;
+}
+
+/**********
+ * Compression buddies ("zbud") provides for packing two (or, possibly
+ * in the future, more) compressed ephemeral pages into a single "raw"
+ * (physical) page and tracking them with data structures so that
+ * the raw pages can be easily reclaimed.
+ *
+ * A zbud page ("zbpg") is an aligned page containing a list_head,
+ * a lock, and two "zbud headers".  The remainder of the physical
+ * page is divided up into aligned 64-byte "chunks" which contain
+ * the compressed data for zero, one, or two zbuds.  Each zbpg
+ * resides on: (1) an "unused list" if it has no zbuds; (2) a
+ * "buddied" list if it is fully populated  with two zbuds; or
+ * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
+ * the one unbuddied zbud uses.  The data inside a zbpg cannot be
+ * read or written unless the zbpg's lock is held.
+ */
+
+#define ZBH_SENTINEL  0x43214321
+#define ZBPG_SENTINEL  0xdeadbeef
+
+#define ZBUD_MAX_BUDS 2
+
+struct zbud_hdr {
+	uint16_t client_id;
+	uint16_t pool_id;
+	struct tmem_oid oid;
+	uint32_t index;
+	uint16_t size; /* compressed size in bytes, zero means unused */
+	DECL_SENTINEL
+};
+
+struct zbud_page {
+	struct list_head bud_list;
+	spinlock_t lock;
+	struct zbud_hdr buddy[ZBUD_MAX_BUDS];
+	DECL_SENTINEL
+	/* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
+};
+
+#define CHUNK_SHIFT	6
+#define CHUNK_SIZE	(1 << CHUNK_SHIFT)
+#define CHUNK_MASK	(~(CHUNK_SIZE-1))
+#define NCHUNKS		(((PAGE_SIZE - sizeof(struct zbud_page)) & \
+				CHUNK_MASK) >> CHUNK_SHIFT)
+#define MAX_CHUNK	(NCHUNKS-1)
+
+static struct {
+	struct list_head list;
+	unsigned count;
+} zbud_unbuddied[NCHUNKS];
+/* list N contains pages with N chunks USED and NCHUNKS-N unused */
+/* element 0 is never used but optimizing that isn't worth it */
+static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
+
+struct list_head zbud_buddied_list;
+static unsigned long zcache_zbud_buddied_count;
+
+/* protects the buddied list and all unbuddied lists */
+static DEFINE_SPINLOCK(zbud_budlists_spinlock);
+
+static atomic_t zcache_zbud_curr_raw_pages;
+static atomic_t zcache_zbud_curr_zpages;
+static unsigned long zcache_zbud_curr_zbytes;
+static unsigned long zcache_zbud_cumul_zpages;
+static unsigned long zcache_zbud_cumul_zbytes;
+static unsigned long zcache_compress_poor;
+static unsigned long zcache_mean_compress_poor;
+
+/* forward references */
+static void *zcache_get_free_page(void);
+
+static void *qcache_alloc(void)
+{
+	void *addr;
+	unsigned long flags;
+	int offset;
+	struct qcache_info *qc = &qcache_info;
+
+	spin_lock_irqsave(&qc->lock, flags);
+	offset = bitmap_find_free_region(qc->bitmap, qc->pages, 0);
+	spin_unlock_irqrestore(&qc->lock, flags);
+
+	if (offset < 0)
+		return NULL;
+
+	addr = qc->addr + offset * PAGE_SIZE;
+	zcache_qc_allocated++;
+	zcache_qc_used++;
+	zcache_qc_max_used = max(zcache_qc_max_used, zcache_qc_used);
+
+	return addr;
+}
+
+static void qcache_free(void *addr)
+{
+	unsigned long flags;
+	int offset;
+	struct qcache_info *qc = &qcache_info;
+
+	offset = (addr - qc->addr) / PAGE_SIZE;
+
+	spin_lock_irqsave(&qc->lock, flags);
+	bitmap_release_region(qc->bitmap, offset, 0);
+	spin_unlock_irqrestore(&qc->lock, flags);
+
+	zcache_qc_freed++;
+	zcache_qc_used--;
+}
+
+/*
+ * zbud helper functions
+ */
+
+static inline unsigned zbud_max_buddy_size(void)
+{
+	return MAX_CHUNK << CHUNK_SHIFT;
+}
+
+static inline unsigned zbud_size_to_chunks(unsigned size)
+{
+	BUG_ON(size == 0 || size > zbud_max_buddy_size());
+	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
+}
+
+static inline int zbud_budnum(struct zbud_hdr *zh)
+{
+	unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
+	struct zbud_page *zbpg = NULL;
+	unsigned budnum = -1U;
+	int i;
+
+	for (i = 0; i < ZBUD_MAX_BUDS; i++)
+		if (offset == offsetof(typeof(*zbpg), buddy[i])) {
+			budnum = i;
+			break;
+		}
+	BUG_ON(budnum == -1U);
+	return budnum;
+}
+
+static char *zbud_data(struct zbud_hdr *zh, unsigned size)
+{
+	struct zbud_page *zbpg;
+	char *p;
+	unsigned budnum;
+
+	ASSERT_SENTINEL(zh, ZBH);
+	budnum = zbud_budnum(zh);
+	BUG_ON(size == 0 || size > zbud_max_buddy_size());
+	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+	ASSERT_SPINLOCK(&zbpg->lock);
+	p = (char *)zbpg;
+	if (budnum == 0)
+		p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
+							CHUNK_MASK);
+	else if (budnum == 1)
+		p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
+	return p;
+}
+
+/*
+ * zbud raw page management
+ */
+
+static struct zbud_page *zbud_alloc_raw_page(void)
+{
+	struct zbud_page *zbpg = NULL;
+	struct zbud_hdr *zh0, *zh1;
+
+	zbpg = zcache_get_free_page();
+	if (likely(zbpg != NULL)) {
+		INIT_LIST_HEAD(&zbpg->bud_list);
+		zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+		spin_lock_init(&zbpg->lock);
+		atomic_inc(&zcache_zbud_curr_raw_pages);
+		INIT_LIST_HEAD(&zbpg->bud_list);
+		SET_SENTINEL(zbpg, ZBPG);
+		zh0->size = 0; zh1->size = 0;
+		tmem_oid_set_invalid(&zh0->oid);
+		tmem_oid_set_invalid(&zh1->oid);
+	}
+	return zbpg;
+}
+
+static void zbud_free_raw_page(struct zbud_page *zbpg)
+{
+	struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
+
+	ASSERT_SENTINEL(zbpg, ZBPG);
+	BUG_ON(!list_empty(&zbpg->bud_list));
+	ASSERT_SPINLOCK(&zbpg->lock);
+	BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
+	BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
+	INVERT_SENTINEL(zbpg, ZBPG);
+	spin_unlock(&zbpg->lock);
+	qcache_free(zbpg);
+}
+
+/*
+ * core zbud handling routines
+ */
+
+static unsigned zbud_free(struct zbud_hdr *zh)
+{
+	unsigned size;
+
+	ASSERT_SENTINEL(zh, ZBH);
+	BUG_ON(!tmem_oid_valid(&zh->oid));
+	size = zh->size;
+	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+	zh->size = 0;
+	tmem_oid_set_invalid(&zh->oid);
+	INVERT_SENTINEL(zh, ZBH);
+	zcache_zbud_curr_zbytes -= size;
+	atomic_dec(&zcache_zbud_curr_zpages);
+	return size;
+}
+
+static void zbud_free_and_delist(struct zbud_hdr *zh)
+{
+	unsigned chunks;
+	struct zbud_hdr *zh_other;
+	unsigned budnum = zbud_budnum(zh), size;
+	struct zbud_page *zbpg =
+		container_of(zh, struct zbud_page, buddy[budnum]);
+
+	spin_lock(&zbpg->lock);
+	if (list_empty(&zbpg->bud_list)) {
+		spin_unlock(&zbpg->lock);
+		return;
+	}
+	size = zbud_free(zh);
+	ASSERT_SPINLOCK(&zbpg->lock);
+	zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
+	if (zh_other->size == 0) { /* was unbuddied: unlist and free */
+		chunks = zbud_size_to_chunks(size) ;
+		spin_lock(&zbud_budlists_spinlock);
+		BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
+		list_del_init(&zbpg->bud_list);
+		zbud_unbuddied[chunks].count--;
+		spin_unlock(&zbud_budlists_spinlock);
+		zbud_free_raw_page(zbpg);
+	} else { /* was buddied: move remaining buddy to unbuddied list */
+		chunks = zbud_size_to_chunks(zh_other->size) ;
+		spin_lock(&zbud_budlists_spinlock);
+		list_del_init(&zbpg->bud_list);
+		zcache_zbud_buddied_count--;
+		list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
+		zbud_unbuddied[chunks].count++;
+		spin_unlock(&zbud_budlists_spinlock);
+		spin_unlock(&zbpg->lock);
+	}
+}
+
+static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
+					struct tmem_oid *oid,
+					uint32_t index, struct page *page,
+					void *cdata, unsigned size)
+{
+	struct zbud_hdr *zh0, *zh1, *zh = NULL;
+	struct zbud_page *zbpg = NULL, *ztmp;
+	unsigned nchunks;
+	char *to;
+	int i, found_good_buddy = 0;
+
+	nchunks = zbud_size_to_chunks(size) ;
+	for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
+		spin_lock(&zbud_budlists_spinlock);
+		if (!list_empty(&zbud_unbuddied[i].list)) {
+			list_for_each_entry_safe(zbpg, ztmp,
+				    &zbud_unbuddied[i].list, bud_list) {
+				if (spin_trylock(&zbpg->lock)) {
+					found_good_buddy = i;
+					goto found_unbuddied;
+				}
+			}
+		}
+		spin_unlock(&zbud_budlists_spinlock);
+	}
+	/* didn't find a good buddy, try allocating a new page */
+	zbpg = zbud_alloc_raw_page();
+	if (unlikely(zbpg == NULL))
+		goto out;
+	/* ok, have a page, now compress the data before taking locks */
+	spin_lock(&zbpg->lock);
+	spin_lock(&zbud_budlists_spinlock);
+	list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
+	zbud_unbuddied[nchunks].count++;
+	zh = &zbpg->buddy[0];
+	goto init_zh;
+
+found_unbuddied:
+	ASSERT_SPINLOCK(&zbpg->lock);
+	zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+	BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
+	if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
+		ASSERT_SENTINEL(zh0, ZBH);
+		zh = zh1;
+	} else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
+		ASSERT_SENTINEL(zh1, ZBH);
+		zh = zh0;
+	} else
+		BUG();
+	list_del_init(&zbpg->bud_list);
+	zbud_unbuddied[found_good_buddy].count--;
+	list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
+	zcache_zbud_buddied_count++;
+
+init_zh:
+	SET_SENTINEL(zh, ZBH);
+	zh->size = size;
+	zh->index = index;
+	zh->oid = *oid;
+	zh->pool_id = pool_id;
+	zh->client_id = client_id;
+	/* can wait to copy the data until the list locks are dropped */
+	spin_unlock(&zbud_budlists_spinlock);
+
+	to = zbud_data(zh, size);
+	memcpy(to, cdata, size);
+	spin_unlock(&zbpg->lock);
+	zbud_cumul_chunk_counts[nchunks]++;
+	atomic_inc(&zcache_zbud_curr_zpages);
+	zcache_zbud_cumul_zpages++;
+	zcache_zbud_curr_zbytes += size;
+	zcache_zbud_cumul_zbytes += size;
+out:
+	return zh;
+}
+
+static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
+{
+	struct zbud_page *zbpg;
+	unsigned budnum = zbud_budnum(zh);
+	size_t out_len = PAGE_SIZE;
+	char *to_va, *from_va;
+	unsigned size;
+	int ret = 0;
+
+	zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+	spin_lock(&zbpg->lock);
+	if (list_empty(&zbpg->bud_list)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	ASSERT_SENTINEL(zh, ZBH);
+	BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+	to_va = kmap_atomic(page, KM_USER0);
+	size = zh->size;
+	from_va = zbud_data(zh, size);
+	ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
+	BUG_ON(ret != LZO_E_OK);
+	BUG_ON(out_len != PAGE_SIZE);
+	kunmap_atomic(to_va, KM_USER0);
+out:
+	spin_unlock(&zbpg->lock);
+	return ret;
+}
+
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
+						uint16_t poolid);
+static void zcache_put_pool(struct tmem_pool *pool);
+
+static void zbud_init(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&zbud_buddied_list);
+	zcache_zbud_buddied_count = 0;
+	for (i = 0; i < NCHUNKS; i++) {
+		INIT_LIST_HEAD(&zbud_unbuddied[i].list);
+		zbud_unbuddied[i].count = 0;
+	}
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * These sysfs routines show a nice distribution of how many zbpg's are
+ * currently (and have ever been placed) in each unbuddied list.  It's fun
+ * to watch but can probably go away before final merge.
+ */
+static int zbud_show_unbuddied_list_counts(char *buf)
+{
+	int i;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++)
+		p += sprintf(p, "%u ", zbud_unbuddied[i].count);
+	return p - buf;
+}
+
+static int zbud_show_cumul_chunk_counts(char *buf)
+{
+	unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
+	unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
+	unsigned long total_chunks_lte_42 = 0;
+	char *p = buf;
+
+	for (i = 0; i < NCHUNKS; i++) {
+		p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
+		chunks += zbud_cumul_chunk_counts[i];
+		total_chunks += zbud_cumul_chunk_counts[i];
+		sum_total_chunks += i * zbud_cumul_chunk_counts[i];
+		if (i == 21)
+			total_chunks_lte_21 = total_chunks;
+		if (i == 32)
+			total_chunks_lte_32 = total_chunks;
+		if (i == 42)
+			total_chunks_lte_42 = total_chunks;
+	}
+	p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
+		total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
+		chunks == 0 ? 0 : sum_total_chunks / chunks);
+	return p - buf;
+}
+#endif
+
+/*
+ * zcache core code starts here
+ */
+
+/* useful stats not collected by cleancache or frontswap */
+static unsigned long zcache_flush_total;
+static unsigned long zcache_flush_found;
+static unsigned long zcache_flobj_total;
+static unsigned long zcache_flobj_found;
+static unsigned long zcache_failed_eph_puts;
+
+/*
+ * Tmem operations assume the poolid implies the invoking client.
+ * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
+ * RAMster has each client numbered by cluster node, and a KVM version
+ * of zcache would have one client per guest and each client might
+ * have a poolid==N.
+ */
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
+{
+	struct tmem_pool *pool = NULL;
+	struct zcache_client *cli = NULL;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else {
+		if (cli_id >= MAX_CLIENTS)
+			goto out;
+		cli = &zcache_clients[cli_id];
+		if (cli == NULL)
+			goto out;
+		atomic_inc(&cli->refcount);
+	}
+	if (poolid < MAX_POOLS_PER_CLIENT) {
+		pool = cli->tmem_pools[poolid];
+		if (pool != NULL)
+			atomic_inc(&pool->refcount);
+	}
+out:
+	return pool;
+}
+
+static void zcache_put_pool(struct tmem_pool *pool)
+{
+	struct zcache_client *cli = NULL;
+
+	if (pool == NULL)
+		BUG();
+	cli = pool->client;
+	atomic_dec(&pool->refcount);
+	atomic_dec(&cli->refcount);
+}
+
+int zcache_new_client(uint16_t cli_id)
+{
+	struct zcache_client *cli = NULL;
+	int ret = -1;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	if (cli->allocated)
+		goto out;
+	cli->allocated = 1;
+	ret = 0;
+out:
+	return ret;
+}
+
+/* counters for debugging */
+static unsigned long zcache_failed_get_free_pages;
+static unsigned long zcache_failed_alloc;
+static unsigned long zcache_put_to_flush;
+static unsigned long zcache_aborted_preload;
+static unsigned long zcache_aborted_shrink;
+
+/*
+ * Ensure that memory allocation requests in zcache don't result
+ * in direct reclaim requests via the shrinker, which would cause
+ * an infinite loop.  Maybe a GFP flag would be better?
+ */
+static DEFINE_SPINLOCK(zcache_direct_reclaim_lock);
+
+/*
+ * for now, used named slabs so can easily track usage; later can
+ * either just use kmalloc, or perhaps add a slab-like allocator
+ * to more carefully manage total memory utilization
+ */
+static struct kmem_cache *zcache_objnode_cache;
+static struct kmem_cache *zcache_obj_cache;
+static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_obj_count_max;
+static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_objnode_count_max;
+
+/*
+ * to avoid memory allocation recursion (e.g. due to direct reclaim), we
+ * preload all necessary data structures so the hostops callbacks never
+ * actually do a malloc
+ */
+struct zcache_preload {
+	void *page;
+	struct tmem_obj *obj;
+	int nr;
+	struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
+};
+static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
+
+static int zcache_do_preload(struct tmem_pool *pool)
+{
+	struct zcache_preload *kp;
+	struct tmem_objnode *objnode;
+	struct tmem_obj *obj;
+	void *page;
+	int ret = -ENOMEM;
+
+	if (unlikely(zcache_objnode_cache == NULL))
+		goto out;
+	if (unlikely(zcache_obj_cache == NULL))
+		goto out;
+	if (!spin_trylock(&zcache_direct_reclaim_lock)) {
+		zcache_aborted_preload++;
+		goto out;
+	}
+	preempt_disable();
+	kp = &__get_cpu_var(zcache_preloads);
+	while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
+		preempt_enable_no_resched();
+		objnode = kmem_cache_alloc(zcache_objnode_cache,
+				ZCACHE_GFP_MASK);
+		if (unlikely(objnode == NULL)) {
+			zcache_failed_alloc++;
+			goto unlock_out;
+		}
+		preempt_disable();
+		kp = &__get_cpu_var(zcache_preloads);
+		if (kp->nr < ARRAY_SIZE(kp->objnodes))
+			kp->objnodes[kp->nr++] = objnode;
+		else
+			kmem_cache_free(zcache_objnode_cache, objnode);
+	}
+	preempt_enable_no_resched();
+	obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
+	if (unlikely(obj == NULL)) {
+		zcache_failed_alloc++;
+		goto unlock_out;
+	}
+	page = qcache_alloc();
+	if (unlikely(page == NULL)) {
+		zcache_failed_get_free_pages++;
+		kmem_cache_free(zcache_obj_cache, obj);
+		goto unlock_out;
+	}
+	preempt_disable();
+	kp = &__get_cpu_var(zcache_preloads);
+	if (kp->obj == NULL)
+		kp->obj = obj;
+	else
+		kmem_cache_free(zcache_obj_cache, obj);
+	if (kp->page == NULL)
+		kp->page = page;
+	else
+		qcache_free(page);
+	ret = 0;
+unlock_out:
+	spin_unlock(&zcache_direct_reclaim_lock);
+out:
+	return ret;
+}
+
+static void *zcache_get_free_page(void)
+{
+	struct zcache_preload *kp;
+	void *page;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	page = kp->page;
+	BUG_ON(page == NULL);
+	kp->page = NULL;
+	return page;
+}
+
+/*
+ * zcache implementation for tmem host ops
+ */
+
+static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
+{
+	struct tmem_objnode *objnode = NULL;
+	unsigned long count;
+	struct zcache_preload *kp;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	if (kp->nr <= 0)
+		goto out;
+	objnode = kp->objnodes[kp->nr - 1];
+	BUG_ON(objnode == NULL);
+	kp->objnodes[kp->nr - 1] = NULL;
+	kp->nr--;
+	count = atomic_inc_return(&zcache_curr_objnode_count);
+	if (count > zcache_curr_objnode_count_max)
+		zcache_curr_objnode_count_max = count;
+out:
+	return objnode;
+}
+
+static void zcache_objnode_free(struct tmem_objnode *objnode,
+					struct tmem_pool *pool)
+{
+	atomic_dec(&zcache_curr_objnode_count);
+	BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
+	kmem_cache_free(zcache_objnode_cache, objnode);
+}
+
+static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
+{
+	struct tmem_obj *obj = NULL;
+	unsigned long count;
+	struct zcache_preload *kp;
+
+	kp = &__get_cpu_var(zcache_preloads);
+	obj = kp->obj;
+	BUG_ON(obj == NULL);
+	kp->obj = NULL;
+	count = atomic_inc_return(&zcache_curr_obj_count);
+	if (count > zcache_curr_obj_count_max)
+		zcache_curr_obj_count_max = count;
+	return obj;
+}
+
+static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
+{
+	atomic_dec(&zcache_curr_obj_count);
+	BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
+	kmem_cache_free(zcache_obj_cache, obj);
+}
+
+static void zcache_flush_all_obj(void)
+{
+	struct tmem_pool *pool;
+	int pool_id;
+	struct zcache_preload *kp;
+
+	kp = &__get_cpu_var(zcache_preloads);
+
+	for (pool_id = 0; pool_id < MAX_POOLS_PER_CLIENT; pool_id++) {
+		pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
+		tmem_flush_pool(pool);
+	}
+	if (kp->page) {
+		qcache_free(kp->page);
+		kp->page = NULL;
+	}
+	if (zcache_qc_used)
+		pr_warn("pages used not 0 after qcache flush all, is %ld\n",
+			zcache_qc_used);
+}
+
+/*
+ * When zcache is disabled ("frozen"), pools can be created and destroyed,
+ * but all puts (and thus all other operations that require memory allocation)
+ * must fail.  If zcache is unfrozen, accepts puts, then frozen again,
+ * data consistency requires all puts while frozen to be converted into
+ * flushes.
+ */
+static bool zcache_freeze;
+
+static void zcache_control(bool freeze)
+{
+	zcache_freeze = freeze;
+}
+
+static struct tmem_hostops zcache_hostops = {
+	.obj_alloc = zcache_obj_alloc,
+	.obj_free = zcache_obj_free,
+	.objnode_alloc = zcache_objnode_alloc,
+	.objnode_free = zcache_objnode_free,
+	.flush_all_obj = zcache_flush_all_obj,
+	.control = zcache_control,
+};
+
+/*
+ * zcache implementations for PAM page descriptor ops
+ */
+
+static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_eph_pampd_count_max;
+
+/* forward reference */
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
+
+static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
+				struct tmem_pool *pool, struct tmem_oid *oid,
+				 uint32_t index)
+{
+	void *pampd = NULL, *cdata;
+	size_t clen;
+	int ret;
+	unsigned long count;
+	struct page *page = (struct page *)(data);
+	struct zcache_client *cli = pool->client;
+	uint16_t client_id = get_client_id_from_client(cli);
+
+	ret = zcache_compress(page, &cdata, &clen);
+	if (ret == 0)
+		goto out;
+	if (clen == 0 || clen > zbud_max_buddy_size()) {
+		zcache_compress_poor++;
+		goto out;
+	}
+	pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
+					index, page, cdata, clen);
+	if (pampd != NULL) {
+		count = atomic_inc_return(&zcache_curr_eph_pampd_count);
+		if (count > zcache_curr_eph_pampd_count_max)
+			zcache_curr_eph_pampd_count_max = count;
+	}
+out:
+	return pampd;
+}
+
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
+					void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oid, uint32_t index)
+{
+	BUG();
+	return 0;
+}
+
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
+					void *pampd, struct tmem_pool *pool,
+					struct tmem_oid *oid, uint32_t index)
+{
+	int ret = 0;
+
+	zbud_decompress((struct page *)(data), pampd);
+	zbud_free_and_delist((struct zbud_hdr *)pampd);
+	atomic_dec(&zcache_curr_eph_pampd_count);
+	return ret;
+}
+
+/*
+ * free the pampd and remove it from any zcache lists
+ * pampd must no longer be pointed to from any tmem data structures!
+ */
+static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
+				struct tmem_oid *oid, uint32_t index)
+{
+	zbud_free_and_delist((struct zbud_hdr *)pampd);
+	atomic_dec(&zcache_curr_eph_pampd_count);
+	BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
+}
+
+static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj)
+{
+}
+
+static void zcache_pampd_new_obj(struct tmem_obj *obj)
+{
+}
+
+static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj)
+{
+	return -1;
+}
+
+static bool zcache_pampd_is_remote(void *pampd)
+{
+	return 0;
+}
+
+static struct tmem_pamops zcache_pamops = {
+	.create = zcache_pampd_create,
+	.get_data = zcache_pampd_get_data,
+	.get_data_and_free = zcache_pampd_get_data_and_free,
+	.free = zcache_pampd_free,
+	.free_obj = zcache_pampd_free_obj,
+	.new_obj = zcache_pampd_new_obj,
+	.replace_in_obj = zcache_pampd_replace_in_obj,
+	.is_remote = zcache_pampd_is_remote,
+};
+
+/*
+ * zcache compression/decompression and related per-cpu stuff
+ */
+
+#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
+#define LZO_DSTMEM_PAGE_ORDER 1
+static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
+static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
+
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
+{
+	int ret = 0;
+	unsigned char *dmem = __get_cpu_var(zcache_dstmem);
+	unsigned char *wmem = __get_cpu_var(zcache_workmem);
+	char *from_va;
+
+	BUG_ON(!irqs_disabled());
+	if (unlikely(dmem == NULL || wmem == NULL))
+		goto out;  /* no buffer, so can't compress */
+	from_va = kmap_atomic(from, KM_USER0);
+	mb();
+	ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
+	BUG_ON(ret != LZO_E_OK);
+	*out_va = dmem;
+	kunmap_atomic(from_va, KM_USER0);
+	ret = 1;
+out:
+	return ret;
+}
+
+#ifdef CONFIG_SYSFS
+#define ZCACHE_SYSFS_RO(_name) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+		return sprintf(buf, "%lu\n", zcache_##_name); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
+	static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+				struct kobj_attribute *attr, char *buf) \
+	{ \
+	    return _func(buf); \
+	} \
+	static struct kobj_attribute zcache_##_name##_attr = { \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = zcache_##_name##_show, \
+	}
+
+ZCACHE_SYSFS_RO(curr_obj_count_max);
+ZCACHE_SYSFS_RO(curr_objnode_count_max);
+ZCACHE_SYSFS_RO(flush_total);
+ZCACHE_SYSFS_RO(flush_found);
+ZCACHE_SYSFS_RO(flobj_total);
+ZCACHE_SYSFS_RO(flobj_found);
+ZCACHE_SYSFS_RO(failed_eph_puts);
+ZCACHE_SYSFS_RO(zbud_curr_zbytes);
+ZCACHE_SYSFS_RO(zbud_cumul_zpages);
+ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
+ZCACHE_SYSFS_RO(zbud_buddied_count);
+ZCACHE_SYSFS_RO(failed_get_free_pages);
+ZCACHE_SYSFS_RO(failed_alloc);
+ZCACHE_SYSFS_RO(put_to_flush);
+ZCACHE_SYSFS_RO(aborted_preload);
+ZCACHE_SYSFS_RO(aborted_shrink);
+ZCACHE_SYSFS_RO(compress_poor);
+ZCACHE_SYSFS_RO(mean_compress_poor);
+ZCACHE_SYSFS_RO(qc_allocated);
+ZCACHE_SYSFS_RO(qc_freed);
+ZCACHE_SYSFS_RO(qc_used);
+ZCACHE_SYSFS_RO(qc_max_used);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
+ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
+ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
+			zbud_show_unbuddied_list_counts);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
+			zbud_show_cumul_chunk_counts);
+
+static struct attribute *qcache_attrs[] = {
+	&zcache_curr_obj_count_attr.attr,
+	&zcache_curr_obj_count_max_attr.attr,
+	&zcache_curr_objnode_count_attr.attr,
+	&zcache_curr_objnode_count_max_attr.attr,
+	&zcache_flush_total_attr.attr,
+	&zcache_flobj_total_attr.attr,
+	&zcache_flush_found_attr.attr,
+	&zcache_flobj_found_attr.attr,
+	&zcache_failed_eph_puts_attr.attr,
+	&zcache_compress_poor_attr.attr,
+	&zcache_mean_compress_poor_attr.attr,
+	&zcache_zbud_curr_raw_pages_attr.attr,
+	&zcache_zbud_curr_zpages_attr.attr,
+	&zcache_zbud_curr_zbytes_attr.attr,
+	&zcache_zbud_cumul_zpages_attr.attr,
+	&zcache_zbud_cumul_zbytes_attr.attr,
+	&zcache_zbud_buddied_count_attr.attr,
+	&zcache_failed_get_free_pages_attr.attr,
+	&zcache_failed_alloc_attr.attr,
+	&zcache_put_to_flush_attr.attr,
+	&zcache_aborted_preload_attr.attr,
+	&zcache_aborted_shrink_attr.attr,
+	&zcache_zbud_unbuddied_list_counts_attr.attr,
+	&zcache_zbud_cumul_chunk_counts_attr.attr,
+	&zcache_qc_allocated_attr.attr,
+	&zcache_qc_freed_attr.attr,
+	&zcache_qc_used_attr.attr,
+	&zcache_qc_max_used_attr.attr,
+	NULL,
+};
+
+static struct attribute_group qcache_attr_group = {
+	.attrs = qcache_attrs,
+	.name = "qcache",
+};
+
+#endif /* CONFIG_SYSFS */
+
+/*
+ * zcache shims between cleancache ops and tmem
+ */
+
+static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+				uint32_t index, struct page *page)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+
+	BUG_ON(!irqs_disabled());
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	if (unlikely(pool == NULL))
+		goto out;
+	if (!zcache_freeze && zcache_do_preload(pool) == 0) {
+		/* preload does preempt_disable on success */
+		ret = tmem_put(pool, oidp, index, (char *)(page),
+				PAGE_SIZE, 0, is_ephemeral(pool));
+		if (ret < 0) {
+			zcache_failed_eph_puts++;
+		}
+		zcache_put_pool(pool);
+		preempt_enable_no_resched();
+	} else {
+		zcache_put_to_flush++;
+		if (atomic_read(&pool->obj_count) > 0)
+			/* the put fails whether the flush succeeds or not */
+			(void)tmem_flush_page(pool, oidp, index);
+		zcache_put_pool(pool);
+	}
+out:
+	return ret;
+}
+
+static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+				uint32_t index, struct page *page)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	unsigned long flags;
+	size_t size = PAGE_SIZE;
+
+	local_irq_save(flags);
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_get(pool, oidp, index, (char *)(page),
+					&size, 0, is_ephemeral(pool));
+		zcache_put_pool(pool);
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+
+static int zcache_flush_page(int cli_id, int pool_id,
+				struct tmem_oid *oidp, uint32_t index)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	zcache_flush_total++;
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_flush_page(pool, oidp, index);
+		zcache_put_pool(pool);
+	}
+	if (ret >= 0)
+		zcache_flush_found++;
+	local_irq_restore(flags);
+	return ret;
+}
+
+static int zcache_flush_object(int cli_id, int pool_id,
+				struct tmem_oid *oidp)
+{
+	struct tmem_pool *pool;
+	int ret = -1;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	zcache_flobj_total++;
+	pool = zcache_get_pool_by_id(cli_id, pool_id);
+	if (likely(pool != NULL)) {
+		if (atomic_read(&pool->obj_count) > 0)
+			ret = tmem_flush_object(pool, oidp);
+		zcache_put_pool(pool);
+	}
+	if (ret >= 0)
+		zcache_flobj_found++;
+	local_irq_restore(flags);
+	return ret;
+}
+
+static int zcache_destroy_pool(int cli_id, int pool_id)
+{
+	struct tmem_pool *pool = NULL;
+	struct zcache_client *cli = NULL;
+	int ret = -1;
+
+	if (pool_id < 0)
+		goto out;
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	atomic_inc(&cli->refcount);
+	pool = cli->tmem_pools[pool_id];
+	if (pool == NULL)
+		goto out;
+	cli->tmem_pools[pool_id] = NULL;
+	/* wait for pool activity on other cpus to quiesce */
+	while (atomic_read(&pool->refcount) != 0)
+		;
+	atomic_dec(&cli->refcount);
+	local_bh_disable();
+	ret = tmem_destroy_pool(pool);
+	local_bh_enable();
+	kfree(pool);
+	pr_info("qcache: destroyed pool id=%d, cli_id=%d\n",
+			pool_id, cli_id);
+out:
+	return ret;
+}
+
+static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
+{
+	int poolid = -1;
+	struct tmem_pool *pool;
+	struct zcache_client *cli = NULL;
+
+	if (cli_id == LOCAL_CLIENT)
+		cli = &zcache_host;
+	else if ((unsigned int)cli_id < MAX_CLIENTS)
+		cli = &zcache_clients[cli_id];
+	if (cli == NULL)
+		goto out;
+	atomic_inc(&cli->refcount);
+	pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
+	if (pool == NULL) {
+		pr_info("qcache: pool creation failed: out of memory\n");
+		goto out;
+	}
+
+	for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
+		if (cli->tmem_pools[poolid] == NULL)
+			break;
+	if (poolid >= MAX_POOLS_PER_CLIENT) {
+		pr_info("qcache: pool creation failed: max exceeded\n");
+		kfree(pool);
+		poolid = -1;
+		goto out;
+	}
+	atomic_set(&pool->refcount, 0);
+	pool->client = cli;
+	pool->pool_id = poolid;
+	tmem_new_pool(pool, flags);
+	cli->tmem_pools[poolid] = pool;
+	pr_info("qcache: created %s tmem pool, id=%d, client=%d\n",
+		flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+		poolid, cli_id);
+out:
+	if (cli != NULL)
+		atomic_dec(&cli->refcount);
+	return poolid;
+}
+
+/**********
+ * Two kernel functionalities currently can be layered on top of tmem.
+ * These are "cleancache" which is used as a second-chance cache for clean
+ * page cache pages; and "frontswap" which is used for swap pages
+ * to avoid writes to disk.  A generic "shim" is provided here for each
+ * to translate in-kernel semantics to zcache semantics.
+ */
+
+static void zcache_cleancache_put_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index, struct page *page)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+	if (likely(ind == index))
+		(void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page);
+}
+
+static int zcache_cleancache_get_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index, struct page *page)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+	int ret = -1;
+
+	if (likely(ind == index))
+		ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page);
+	return ret;
+}
+
+static void zcache_cleancache_flush_page(int pool_id,
+					struct cleancache_filekey key,
+					pgoff_t index)
+{
+	u32 ind = (u32) index;
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+	if (likely(ind == index))
+		(void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
+}
+
+static void zcache_cleancache_flush_inode(int pool_id,
+					struct cleancache_filekey key)
+{
+	struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+	(void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
+}
+
+static void zcache_cleancache_flush_fs(int pool_id)
+{
+	if (pool_id >= 0)
+		(void)zcache_destroy_pool(LOCAL_CLIENT, pool_id);
+}
+
+static int zcache_cleancache_init_fs(size_t pagesize)
+{
+	BUG_ON(sizeof(struct cleancache_filekey) !=
+				sizeof(struct tmem_oid));
+	BUG_ON(pagesize != PAGE_SIZE);
+	return zcache_new_pool(LOCAL_CLIENT, 0);
+}
+
+static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
+{
+	/* shared pools are unsupported and map to private */
+	BUG_ON(sizeof(struct cleancache_filekey) !=
+				sizeof(struct tmem_oid));
+	BUG_ON(pagesize != PAGE_SIZE);
+	return zcache_new_pool(LOCAL_CLIENT, 0);
+}
+
+static struct cleancache_ops zcache_cleancache_ops = {
+	.put_page = zcache_cleancache_put_page,
+	.get_page = zcache_cleancache_get_page,
+	.flush_page = zcache_cleancache_flush_page,
+	.flush_inode = zcache_cleancache_flush_inode,
+	.flush_fs = zcache_cleancache_flush_fs,
+	.init_shared_fs = zcache_cleancache_init_shared_fs,
+	.init_fs = zcache_cleancache_init_fs
+};
+
+struct cleancache_ops zcache_cleancache_register_ops(void)
+{
+	struct cleancache_ops old_ops =
+		cleancache_register_ops(&zcache_cleancache_ops);
+
+	return old_ops;
+}
+
+static int __init qcache_init(void)
+{
+	int ret = 0;
+	struct qcache_info *qc = &qcache_info;
+	struct fmem_data *fdp;
+	int bitmap_size;
+	unsigned int cpu;
+	struct cleancache_ops old_ops;
+
+#ifdef CONFIG_SYSFS
+	ret = sysfs_create_group(mm_kobj, &qcache_attr_group);
+	if (ret) {
+		pr_err("qcache: can't create sysfs\n");
+		goto out;
+	}
+#endif /* CONFIG_SYSFS */
+
+	fdp = fmem_get_info();
+	qc->addr = fdp->virt;
+	qc->pages = fdp->size >> PAGE_SHIFT;
+	if (!qc->pages)
+		goto out;
+
+	tmem_register_hostops(&zcache_hostops);
+	tmem_register_pamops(&zcache_pamops);
+	for_each_online_cpu(cpu) {
+		per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
+			GFP_KERNEL | __GFP_REPEAT,
+			LZO_DSTMEM_PAGE_ORDER),
+		per_cpu(zcache_workmem, cpu) =
+			kzalloc(LZO1X_MEM_COMPRESS,
+				GFP_KERNEL | __GFP_REPEAT);
+	}
+	zcache_objnode_cache = kmem_cache_create("zcache_objnode",
+				sizeof(struct tmem_objnode), 0, 0, NULL);
+	zcache_obj_cache = kmem_cache_create("zcache_obj",
+				sizeof(struct tmem_obj), 0, 0, NULL);
+	ret = zcache_new_client(LOCAL_CLIENT);
+	if (ret) {
+		pr_err("qcache: can't create client\n");
+		goto out;
+	}
+
+	zbud_init();
+	old_ops = zcache_cleancache_register_ops();
+	pr_info("qcache: cleancache enabled using kernel "
+		"transcendent memory and compression buddies\n");
+	if (old_ops.init_fs != NULL)
+		pr_warning("qcache: cleancache_ops overridden");
+
+
+	bitmap_size = BITS_TO_LONGS(qc->pages) * sizeof(long);
+
+	qc->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!qc->bitmap) {
+		pr_info("can't allocate qcache bitmap!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	spin_lock_init(&qc->lock);
+
+	fmem_set_state(FMEM_T_STATE);
+
+out:
+	return ret;
+}
+
+module_init(qcache_init)
diff --git a/drivers/staging/qcache/tmem.c b/drivers/staging/qcache/tmem.c
new file mode 100644
index 0000000..8c9049c
--- /dev/null
+++ b/drivers/staging/qcache/tmem.c
@@ -0,0 +1,835 @@
+/*
+ * In-kernel transcendent memory (generic implementation)
+ *
+ * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
+ * "handles" (triples containing a pool id, and object id, and an index), to
+ * pages in a page-accessible memory (PAM).  Tmem references the PAM pages via
+ * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
+ * set of functions (pamops).  Each pampd contains some representation of
+ * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of
+ * pages and must be able to insert, find, and delete these pages at a
+ * potential frequency of thousands per second concurrently across many CPUs,
+ * (and, if used with KVM, across many vcpus across many guests).
+ * Tmem is tracked with a hierarchy of data structures, organized by
+ * the elements in a handle-tuple: pool_id, object_id, and page index.
+ * One or more "clients" (e.g. guests) each provide one or more tmem_pools.
+ * Each pool, contains a hash table of rb_trees of tmem_objs.  Each
+ * tmem_obj contains a radix-tree-like tree of pointers, with intermediate
+ * nodes called tmem_objnodes.  Each leaf pointer in this tree points to
+ * a pampd, which is accessible only through a small set of callbacks
+ * registered by the PAM implementation (see tmem_register_pamops). Tmem
+ * does all memory allocation via a set of callbacks registered by the tmem
+ * host implementation (e.g. see tmem_register_hostops).
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+
+#include "tmem.h"
+
+/* data structure sentinels used for debugging... see tmem.h */
+#define POOL_SENTINEL 0x87658765
+#define OBJ_SENTINEL 0x12345678
+#define OBJNODE_SENTINEL 0xfedcba09
+
+static bool tmem_enabled;
+
+static void lock_tmem_state(void)
+{
+	lock_fmem_state();
+}
+
+static void unlock_tmem_state(void)
+{
+	unlock_fmem_state();
+}
+
+/*
+ * A tmem host implementation must use this function to register callbacks
+ * for memory allocation.
+ */
+static struct tmem_hostops tmem_hostops;
+
+static void tmem_objnode_tree_init(void);
+
+void tmem_register_hostops(struct tmem_hostops *m)
+{
+	tmem_objnode_tree_init();
+	tmem_hostops = *m;
+}
+
+/*
+ * A tmem host implementation must use this function to register
+ * callbacks for a page-accessible memory (PAM) implementation
+ */
+static struct tmem_pamops tmem_pamops;
+
+void tmem_register_pamops(struct tmem_pamops *m)
+{
+	tmem_pamops = *m;
+}
+
+/*
+ * Oid's are potentially very sparse and tmem_objs may have an indeterminately
+ * short life, being added and deleted at a relatively high frequency.
+ * So an rb_tree is an ideal data structure to manage tmem_objs.  But because
+ * of the potentially huge number of tmem_objs, each pool manages a hashtable
+ * of rb_trees to reduce search, insert, delete, and rebalancing time.
+ * Each hashbucket also has a lock to manage concurrent access.
+ *
+ * The following routines manage tmem_objs.  When any tmem_obj is accessed,
+ * the hashbucket lock must be held.
+ */
+
+/* searches for object==oid in pool, returns locked object if found */
+static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
+					struct tmem_oid *oidp)
+{
+	struct rb_node *rbnode;
+	struct tmem_obj *obj;
+
+	rbnode = hb->obj_rb_root.rb_node;
+	while (rbnode) {
+		BUG_ON(RB_EMPTY_NODE(rbnode));
+		obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
+		switch (tmem_oid_compare(oidp, &obj->oid)) {
+		case 0: /* equal */
+			goto out;
+		case -1:
+			rbnode = rbnode->rb_left;
+			break;
+		case 1:
+			rbnode = rbnode->rb_right;
+			break;
+		}
+	}
+	obj = NULL;
+out:
+	return obj;
+}
+
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *);
+
+/* free an object that has no more pampds in it */
+static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb)
+{
+	struct tmem_pool *pool;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pampd_count > 0);
+	pool = obj->pool;
+	BUG_ON(pool == NULL);
+	if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */
+		tmem_pampd_destroy_all_in_obj(obj);
+	BUG_ON(obj->objnode_tree_root != NULL);
+	BUG_ON((long)obj->objnode_count != 0);
+	atomic_dec(&pool->obj_count);
+	BUG_ON(atomic_read(&pool->obj_count) < 0);
+	INVERT_SENTINEL(obj, OBJ);
+	obj->pool = NULL;
+	tmem_oid_set_invalid(&obj->oid);
+	rb_erase(&obj->rb_tree_node, &hb->obj_rb_root);
+}
+
+/*
+ * initialize, and insert an tmem_object_root (called only if find failed)
+ */
+static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb,
+					struct tmem_pool *pool,
+					struct tmem_oid *oidp)
+{
+	struct rb_root *root = &hb->obj_rb_root;
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+	struct tmem_obj *this;
+
+	BUG_ON(pool == NULL);
+	atomic_inc(&pool->obj_count);
+	obj->objnode_tree_height = 0;
+	obj->objnode_tree_root = NULL;
+	obj->pool = pool;
+	obj->oid = *oidp;
+	obj->objnode_count = 0;
+	obj->pampd_count = 0;
+	(*tmem_pamops.new_obj)(obj);
+	SET_SENTINEL(obj, OBJ);
+	while (*new) {
+		BUG_ON(RB_EMPTY_NODE(*new));
+		this = rb_entry(*new, struct tmem_obj, rb_tree_node);
+		parent = *new;
+		switch (tmem_oid_compare(oidp, &this->oid)) {
+		case 0:
+			BUG(); /* already present; should never happen! */
+			break;
+		case -1:
+			new = &(*new)->rb_left;
+			break;
+		case 1:
+			new = &(*new)->rb_right;
+			break;
+		}
+	}
+	rb_link_node(&obj->rb_tree_node, parent, new);
+	rb_insert_color(&obj->rb_tree_node, root);
+}
+
+/*
+ * Tmem is managed as a set of tmem_pools with certain attributes, such as
+ * "ephemeral" vs "persistent".  These attributes apply to all tmem_objs
+ * and all pampds that belong to a tmem_pool.  A tmem_pool is created
+ * or deleted relatively rarely (for example, when a filesystem is
+ * mounted or unmounted.
+ */
+
+/* flush all data from a pool and, optionally, free it */
+static void tmem_pool_flush(struct tmem_pool *pool, bool destroy)
+{
+	struct rb_node *rbnode;
+	struct tmem_obj *obj;
+	struct tmem_hashbucket *hb = &pool->hashbucket[0];
+	int i;
+
+	BUG_ON(pool == NULL);
+	for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
+		spin_lock(&hb->lock);
+		rbnode = rb_first(&hb->obj_rb_root);
+		while (rbnode != NULL) {
+			obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
+			rbnode = rb_next(rbnode);
+			tmem_pampd_destroy_all_in_obj(obj);
+			tmem_obj_free(obj, hb);
+			(*tmem_hostops.obj_free)(obj, pool);
+		}
+		spin_unlock(&hb->lock);
+	}
+	if (destroy)
+		list_del(&pool->pool_list);
+}
+
+/*
+ * A tmem_obj contains a radix-tree-like tree in which the intermediate
+ * nodes are called tmem_objnodes.  (The kernel lib/radix-tree.c implementation
+ * is very specialized and tuned for specific uses and is not particularly
+ * suited for use from this code, though some code from the core algorithms has
+ * been reused, thus the copyright notices below).  Each tmem_objnode contains
+ * a set of pointers which point to either a set of intermediate tmem_objnodes
+ * or a set of of pampds.
+ *
+ * Portions Copyright (C) 2001 Momchil Velikov
+ * Portions Copyright (C) 2001 Christoph Hellwig
+ * Portions Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+
+struct tmem_objnode_tree_path {
+	struct tmem_objnode *objnode;
+	int offset;
+};
+
+/* objnode height_to_maxindex translation */
+static unsigned long tmem_objnode_tree_h2max[OBJNODE_TREE_MAX_PATH + 1];
+
+static void tmem_objnode_tree_init(void)
+{
+	unsigned int ht, tmp;
+
+	for (ht = 0; ht < ARRAY_SIZE(tmem_objnode_tree_h2max); ht++) {
+		tmp = ht * OBJNODE_TREE_MAP_SHIFT;
+		if (tmp >= OBJNODE_TREE_INDEX_BITS)
+			tmem_objnode_tree_h2max[ht] = ~0UL;
+		else
+			tmem_objnode_tree_h2max[ht] =
+			    (~0UL >> (OBJNODE_TREE_INDEX_BITS - tmp - 1)) >> 1;
+	}
+}
+
+static struct tmem_objnode *tmem_objnode_alloc(struct tmem_obj *obj)
+{
+	struct tmem_objnode *objnode;
+
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+	objnode = (*tmem_hostops.objnode_alloc)(obj->pool);
+	if (unlikely(objnode == NULL))
+		goto out;
+	objnode->obj = obj;
+	SET_SENTINEL(objnode, OBJNODE);
+	memset(&objnode->slots, 0, sizeof(objnode->slots));
+	objnode->slots_in_use = 0;
+	obj->objnode_count++;
+out:
+	return objnode;
+}
+
+static void tmem_objnode_free(struct tmem_objnode *objnode)
+{
+	struct tmem_pool *pool;
+	int i;
+
+	BUG_ON(objnode == NULL);
+	for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++)
+		BUG_ON(objnode->slots[i] != NULL);
+	ASSERT_SENTINEL(objnode, OBJNODE);
+	INVERT_SENTINEL(objnode, OBJNODE);
+	BUG_ON(objnode->obj == NULL);
+	ASSERT_SENTINEL(objnode->obj, OBJ);
+	pool = objnode->obj->pool;
+	BUG_ON(pool == NULL);
+	ASSERT_SENTINEL(pool, POOL);
+	objnode->obj->objnode_count--;
+	objnode->obj = NULL;
+	(*tmem_hostops.objnode_free)(objnode, pool);
+}
+
+/*
+ * lookup index in object and return associated pampd (or NULL if not found)
+ */
+static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
+{
+	unsigned int height, shift;
+	struct tmem_objnode **slot = NULL;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+
+	height = obj->objnode_tree_height;
+	if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height])
+		goto out;
+	if (height == 0 && obj->objnode_tree_root) {
+		slot = &obj->objnode_tree_root;
+		goto out;
+	}
+	shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
+	slot = &obj->objnode_tree_root;
+	while (height > 0) {
+		if (*slot == NULL)
+			goto out;
+		slot = (struct tmem_objnode **)
+			((*slot)->slots +
+			 ((index >> shift) & OBJNODE_TREE_MAP_MASK));
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	}
+out:
+	return slot != NULL ? (void **)slot : NULL;
+}
+
+static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
+{
+	struct tmem_objnode **slot;
+
+	slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
+	return slot != NULL ? *slot : NULL;
+}
+
+static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index,
+					void *new_pampd)
+{
+	struct tmem_objnode **slot;
+	void *ret = NULL;
+
+	slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
+	if ((slot != NULL) && (*slot != NULL)) {
+		void *old_pampd = *(void **)slot;
+		*(void **)slot = new_pampd;
+		(*tmem_pamops.free)(old_pampd, obj->pool, NULL, 0);
+		ret = new_pampd;
+	}
+	return ret;
+}
+
+static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index,
+					void *pampd)
+{
+	int ret = 0;
+	struct tmem_objnode *objnode = NULL, *newnode, *slot;
+	unsigned int height, shift;
+	int offset = 0;
+
+	/* if necessary, extend the tree to be higher  */
+	if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) {
+		height = obj->objnode_tree_height + 1;
+		if (index > tmem_objnode_tree_h2max[height])
+			while (index > tmem_objnode_tree_h2max[height])
+				height++;
+		if (obj->objnode_tree_root == NULL) {
+			obj->objnode_tree_height = height;
+			goto insert;
+		}
+		do {
+			newnode = tmem_objnode_alloc(obj);
+			if (!newnode) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			newnode->slots[0] = obj->objnode_tree_root;
+			newnode->slots_in_use = 1;
+			obj->objnode_tree_root = newnode;
+			obj->objnode_tree_height++;
+		} while (height > obj->objnode_tree_height);
+	}
+insert:
+	slot = obj->objnode_tree_root;
+	height = obj->objnode_tree_height;
+	shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
+	while (height > 0) {
+		if (slot == NULL) {
+			/* add a child objnode.  */
+			slot = tmem_objnode_alloc(obj);
+			if (!slot) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			if (objnode) {
+
+				objnode->slots[offset] = slot;
+				objnode->slots_in_use++;
+			} else
+				obj->objnode_tree_root = slot;
+		}
+		/* go down a level */
+		offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
+		objnode = slot;
+		slot = objnode->slots[offset];
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	}
+	BUG_ON(slot != NULL);
+	if (objnode) {
+		objnode->slots_in_use++;
+		objnode->slots[offset] = pampd;
+	} else
+		obj->objnode_tree_root = pampd;
+	obj->pampd_count++;
+out:
+	return ret;
+}
+
+static void *tmem_pampd_delete_from_obj(struct tmem_obj *obj, uint32_t index)
+{
+	struct tmem_objnode_tree_path path[OBJNODE_TREE_MAX_PATH + 1];
+	struct tmem_objnode_tree_path *pathp = path;
+	struct tmem_objnode *slot = NULL;
+	unsigned int height, shift;
+	int offset;
+
+	BUG_ON(obj == NULL);
+	ASSERT_SENTINEL(obj, OBJ);
+	BUG_ON(obj->pool == NULL);
+	ASSERT_SENTINEL(obj->pool, POOL);
+	height = obj->objnode_tree_height;
+	if (index > tmem_objnode_tree_h2max[height])
+		goto out;
+	slot = obj->objnode_tree_root;
+	if (height == 0 && obj->objnode_tree_root) {
+		obj->objnode_tree_root = NULL;
+		goto out;
+	}
+	shift = (height - 1) * OBJNODE_TREE_MAP_SHIFT;
+	pathp->objnode = NULL;
+	do {
+		if (slot == NULL)
+			goto out;
+		pathp++;
+		offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
+		pathp->offset = offset;
+		pathp->objnode = slot;
+		slot = slot->slots[offset];
+		shift -= OBJNODE_TREE_MAP_SHIFT;
+		height--;
+	} while (height > 0);
+	if (slot == NULL)
+		goto out;
+	while (pathp->objnode) {
+		pathp->objnode->slots[pathp->offset] = NULL;
+		pathp->objnode->slots_in_use--;
+		if (pathp->objnode->slots_in_use) {
+			if (pathp->objnode == obj->objnode_tree_root) {
+				while (obj->objnode_tree_height > 0 &&
+				  obj->objnode_tree_root->slots_in_use == 1 &&
+				  obj->objnode_tree_root->slots[0]) {
+					struct tmem_objnode *to_free =
+						obj->objnode_tree_root;
+
+					obj->objnode_tree_root =
+							to_free->slots[0];
+					obj->objnode_tree_height--;
+					to_free->slots[0] = NULL;
+					to_free->slots_in_use = 0;
+					tmem_objnode_free(to_free);
+				}
+			}
+			goto out;
+		}
+		tmem_objnode_free(pathp->objnode); /* 0 slots used, free it */
+		pathp--;
+	}
+	obj->objnode_tree_height = 0;
+	obj->objnode_tree_root = NULL;
+
+out:
+	if (slot != NULL)
+		obj->pampd_count--;
+	BUG_ON(obj->pampd_count < 0);
+	return slot;
+}
+
+/* recursively walk the objnode_tree destroying pampds and objnodes */
+static void tmem_objnode_node_destroy(struct tmem_obj *obj,
+					struct tmem_objnode *objnode,
+					unsigned int ht)
+{
+	int i;
+
+	if (ht == 0)
+		return;
+	for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) {
+		if (objnode->slots[i]) {
+			if (ht == 1) {
+				obj->pampd_count--;
+				(*tmem_pamops.free)(objnode->slots[i],
+						obj->pool, NULL, 0);
+				objnode->slots[i] = NULL;
+				continue;
+			}
+			tmem_objnode_node_destroy(obj, objnode->slots[i], ht-1);
+			tmem_objnode_free(objnode->slots[i]);
+			objnode->slots[i] = NULL;
+		}
+	}
+}
+
+static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj)
+{
+	if (obj->objnode_tree_root == NULL)
+		return;
+	if (obj->objnode_tree_height == 0) {
+		obj->pampd_count--;
+		(*tmem_pamops.free)(obj->objnode_tree_root, obj->pool, NULL, 0);
+	} else {
+		tmem_objnode_node_destroy(obj, obj->objnode_tree_root,
+					obj->objnode_tree_height);
+		tmem_objnode_free(obj->objnode_tree_root);
+		obj->objnode_tree_height = 0;
+	}
+	obj->objnode_tree_root = NULL;
+	(*tmem_pamops.free_obj)(obj->pool, obj);
+}
+
+/*
+ * Tmem is operated on by a set of well-defined actions:
+ * "put", "get", "flush", "flush_object", "new pool" and "destroy pool".
+ * (The tmem ABI allows for subpages and exchanges but these operations
+ * are not included in this implementation.)
+ *
+ * These "tmem core" operations are implemented in the following functions.
+ */
+
+/*
+ * "Put" a page, e.g. copy a page from the kernel into newly allocated
+ * PAM space (if such space is available).  Tmem_put is complicated by
+ * a corner case: What if a page with matching handle already exists in
+ * tmem?  To guarantee coherency, one of two actions is necessary: Either
+ * the data for the page must be overwritten, or the page must be
+ * "flushed" so that the data is not accessible to a subsequent "get".
+ * Since these "duplicate puts" are relatively rare, this implementation
+ * always flushes for simplicity.
+ */
+int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
+		char *data, size_t size, bool raw, bool ephemeral)
+{
+	struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL;
+	void *pampd = NULL, *pampd_del = NULL;
+	int ret = -ENOMEM;
+	struct tmem_hashbucket *hb;
+
+	lock_tmem_state();
+	if (!tmem_enabled)
+		goto disabled;
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = objfound = tmem_obj_find(hb, oidp);
+	if (obj != NULL) {
+		pampd = tmem_pampd_lookup_in_obj(objfound, index);
+		if (pampd != NULL) {
+			/* if found, is a dup put, flush the old one */
+			pampd_del = tmem_pampd_delete_from_obj(obj, index);
+			BUG_ON(pampd_del != pampd);
+			(*tmem_pamops.free)(pampd, pool, oidp, index);
+			if (obj->pampd_count == 0) {
+				objnew = obj;
+				objfound = NULL;
+			}
+			pampd = NULL;
+		}
+	} else {
+		obj = objnew = (*tmem_hostops.obj_alloc)(pool);
+		if (unlikely(obj == NULL)) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		tmem_obj_init(obj, hb, pool, oidp);
+	}
+	BUG_ON(obj == NULL);
+	BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound));
+	pampd = (*tmem_pamops.create)(data, size, raw, ephemeral,
+					obj->pool, &obj->oid, index);
+	if (unlikely(pampd == NULL))
+		goto free;
+	ret = tmem_pampd_add_to_obj(obj, index, pampd);
+	if (unlikely(ret == -ENOMEM))
+		/* may have partially built objnode tree ("stump") */
+		goto delete_and_free;
+	goto out;
+
+delete_and_free:
+	(void)tmem_pampd_delete_from_obj(obj, index);
+free:
+	if (pampd)
+		(*tmem_pamops.free)(pampd, pool, NULL, 0);
+	if (objnew) {
+		tmem_obj_free(objnew, hb);
+		(*tmem_hostops.obj_free)(objnew, pool);
+	}
+out:
+	spin_unlock(&hb->lock);
+disabled:
+	unlock_tmem_state();
+	return ret;
+}
+
+/*
+ * "Get" a page, e.g. if one can be found, copy the tmem page with the
+ * matching handle from PAM space to the kernel.  By tmem definition,
+ * when a "get" is successful on an ephemeral page, the page is "flushed",
+ * and when a "get" is successful on a persistent page, the page is retained
+ * in tmem.  Note that to preserve
+ * coherency, "get" can never be skipped if tmem contains the data.
+ * That is, if a get is done with a certain handle and fails, any
+ * subsequent "get" must also fail (unless of course there is a
+ * "put" done with the same handle).
+
+ */
+int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
+		char *data, size_t *size, bool raw, int get_and_free)
+{
+	struct tmem_obj *obj;
+	void *pampd;
+	bool ephemeral = is_ephemeral(pool);
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+	bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
+	bool lock_held = false;
+
+	lock_tmem_state();
+	if (!tmem_enabled)
+		goto disabled;
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	lock_held = true;
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	if (free)
+		pampd = tmem_pampd_delete_from_obj(obj, index);
+	else
+		pampd = tmem_pampd_lookup_in_obj(obj, index);
+	if (pampd == NULL)
+		goto out;
+	if (free) {
+		if (obj->pampd_count == 0) {
+			tmem_obj_free(obj, hb);
+			(*tmem_hostops.obj_free)(obj, pool);
+			obj = NULL;
+		}
+	}
+	if (tmem_pamops.is_remote(pampd)) {
+		lock_held = false;
+		spin_unlock(&hb->lock);
+	}
+	if (free)
+		ret = (*tmem_pamops.get_data_and_free)(
+				data, size, raw, pampd, pool, oidp, index);
+	else
+		ret = (*tmem_pamops.get_data)(
+				data, size, raw, pampd, pool, oidp, index);
+	if (ret < 0)
+		goto out;
+	ret = 0;
+out:
+	if (lock_held)
+		spin_unlock(&hb->lock);
+disabled:
+	unlock_tmem_state();
+	return ret;
+}
+
+/*
+ * If a page in tmem matches the handle, "flush" this page from tmem such
+ * that any subsequent "get" does not succeed (unless, of course, there
+ * was another "put" with the same handle).
+ */
+int tmem_flush_page(struct tmem_pool *pool,
+				struct tmem_oid *oidp, uint32_t index)
+{
+	struct tmem_obj *obj;
+	void *pampd;
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	pampd = tmem_pampd_delete_from_obj(obj, index);
+	if (pampd == NULL)
+		goto out;
+	(*tmem_pamops.free)(pampd, pool, oidp, index);
+	if (obj->pampd_count == 0) {
+		tmem_obj_free(obj, hb);
+		(*tmem_hostops.obj_free)(obj, pool);
+	}
+	ret = 0;
+
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * If a page in tmem matches the handle, replace the page so that any
+ * subsequent "get" gets the new page.  Returns 0 if
+ * there was a page to replace, else returns -1.
+ */
+int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
+			uint32_t index, void *new_pampd)
+{
+	struct tmem_obj *obj;
+	int ret = -1;
+	struct tmem_hashbucket *hb;
+
+	lock_tmem_state();
+	if (!tmem_enabled)
+		goto disabled;
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd);
+	ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
+out:
+	spin_unlock(&hb->lock);
+disabled:
+	unlock_tmem_state();
+	return ret;
+}
+
+/*
+ * "Flush" all pages in tmem matching this oid.
+ */
+int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp)
+{
+	struct tmem_obj *obj;
+	struct tmem_hashbucket *hb;
+	int ret = -1;
+
+	hb = &pool->hashbucket[tmem_oid_hash(oidp)];
+	spin_lock(&hb->lock);
+	obj = tmem_obj_find(hb, oidp);
+	if (obj == NULL)
+		goto out;
+	tmem_pampd_destroy_all_in_obj(obj);
+	tmem_obj_free(obj, hb);
+	(*tmem_hostops.obj_free)(obj, pool);
+	ret = 0;
+
+out:
+	spin_unlock(&hb->lock);
+	return ret;
+}
+
+/*
+ * "Flush" all pages (and tmem_objs) from this tmem_pool and disable
+ * all subsequent access to this tmem_pool.
+ */
+int tmem_destroy_pool(struct tmem_pool *pool)
+{
+	int ret = -1;
+
+	if (pool == NULL)
+		goto out;
+	tmem_pool_flush(pool, 1);
+	ret = 0;
+out:
+	return ret;
+}
+
+int tmem_flush_pool(struct tmem_pool *pool)
+{
+	int ret = -1;
+
+	if (pool == NULL)
+		goto out;
+	tmem_pool_flush(pool, 0);
+	ret = 0;
+out:
+	return ret;
+}
+
+static LIST_HEAD(tmem_global_pool_list);
+
+/*
+ * Create a new tmem_pool with the provided flag and return
+ * a pool id provided by the tmem host implementation.
+ */
+void tmem_new_pool(struct tmem_pool *pool, uint32_t flags)
+{
+	int persistent = flags & TMEM_POOL_PERSIST;
+	int shared = flags & TMEM_POOL_SHARED;
+	struct tmem_hashbucket *hb = &pool->hashbucket[0];
+	int i;
+
+	for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
+		hb->obj_rb_root = RB_ROOT;
+		spin_lock_init(&hb->lock);
+	}
+	INIT_LIST_HEAD(&pool->pool_list);
+	atomic_set(&pool->obj_count, 0);
+	SET_SENTINEL(pool, POOL);
+	list_add_tail(&pool->pool_list, &tmem_global_pool_list);
+	pool->persistent = persistent;
+	pool->shared = shared;
+}
+
+/* The following must be called with tmem state locked */
+static void tmem_reset(void)
+{
+	(*tmem_hostops.flush_all_obj)();
+}
+
+void tmem_enable(bool reset)
+{
+	pr_info("turning tmem on\n");
+	tmem_enabled = true;
+
+	if (!reset)
+		return;
+
+	tmem_reset();
+	(*tmem_hostops.control)(false);
+}
+
+void tmem_disable(void)
+{
+	pr_info("turning tmem off\n");
+	(*tmem_hostops.control)(true);
+	tmem_enabled = false;
+}
diff --git a/drivers/staging/qcache/tmem.h b/drivers/staging/qcache/tmem.h
new file mode 100644
index 0000000..344561f
--- /dev/null
+++ b/drivers/staging/qcache/tmem.h
@@ -0,0 +1,214 @@
+/*
+ * tmem.h
+ *
+ * Transcendent memory
+ *
+ * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ */
+
+#ifndef _TMEM_H_
+#define _TMEM_H_
+
+#include <linux/types.h>
+#include <linux/highmem.h>
+#include <linux/hash.h>
+#include <linux/atomic.h>
+#include <linux/fmem.h>
+
+/*
+ * These are pre-defined by the Xen<->Linux ABI
+ */
+#define TMEM_PUT_PAGE			4
+#define TMEM_GET_PAGE			5
+#define TMEM_FLUSH_PAGE			6
+#define TMEM_FLUSH_OBJECT		7
+#define TMEM_POOL_PERSIST		1
+#define TMEM_POOL_SHARED		2
+#define TMEM_POOL_PRECOMPRESSED		4
+#define TMEM_POOL_PAGESIZE_SHIFT	4
+#define TMEM_POOL_PAGESIZE_MASK		0xf
+#define TMEM_POOL_RESERVED_BITS		0x00ffff00
+
+/*
+ * sentinels have proven very useful for debugging but can be removed
+ * or disabled before final merge.
+ */
+#define SENTINELS
+#ifdef SENTINELS
+#define DECL_SENTINEL uint32_t sentinel;
+#define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL)
+#define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL)
+#define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL)
+#define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL)
+#else
+#define DECL_SENTINEL
+#define SET_SENTINEL(_x, _y) do { } while (0)
+#define INVERT_SENTINEL(_x, _y) do { } while (0)
+#define ASSERT_SENTINEL(_x, _y) do { } while (0)
+#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
+#endif
+
+#define ASSERT_SPINLOCK(_l)	WARN_ON(!spin_is_locked(_l))
+
+/*
+ * A pool is the highest-level data structure managed by tmem and
+ * usually corresponds to a large independent set of pages such as
+ * a filesystem.  Each pool has an id, and certain attributes and counters.
+ * It also contains a set of hash buckets, each of which contains an rbtree
+ * of objects and a lock to manage concurrency within the pool.
+ */
+
+#define TMEM_HASH_BUCKET_BITS	8
+#define TMEM_HASH_BUCKETS	(1<<TMEM_HASH_BUCKET_BITS)
+
+struct tmem_hashbucket {
+	struct rb_root obj_rb_root;
+	spinlock_t lock;
+};
+
+struct tmem_pool {
+	void *client; /* "up" for some clients, avoids table lookup */
+	struct list_head pool_list;
+	uint32_t pool_id;
+	bool persistent;
+	bool shared;
+	atomic_t obj_count;
+	atomic_t refcount;
+	struct tmem_hashbucket hashbucket[TMEM_HASH_BUCKETS];
+	DECL_SENTINEL
+};
+
+#define is_persistent(_p)  (_p->persistent)
+#define is_ephemeral(_p)   (!(_p->persistent))
+
+/*
+ * An object id ("oid") is large: 192-bits (to ensure, for example, files
+ * in a modern filesystem can be uniquely identified).
+ */
+
+struct tmem_oid {
+	uint64_t oid[3];
+};
+
+static inline void tmem_oid_set_invalid(struct tmem_oid *oidp)
+{
+	oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL;
+}
+
+static inline bool tmem_oid_valid(struct tmem_oid *oidp)
+{
+	return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL ||
+		oidp->oid[2] != -1UL;
+}
+
+static inline int tmem_oid_compare(struct tmem_oid *left,
+					struct tmem_oid *right)
+{
+	int ret;
+
+	if (left->oid[2] == right->oid[2]) {
+		if (left->oid[1] == right->oid[1]) {
+			if (left->oid[0] == right->oid[0])
+				ret = 0;
+			else if (left->oid[0] < right->oid[0])
+				ret = -1;
+			else
+				return 1;
+		} else if (left->oid[1] < right->oid[1])
+			ret = -1;
+		else
+			ret = 1;
+	} else if (left->oid[2] < right->oid[2])
+		ret = -1;
+	else
+		ret = 1;
+	return ret;
+}
+
+static inline unsigned tmem_oid_hash(struct tmem_oid *oidp)
+{
+	return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2],
+				TMEM_HASH_BUCKET_BITS);
+}
+
+/*
+ * A tmem_obj contains an identifier (oid), pointers to the parent
+ * pool and the rb_tree to which it belongs, counters, and an ordered
+ * set of pampds, structured in a radix-tree-like tree.  The intermediate
+ * nodes of the tree are called tmem_objnodes.
+ */
+
+struct tmem_objnode;
+
+struct tmem_obj {
+	struct tmem_oid oid;
+	struct tmem_pool *pool;
+	struct rb_node rb_tree_node;
+	struct tmem_objnode *objnode_tree_root;
+	unsigned int objnode_tree_height;
+	unsigned long objnode_count;
+	long pampd_count;
+	void *extra; /* for private use by pampd implementation */
+	DECL_SENTINEL
+};
+
+#define OBJNODE_TREE_MAP_SHIFT 6
+#define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT)
+#define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1)
+#define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
+#define OBJNODE_TREE_MAX_PATH \
+		(OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2)
+
+struct tmem_objnode {
+	struct tmem_obj *obj;
+	DECL_SENTINEL
+	void *slots[OBJNODE_TREE_MAP_SIZE];
+	unsigned int slots_in_use;
+};
+
+/* pampd abstract datatype methods provided by the PAM implementation */
+struct tmem_pamops {
+	void *(*create)(char *, size_t, bool, int,
+			struct tmem_pool *, struct tmem_oid *, uint32_t);
+	int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *,
+				struct tmem_oid *, uint32_t);
+	int (*get_data_and_free)(char *, size_t *, bool, void *,
+				struct tmem_pool *, struct tmem_oid *,
+				uint32_t);
+	void (*free)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t);
+	void (*free_obj)(struct tmem_pool *, struct tmem_obj *);
+	bool (*is_remote)(void *);
+	void (*new_obj)(struct tmem_obj *);
+	int (*replace_in_obj)(void *, struct tmem_obj *);
+};
+extern void tmem_register_pamops(struct tmem_pamops *m);
+
+/* memory allocation methods provided by the host implementation */
+struct tmem_hostops {
+	struct tmem_obj *(*obj_alloc)(struct tmem_pool *);
+	void (*obj_free)(struct tmem_obj *, struct tmem_pool *);
+	struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *);
+	void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *);
+	void (*flush_all_obj)(void);
+	void (*control)(bool);
+};
+extern void tmem_register_hostops(struct tmem_hostops *m);
+
+/* core tmem accessor functions */
+extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			char *, size_t, bool, bool);
+extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			char *, size_t *, bool, int);
+extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
+			void *);
+extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
+			uint32_t index);
+extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
+extern int tmem_destroy_pool(struct tmem_pool *);
+extern int tmem_flush_pool(struct tmem_pool *);
+extern void tmem_new_pool(struct tmem_pool *, uint32_t);
+
+extern void tmem_enable(bool);
+extern void tmem_disable(void);
+#endif /* _TMEM_H */
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index af6f351..047df1a 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -373,12 +373,13 @@
 	char *name;
 	char buf[32], *b;
 	int once = 0, err = -1;
-	int (*notify)(uint32_t, const char *) = NULL;
+	int (*notify)(uint32_t, const char *);
 
 	strlcpy(buf, diag_clients, sizeof(buf));
 	b = strim(buf);
 
 	while (b) {
+		notify = NULL;
 		name = strsep(&b, ",");
 		/* Allow only first diag channel to update pid and serial no */
 		if (_android_dev->pdata && !once++)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index e084278..6282389 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -155,6 +155,7 @@
 #define CAP_ENDPTLISTADDR   (0x018UL)
 #define CAP_PORTSC          (0x044UL)
 #define CAP_DEVLC           (0x084UL)
+#define CAP_ENDPTPIPEID     (0x0BCUL)
 #define CAP_USBMODE         (hw_bank.lpm ? 0x0C8UL : 0x068UL)
 #define CAP_ENDPTSETUPSTAT  (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
 #define CAP_ENDPTPRIME      (hw_bank.lpm ? 0x0DCUL : 0x070UL)
@@ -1638,6 +1639,23 @@
 		if (!mReq->req.no_interrupt)
 			mReq->ptr->token  |= TD_IOC;
 	}
+
+	/* MSM Specific: updating the request as required for
+	 * SPS mode. Enable MSM proprietary DMA engine acording
+	 * to the UDC private data in the request.
+	 */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mReq->ptr->token = TD_STATUS_ACTIVE;
+			if (mReq->req.udc_priv & MSM_TBE)
+				mReq->ptr->next = TD_TERMINATE;
+			else
+				mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+			if (!mReq->req.no_interrupt)
+				mReq->ptr->token |= MSM_ETD_IOC;
+		}
+	}
+
 	mReq->ptr->page[0]  = mReq->req.dma;
 	for (i = 1; i < 5; i++)
 		mReq->ptr->page[i] =
@@ -1680,6 +1698,39 @@
 	}
 
 	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mEp->qh.ptr->td.next   |= MSM_ETD_TYPE;
+			i = hw_cread(CAP_ENDPTPIPEID +
+						 mEp->num * sizeof(u32), ~0);
+			/* Read current value of this EPs pipe id */
+			i = (mEp->dir == TX) ?
+				((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
+					(i & MSM_PIPE_ID_MASK);
+			/* If requested pipe id is different from current,
+			   then write it */
+			if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
+				if (mEp->dir == TX)
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK <<
+							MSM_TX_PIPE_ID_OFS,
+						(mReq->req.udc_priv &
+						 MSM_PIPE_ID_MASK)
+							<< MSM_TX_PIPE_ID_OFS);
+				else
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK,
+						mReq->req.udc_priv &
+							MSM_PIPE_ID_MASK);
+			}
+		}
+	}
+
 	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
 	mEp->qh.ptr->cap |=  QH_ZLT;
 
@@ -1712,6 +1763,10 @@
 	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
 		return -EBUSY;
 
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+		if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
+			(mReq->req.udc_priv & MSM_TBE))
+			return -EBUSY;
 	if (mReq->zptr) {
 		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
 			return -EBUSY;
@@ -1756,6 +1811,7 @@
 __acquires(mEp->lock)
 {
 	struct ci13xxx_ep *mEpTemp = mEp;
+	unsigned val;
 
 	trace("%p", mEp);
 
@@ -1771,6 +1827,21 @@
 			list_entry(mEp->qh.queue.next,
 				   struct ci13xxx_req, queue);
 		list_del_init(&mReq->queue);
+
+		/* MSM Specific: Clear end point proprietary register */
+		if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+			if (mReq->req.udc_priv & MSM_SPS_MODE) {
+				val = hw_cread(CAP_ENDPTPIPEID +
+					mEp->num * sizeof(u32),
+					~0);
+
+				if (val != MSM_EP_PIPE_ID_RESET_VAL)
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+						 mEp->num * sizeof(u32),
+						~0, MSM_EP_PIPE_ID_RESET_VAL);
+			}
+		}
 		mReq->req.status = -ESHUTDOWN;
 
 		if (mReq->req.complete != NULL) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index b917fe9..35b0712 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -25,6 +25,21 @@
 #define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
 #define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
 
+/* UDC private data:
+ *  16MSb - Vendor ID | 16 LSb Vendor private data
+ */
+#define CI13XX_REQ_VENDOR_ID(id)  (id & 0xFFFF0000UL)
+
+/* MSM specific */
+#define MSM_PIPE_ID_MASK         (0x1F)
+#define MSM_TX_PIPE_ID_OFS       (16)
+#define MSM_SPS_MODE             BIT(5)
+#define MSM_TBE                  BIT(6)
+#define MSM_ETD_TYPE             BIT(1)
+#define MSM_ETD_IOC              BIT(9)
+#define MSM_VENDOR_ID            BIT(16)
+#define MSM_EP_PIPE_ID_RESET_VAL 0x1F001F
+
 /******************************************************************************
  * STRUCTURES
  *****************************************************************************/
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index ccfd2e3..f492143 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -515,9 +515,11 @@
 	int rc = 0;
 
 	dev->in_desc = ep_choose(cdev->gadget,
-			&hs_bulk_in_desc, &fs_bulk_in_desc);
+			(struct usb_endpoint_descriptor *)f->hs_descriptors[1],
+			(struct usb_endpoint_descriptor *)f->descriptors[1]);
 	dev->out_desc = ep_choose(cdev->gadget,
-			&hs_bulk_out_desc, &fs_bulk_out_desc);
+			(struct usb_endpoint_descriptor *)f->hs_descriptors[2],
+			(struct usb_endpoint_descriptor *)f->descriptors[2]);
 	dev->in->driver_data = dev;
 	rc = usb_ep_enable(dev->in, dev->in_desc);
 	if (rc) {
@@ -669,10 +671,13 @@
 
 		temp += scnprintf(buf + temp, PAGE_SIZE - temp,
 				"---Name: %s---\n"
+				"endpoints: %s, %s\n"
 				"dpkts_tolaptop: %lu\n"
 				"dpkts_tomodem:  %lu\n"
 				"pkts_tolaptop_pending: %u\n",
-				ch->name, ctxt->dpkts_tolaptop,
+				ch->name,
+				ctxt->in->name, ctxt->out->name,
+				ctxt->dpkts_tolaptop,
 				ctxt->dpkts_tomodem,
 				ctxt->dpkts_tolaptop_pending);
 	}
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 32791d9..cbcf5ac 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -18,10 +18,10 @@
 #include <linux/spinlock.h>
 
 #include <mach/usb_gadget_xport.h>
+
 #include "u_rmnet.h"
 #include "gadget_chips.h"
 
-
 #define RMNET_NOTIFY_INTERVAL	5
 #define RMNET_MAX_NOTIFY_SIZE	sizeof(struct usb_cdc_notification)
 
@@ -66,6 +66,7 @@
 static unsigned int no_ctrl_smd_ports;
 static unsigned int no_ctrl_hsic_ports;
 static unsigned int no_data_bam_ports;
+static unsigned int no_data_bam2bam_ports;
 static unsigned int no_data_hsic_ports;
 static struct rmnet_ports {
 	enum transport_type		data_xport;
@@ -241,13 +242,16 @@
 	int	port_idx;
 	int	i;
 
-	pr_debug("%s: bam ports: %u data hsic ports: %u smd ports: %u"
-			" ctrl hsic ports: %u nr_rmnet_ports: %u\n",
-			__func__, no_data_bam_ports, no_data_hsic_ports,
-			no_ctrl_smd_ports, no_ctrl_hsic_ports, nr_rmnet_ports);
+	pr_debug("%s: bam ports: %u bam2bam ports: %u data hsic ports: %u"
+		" smd ports: %u ctrl hsic ports: %u"
+	" nr_rmnet_ports: %u\n",
+		__func__, no_data_bam_ports, no_data_bam2bam_ports,
+		no_data_hsic_ports, no_ctrl_smd_ports,
+		no_ctrl_hsic_ports, nr_rmnet_ports);
 
-	if (no_data_bam_ports) {
-		ret = gbam_setup(no_data_bam_ports);
+	if (no_data_bam_ports || no_data_bam2bam_ports) {
+		ret = gbam_setup(no_data_bam_ports,
+						 no_data_bam2bam_ports);
 		if (ret)
 			return ret;
 	}
@@ -329,7 +333,11 @@
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
 	switch (dxport) {
 	case USB_GADGET_XPORT_BAM:
-		ret = gbam_connect(&dev->port, port_num);
+	case USB_GADGET_XPORT_BAM2BAM:
+		/* currently only one connection (idx 0)
+		   is supported */
+		ret = gbam_connect(&dev->port, port_num,
+						   dxport, 0);
 		if (ret) {
 			pr_err("%s: gbam_connect failed: err:%d\n",
 					__func__, ret);
@@ -386,7 +394,8 @@
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
 	switch (dxport) {
 	case USB_GADGET_XPORT_BAM:
-		gbam_disconnect(&dev->port, port_num);
+	case USB_GADGET_XPORT_BAM2BAM:
+		gbam_disconnect(&dev->port, port_num, dxport);
 		break;
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_data_disconnect(&dev->port, port_num);
@@ -954,6 +963,7 @@
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
 	no_data_bam_ports = 0;
+	no_data_bam2bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
 	no_data_hsic_ports = 0;
 }
@@ -1013,6 +1023,10 @@
 		rmnet_port->data_xport_num = no_data_bam_ports;
 		no_data_bam_ports++;
 		break;
+	case USB_GADGET_XPORT_BAM2BAM:
+		rmnet_port->data_xport_num = no_data_bam2bam_ports;
+		no_data_bam2bam_ports++;
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		rmnet_port->data_xport_num = no_data_hsic_ports;
 		no_data_hsic_ports++;
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 70cbd2f..9605927 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -23,12 +23,17 @@
 #include <linux/bitops.h>
 #include <linux/termios.h>
 
+#include <mach/usb_gadget_xport.h>
+#include <mach/usb_bam.h>
+
 #include "u_rmnet.h"
 
 #define BAM_N_PORTS	1
+#define BAM2BAM_N_PORTS	1
 
 static struct workqueue_struct *gbam_wq;
 static int n_bam_ports;
+static int n_bam2bam_ports;
 static unsigned bam_ch_ids[] = { 8 };
 
 static const char *bam_ch_names[] = { "bam_dmux_ch_8" };
@@ -68,6 +73,11 @@
 
 #define BAM_CH_OPENED	BIT(0)
 #define BAM_CH_READY	BIT(1)
+#define SPS_PARAMS_PIPE_ID_MASK		(0x1F)
+#define SPS_PARAMS_SPS_MODE			BIT(5)
+#define SPS_PARAMS_TBE		        BIT(6)
+#define MSM_VENDOR_ID				BIT(16)
+
 struct bam_ch_info {
 	unsigned long		flags;
 	unsigned		id;
@@ -81,6 +91,13 @@
 	struct gbam_port	*port;
 	struct work_struct	write_tobam_w;
 
+	struct usb_request	*rx_req;
+	struct usb_request	*tx_req;
+
+	u8					src_pipe_idx;
+	u8					dst_pipe_idx;
+	u8					connection_idx;
+
 	/* stats */
 	unsigned int		pending_with_bam;
 	unsigned int		tohost_drp_cnt;
@@ -96,6 +113,7 @@
 	spinlock_t		port_lock;
 
 	struct grmnet		*port_usb;
+	struct grmnet		*gr;
 
 	struct bam_ch_info	data_ch;
 
@@ -108,7 +126,10 @@
 	struct platform_driver pdrv;
 } bam_ports[BAM_N_PORTS];
 
+struct gbam_port *bam2bam_ports[BAM2BAM_N_PORTS];
 static void gbam_start_rx(struct gbam_port *port);
+static void gbam_start_endless_rx(struct gbam_port *port);
+static void gbam_start_endless_tx(struct gbam_port *port);
 
 /*---------------misc functions---------------- */
 static void gbam_free_requests(struct usb_ep *ep, struct list_head *head)
@@ -273,10 +294,9 @@
 
 	while (d->pending_with_bam < BAM_PENDING_LIMIT) {
 		skb =  __skb_dequeue(&d->rx_skb_q);
-		if (!skb) {
-			spin_unlock_irqrestore(&port->port_lock, flags);
-			return;
-		}
+		if (!skb)
+			break;
+
 		d->pending_with_bam++;
 		d->to_modem++;
 
@@ -414,6 +434,20 @@
 	}
 }
 
+static void gbam_endless_rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_debug("%s status: %d\n", __func__, status);
+}
+
+static void gbam_endless_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_debug("%s status: %d\n", __func__, status);
+}
+
 static void gbam_start_rx(struct gbam_port *port)
 {
 	struct usb_request		*req;
@@ -469,6 +503,26 @@
 	spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
+static void gbam_start_endless_rx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+
+	status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start_endless_tx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+
+	status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
 static void gbam_start_io(struct gbam_port *port)
 {
 	unsigned long		flags;
@@ -520,6 +574,32 @@
 	}
 }
 
+static void gbam_free_buffers(struct gbam_port *port)
+{
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	struct bam_ch_info	*d;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	if (!port || !port->port_usb)
+		goto free_buf_out;
+
+	d = &port->data_ch;
+
+	gbam_free_requests(port->port_usb->in, &d->tx_idle);
+	gbam_free_requests(port->port_usb->out, &d->rx_idle);
+
+	while ((skb = __skb_dequeue(&d->tx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+	while ((skb = __skb_dequeue(&d->rx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+free_buf_out:
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
 static void gbam_disconnect_work(struct work_struct *w)
 {
 	struct gbam_port *port =
@@ -533,6 +613,22 @@
 	clear_bit(BAM_CH_OPENED, &d->flags);
 }
 
+static void gbam2bam_disconnect_work(struct work_struct *w)
+{
+	struct gbam_port *port =
+			container_of(w, struct gbam_port, disconnect_w);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	port->port_usb = 0;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	/* disable endpoints */
+	usb_ep_disable(port->gr->out);
+	usb_ep_disable(port->gr->in);
+
+}
+
 static void gbam_connect_work(struct work_struct *w)
 {
 	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
@@ -563,30 +659,47 @@
 	pr_debug("%s: done\n", __func__);
 }
 
-static void gbam_free_buffers(struct gbam_port *port)
+static void gbam2bam_connect_work(struct work_struct *w)
 {
-	struct sk_buff		*skb;
-	unsigned long		flags;
-	struct bam_ch_info	*d;
+	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct bam_ch_info *d = &port->data_ch;
+	u32 sps_params;
+	int ret;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
+						  &d->dst_pipe_idx);
+	if (ret) {
+		pr_err("%s: usb_bam_connect failed: err:%d\n",
+			__func__, ret);
+		return;
+	}
 
-	if (!port || !port->port_usb)
-		goto free_buf_out;
+	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
+	if (!d->rx_req)
+		return;
 
-	d = &port->data_ch;
+	d->rx_req->context = port;
+	d->rx_req->complete = gbam_endless_rx_complete;
+	d->rx_req->length = 0;
+	sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
+				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+	d->rx_req->udc_priv = sps_params;
+	d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL);
+	if (!d->tx_req)
+		return;
 
-	gbam_free_requests(port->port_usb->in, &d->tx_idle);
-	gbam_free_requests(port->port_usb->out, &d->rx_idle);
+	d->tx_req->context = port;
+	d->tx_req->complete = gbam_endless_tx_complete;
+	d->tx_req->length = 0;
+	sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
+				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+	d->tx_req->udc_priv = sps_params;
 
-	while ((skb = __skb_dequeue(&d->tx_skb_q)))
-		dev_kfree_skb_any(skb);
+	/* queue in & out requests */
+	gbam_start_endless_rx(port);
+	gbam_start_endless_tx(port);
 
-	while ((skb = __skb_dequeue(&d->rx_skb_q)))
-		dev_kfree_skb_any(skb);
-
-free_buf_out:
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	pr_debug("%s: done\n", __func__);
 }
 
 /* BAM data channel ready, allow attempt to open */
@@ -673,6 +786,13 @@
 	}
 }
 
+static void gbam2bam_port_free(int portno)
+{
+	struct gbam_port *port = bam2bam_ports[portno];
+
+	kfree(port);
+}
+
 static int gbam_port_alloc(int portno)
 {
 	struct gbam_port	*port;
@@ -709,6 +829,32 @@
 	pdrv->driver.owner = THIS_MODULE;
 
 	platform_driver_register(pdrv);
+	pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
+
+	return 0;
+}
+
+static int gbam2bam_port_alloc(int portno)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+
+	port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->port_num = portno;
+
+	/* port initialization */
+	spin_lock_init(&port->port_lock);
+
+	INIT_WORK(&port->connect_w, gbam2bam_connect_work);
+	INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
+
+	/* data ch */
+	d = &port->data_ch;
+	d->port = port;
+	bam2bam_ports[portno] = port;
 
 	pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
 
@@ -820,7 +966,7 @@
 static void gam_debugfs_init(void) { }
 #endif
 
-void gbam_disconnect(struct grmnet *gr, u8 port_num)
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
 {
 	struct gbam_port	*port;
 	unsigned long		flags;
@@ -828,8 +974,17 @@
 
 	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
 
-	if (port_num >= n_bam_ports) {
-		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+	if (trans == USB_GADGET_XPORT_BAM &&
+		port_num >= n_bam_ports) {
+		pr_err("%s: invalid bam portno#%d\n",
+			   __func__, port_num);
+		return;
+	}
+
+	if (trans == USB_GADGET_XPORT_BAM2BAM &&
+		port_num >= n_bam2bam_ports) {
+		pr_err("%s: invalid bam2bam portno#%d\n",
+			   __func__, port_num);
 		return;
 	}
 
@@ -837,24 +992,31 @@
 		pr_err("%s: grmnet port is null\n", __func__);
 		return;
 	}
+	if (trans == USB_GADGET_XPORT_BAM)
+		port = bam_ports[port_num].port;
+	else
+		port = bam2bam_ports[port_num];
 
-	port = bam_ports[port_num].port;
 	d = &port->data_ch;
+	port->gr = gr;
 
-	gbam_free_buffers(port);
+	if (trans == USB_GADGET_XPORT_BAM) {
+		gbam_free_buffers(port);
 
-	spin_lock_irqsave(&port->port_lock, flags);
-	port->port_usb = 0;
-	spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_lock_irqsave(&port->port_lock, flags);
+		port->port_usb = 0;
+		spin_unlock_irqrestore(&port->port_lock, flags);
 
-	/* disable endpoints */
-	usb_ep_disable(gr->out);
-	usb_ep_disable(gr->in);
+		/* disable endpoints */
+		usb_ep_disable(gr->out);
+		usb_ep_disable(gr->in);
+	}
 
 	queue_work(gbam_wq, &port->disconnect_w);
 }
 
-int gbam_connect(struct grmnet *gr, u8 port_num)
+int gbam_connect(struct grmnet *gr, u8 port_num,
+				 enum transport_type trans, u8 connection_idx)
 {
 	struct gbam_port	*port;
 	struct bam_ch_info	*d;
@@ -863,7 +1025,12 @@
 
 	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
 
-	if (port_num >= n_bam_ports) {
+	if (trans == USB_GADGET_XPORT_BAM && port_num >= n_bam_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return -ENODEV;
+	}
+
+	if (trans == USB_GADGET_XPORT_BAM2BAM && port_num >= n_bam2bam_ports) {
 		pr_err("%s: invalid portno#%d\n", __func__, port_num);
 		return -ENODEV;
 	}
@@ -873,7 +1040,11 @@
 		return -ENODEV;
 	}
 
-	port = bam_ports[port_num].port;
+	if (trans == USB_GADGET_XPORT_BAM)
+		port = bam_ports[port_num].port;
+	else
+		port = bam2bam_ports[port_num];
+
 	d = &port->data_ch;
 
 	ret = usb_ep_enable(gr->in, gr->in_desc);
@@ -896,29 +1067,35 @@
 	spin_lock_irqsave(&port->port_lock, flags);
 	port->port_usb = gr;
 
-	d->to_host = 0;
-	d->to_modem = 0;
-	d->pending_with_bam = 0;
-	d->tohost_drp_cnt = 0;
-	d->tomodem_drp_cnt = 0;
+	if (trans == USB_GADGET_XPORT_BAM) {
+		d->to_host = 0;
+		d->to_modem = 0;
+		d->pending_with_bam = 0;
+		d->tohost_drp_cnt = 0;
+		d->tomodem_drp_cnt = 0;
+	}
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
+	if (trans == USB_GADGET_XPORT_BAM2BAM)
+		d->connection_idx = connection_idx;
 
 	queue_work(gbam_wq, &port->connect_w);
 
 	return 0;
 }
 
-int gbam_setup(unsigned int count)
+int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
 {
 	int	i;
 	int	ret;
 
-	pr_debug("%s: requested ports:%d\n", __func__, count);
+	pr_debug("%s: requested BAM ports:%d and BAM2BAM ports:%d\n",
+			  __func__, no_bam_port, no_bam2bam_port);
 
-	if (!count || count > BAM_N_PORTS) {
-		pr_err("%s: Invalid num of ports count:%d\n",
-				__func__, count);
+	if ((!no_bam_port && !no_bam2bam_port) || no_bam_port > BAM_N_PORTS
+		|| no_bam2bam_port > BAM2BAM_N_PORTS) {
+		pr_err("%s: Invalid num of ports count:%d,%d\n",
+				__func__, no_bam_port, no_bam2bam_port);
 		return -EINVAL;
 	}
 
@@ -929,7 +1106,7 @@
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < no_bam_port; i++) {
 		n_bam_ports++;
 		ret = gbam_port_alloc(i);
 		if (ret) {
@@ -939,13 +1116,23 @@
 		}
 	}
 
+	for (i = 0; i < no_bam2bam_port; i++) {
+		n_bam2bam_ports++;
+		ret = gbam2bam_port_alloc(i);
+		if (ret) {
+			n_bam2bam_ports--;
+			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			goto free_bam_ports;
+		}
+	}
 	gbam_debugfs_init();
-
 	return 0;
+
 free_bam_ports:
 	for (i = 0; i < n_bam_ports; i++)
 		gbam_port_free(i);
-
+	for (i = 0; i < n_bam2bam_ports; i++)
+		gbam2bam_port_free(i);
 	destroy_workqueue(gbam_wq);
 
 	return ret;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index d8de31e..fd1e124 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,10 +48,10 @@
 	void (*connect)(struct grmnet *g);
 };
 
-int gbam_setup(unsigned int count);
-int gbam_connect(struct grmnet *, u8 port_num);
-void gbam_disconnect(struct grmnet *, u8 port_num);
-
+int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
+int gbam_connect(struct grmnet *gr, u8 port_num,
+				 enum transport_type trans, u8 connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
 int gsmd_ctrl_setup(unsigned int count);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 8b08b7a..90cbe54 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -544,12 +544,13 @@
 	}
 
 	for (i = 0; i < count; i++) {
+		n_rmnet_ctrl_ports++;
 		ret = grmnet_ctrl_smd_port_alloc(i);
 		if (ret) {
 			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			n_rmnet_ctrl_ports--;
 			goto free_ctrl_smd_ports;
 		}
-		n_rmnet_ctrl_ports++;
 	}
 
 	return 0;
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 0397428..11d388c 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -697,6 +697,8 @@
 
 	dev_dbg(&dev->udev->dev, "%s:\n", __func__);
 
+	platform_device_del(dev->pdev);
+
 	kfree(dev->in_ctlreq);
 	kfree(dev->readbuf);
 	kfree(dev->intbuf);
@@ -704,7 +706,6 @@
 	usb_free_urb(dev->readurb);
 	usb_free_urb(dev->inturb);
 
-	platform_device_del(dev->pdev);
 	__dev[id] = NULL;
 	ch_id--;
 
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 7c44a9a..6fe5b1d 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -779,7 +779,7 @@
 	usb_get_dev(udev);
 
 	if (iface_num != DUN_IFACE_NUM && iface_num != TETHERED_RMNET_IFACE_NUM)
-		return 0;
+		return -ENODEV;
 
 	numends = iface->cur_altsetting->desc.bNumEndpoints;
 	for (i = 0; i < numends; i++) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 2466246..dc3ff26 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1653,6 +1653,12 @@
 		msm_otg_reset(otg);
 		msm_otg_init_sm(motg);
 		otg->state = OTG_STATE_B_IDLE;
+		if (!test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(ID, &motg->inputs)) {
+			pm_runtime_put_noidle(otg->dev);
+			pm_runtime_suspend(otg->dev);
+			break;
+		}
 		/* FALL THROUGH */
 	case OTG_STATE_B_IDLE:
 		dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
@@ -1978,7 +1984,7 @@
 {
 	struct msm_otg *motg = s->private;
 
-	seq_printf(s, chg_to_string(motg->chg_type));
+	seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
 	return 0;
 }
 
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index e4fad5e..64fc6ea 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -406,6 +406,10 @@
 	portdata = usb_get_serial_port_data(port);
 	intfdata = serial->private;
 
+	/* explicitly set the driver mode to raw */
+	tty->raw = 0;
+	tty->real_raw = 0;
+
 	dbg("%s", __func__);
 
 	/* Start reading from the IN endpoint */
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 0f1d19b..c87119f 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3398,18 +3398,6 @@
 	HDMI_OUTP(0x002C, audio_info_ctrl_reg);
 }
 
-static void hdmi_msm_audio_ctrl_setup(boolean enabled, int delay)
-{
-	uint32 audio_pkt_ctrl_reg = 0;
-
-	/* Enable Packet Transmission */
-	audio_pkt_ctrl_reg |= enabled ? 0x00000001 : 0;
-	audio_pkt_ctrl_reg |= (delay << 4);
-
-	/* HDMI_AUDIO_PKT_CTRL1[0x0020] */
-	HDMI_OUTP(0x0020, audio_pkt_ctrl_reg);
-}
-
 static void hdmi_msm_en_gc_packet(boolean av_mute_is_requested)
 {
 	/* HDMI_GC[0x0040] */
@@ -3544,7 +3532,6 @@
 		}
 	}
 	hdmi_msm_audio_info_setup(FALSE, 0, 0, FALSE);
-	hdmi_msm_audio_ctrl_setup(FALSE, 0);
 	hdmi_msm_audio_acr_setup(FALSE, 0, 0, 0);
 	DEV_INFO("HDMI Audio: Disabled\n");
 	return 0;
@@ -4459,7 +4446,7 @@
 {
 	int rc;
 
-	if (cpu_is_msm8627())
+	if (cpu_is_msm8930())
 		return 0;
 
 	if (msm_fb_detect_client("hdmi_msm"))
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 72a11a2..a06eef8 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2001,6 +2001,9 @@
 
 static void mdp4_overlay_update_blt_mode(struct msm_fb_data_type *mfd)
 {
+	if (mfd->use_ov0_blt == mfd->ov0_blt_state)
+		return;
+
 	if (mfd->use_ov0_blt) {
 		if (mfd->panel_info.type == LCDC_PANEL)
 			mdp4_lcdc_overlay_blt_start(mfd);
@@ -2016,6 +2019,7 @@
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_stop(mfd);
 	}
+	mfd->ov0_blt_state = mfd->use_ov0_blt;
 }
 
 static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
@@ -2237,8 +2241,6 @@
 
 		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
 		mdp4_overlay_update_blt_mode(mfd);
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-
 	}
 	else {	/* mixer1, DTV, ATV */
 		if (ctrl->panel_mode & MDP4_PANEL_DTV)
@@ -2463,10 +2465,8 @@
 		}
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+	if (mfd->use_ov0_blt)
 		mdp4_overlay_update_blt_mode(mfd);
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
 
 	if (pipe->pipe_num >= OVERLAY_PIPE_VG1)
 		mdp4_overlay_vg_setup(pipe);	/* video/graphic pipe */
@@ -2501,15 +2501,20 @@
 		}
 #endif
 	} else {
+
 		/* primary interface */
 		ctrl->mixer0_played++;
 		if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
 			mdp4_overlay_reg_flush(pipe, 1);
+			if (!mfd->use_ov0_blt)
+				mdp4_overlay_update_blt_mode(mfd);
 			mdp4_overlay_lcdc_vsync_push(mfd, pipe);
 		}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
 			mdp4_overlay_reg_flush(pipe, 1);
+			if (!mfd->use_ov0_blt)
+				mdp4_overlay_update_blt_mode(mfd);
 			mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
 		}
 #endif
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 35af84d..0a80363 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -792,6 +792,11 @@
 	uint32 dsi_ctrl, intr_ctrl;
 	uint32 data;
 
+	if (mdp_rev > MDP_REV_41 || mdp_rev == MDP_REV_303)
+		pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
+	else
+		pinfo->rgb_swap = DSI_RGB_SWAP_BGR;
+
 	if (pinfo->mode == DSI_VIDEO_MODE) {
 		data = 0;
 		if (pinfo->pulse_mode_hsa_he)
@@ -811,11 +816,6 @@
 		data |= (pinfo->vc & 0x03);
 		MIPI_OUTP(MIPI_DSI_BASE + 0x000c, data);
 
-		if (mdp_rev > MDP_REV_41 || mdp_rev == MDP_REV_303)
-			pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
-		else
-			pinfo->rgb_swap = DSI_RGB_SWAP_BGR;
-
 		data = 0;
 		data |= ((pinfo->rgb_swap & 0x07) << 12);
 		if (pinfo->b_sel)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index cc0acc3..1144166 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -293,6 +293,7 @@
 	u32  prev_ip_frm_tag;
 	u32  cont_mode;
 	u32  reconfig_detected;
+	u32  dmx_disable;
 };
 union ddl_codec_data{
 	struct ddl_codec_data_hdr  hdr;
@@ -434,6 +435,7 @@
 void ddl_decoder_chroma_dpb_change(struct ddl_client_context *ddl);
 u32  ddl_check_reconfig(struct ddl_client_context *ddl);
 void ddl_handle_reconfig(u32 res_change, struct ddl_client_context *ddl);
+void ddl_fill_dec_desc_buffer(struct ddl_client_context *ddl);
 
 #ifdef DDL_BUF_LOG
 void ddl_list_buffers(struct ddl_client_context *ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 45b22ea..f10abc5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -697,6 +697,9 @@
 			DDL_KILO_BYTE(2));
 		if (!ptr)
 			status = VCD_ERR_ALLOC_FAIL;
+		else
+			memset(dec_bufs->desc.align_virtual_addr,
+				   0, buf_size.sz_desc);
 	}
 	if (status)
 		ddl_free_dec_hw_buffers(ddl);
@@ -973,3 +976,15 @@
 	}
 }
 
+void ddl_fill_dec_desc_buffer(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
+	struct vcd_frame_data *ip_bitstream = &(ddl->input_frame.vcd_frm);
+	struct ddl_buf_addr *dec_desc_buf = &(decoder->hw_bufs.desc);
+
+	if (ip_bitstream->desc_buf &&
+		ip_bitstream->desc_size < DDL_KILO_BYTE(128))
+		memcpy(dec_desc_buf->align_virtual_addr,
+			   ip_bitstream->desc_buf,
+			   ip_bitstream->desc_size);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 29f178d..5485335 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -13,6 +13,7 @@
 
 #include "vcd_ddl.h"
 #include "vcd_ddl_metadata.h"
+#include "vcd_res_tracker_api.h"
 
 static u32 ddl_set_dec_property(struct ddl_client_context *pddl,
 	struct vcd_property_hdr *property_hdr, void *property_value);
@@ -411,6 +412,24 @@
 		}
 	}
 	break;
+	case VCD_I_DISABLE_DMX:
+	{
+		int disable_dmx_allowed = 0;
+		DDL_MSG_LOW("Set property VCD_I_DISABLE_DMX\n");
+		if (res_trk_get_disable_dmx() &&
+			((decoder->codec.codec == VCD_CODEC_H264) ||
+			 (decoder->codec.codec == VCD_CODEC_VC1) ||
+			 (decoder->codec.codec == VCD_CODEC_VC1_RCV)))
+			disable_dmx_allowed = 1;
+
+		if (sizeof(u32) == property_hdr->sz &&
+			DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN) &&
+			disable_dmx_allowed) {
+				decoder->dmx_disable = *(u32 *)property_value;
+				vcd_status = VCD_S_SUCCESS;
+		}
+	}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1072,6 +1091,18 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 	break;
+	case VCD_I_DISABLE_DMX_SUPPORT:
+		if (sizeof(u32) == property_hdr->sz) {
+			*(u32 *)property_value = res_trk_get_disable_dmx();
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
+	case VCD_I_DISABLE_DMX:
+		if (sizeof(u32) == property_hdr->sz) {
+			*(u32 *)property_value = decoder->dmx_disable;
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 	break;
@@ -1477,6 +1508,7 @@
 	decoder->field_needed_for_prev_ip = 0;
 	decoder->cont_mode = 0;
 	decoder->reconfig_detected = false;
+	decoder->dmx_disable = false;
 	ddl_set_default_metadata_flag(ddl);
 	ddl_set_default_decoder_buffer_req(decoder, true);
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index df65d26..521e3b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -65,7 +65,7 @@
 		addr->alloc_handle = ion_alloc(
 		ddl_context->video_ion_client, alloc_size, SZ_4K,
 			(1<<res_trk_get_mem_type()));
-		if (!addr->alloc_handle) {
+		if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 			DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						 __func__);
 			goto bail_out;
@@ -145,7 +145,7 @@
 		return;
 	}
 	if (ddl_context->video_ion_client) {
-		if (addr->alloc_handle) {
+		if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
 			ion_free(ddl_context->video_ion_client,
 				addr->alloc_handle);
 		}
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 cf8f712..5ae8d09 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -846,6 +846,7 @@
 				ddl_context->dram_base_a, ddl->shared_mem
 				[ddl->command_channel]);
 	init_buf_param.dpb_count = decoder->dp_buf.no_of_dec_pic_buf;
+	init_buf_param.dmx_disable = decoder->dmx_disable;
 	ddl_context->vidc_decode_init_buffers[ddl->command_channel] (
 		&init_buf_param);
 	return VCD_S_SUCCESS;
@@ -892,6 +893,9 @@
 	dec_param.release_dpb_bit_mask = dpb_mask->hw_mask;
 	dec_param.decode = VIDC_1080P_DEC_TYPE_FRAME_DATA;
 	dec_param.dpb_count = decoder->dp_buf.no_of_dec_pic_buf;
+	dec_param.dmx_disable = decoder->dmx_disable;
+	if (decoder->dmx_disable)
+		ddl_fill_dec_desc_buffer(ddl);
 	if (decoder->flush_pending) {
 		dec_param.dpb_flush = true;
 		decoder->flush_pending = false;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index 5b4cdee..75014cc 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -550,7 +550,6 @@
 void vidc_1080p_decode_seq_start_ch0(
 	struct vidc_1080p_dec_seq_start_param *param)
 {
-
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_117192,
@@ -563,6 +562,7 @@
 	VIDC_HWIO_OUT(REG_190381,  param->stream_buffersize);
 	VIDC_HWIO_OUT(REG_85655,  param->descriptor_buffer_size);
 	VIDC_HWIO_OUT(REG_889944,  param->shared_mem_addr_offset);
+	VIDC_HWIO_OUT(REG_404623, 0);
 	VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_DEC_TYPE_SEQ_HEADER |
 		param->inst_id);
@@ -571,7 +571,6 @@
 void vidc_1080p_decode_seq_start_ch1(
 	struct vidc_1080p_dec_seq_start_param *param)
 {
-
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_980194,
@@ -584,6 +583,7 @@
 	VIDC_HWIO_OUT(REG_887095, param->stream_buffersize);
 	VIDC_HWIO_OUT(REG_576987, param->descriptor_buffer_size);
 	VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
+	VIDC_HWIO_OUT(REG_404623, 0);
 	VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_DEC_TYPE_SEQ_HEADER |
 		param->inst_id);
@@ -611,7 +611,10 @@
 		VIDC_HWIO_OUT(REG_190381,
 			param->stream_buffersize);
 	}
-	dpb_config = VIDC_SETFIELD(param->dpb_flush,
+	dpb_config = VIDC_SETFIELD(param->dmx_disable,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_SHFT,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_BMSK) |
+				VIDC_SETFIELD(param->dpb_flush,
 					VIDC_1080P_SI_RG10_DPB_FLUSH_SHFT,
 					VIDC_1080P_SI_RG10_DPB_FLUSH_BMSK) |
 				VIDC_SETFIELD(param->dpb_count,
@@ -652,7 +655,10 @@
 		VIDC_HWIO_OUT(REG_887095,
 			param->stream_buffersize);
 	}
-	dpb_config = VIDC_SETFIELD(param->dpb_flush,
+	dpb_config = VIDC_SETFIELD(param->dmx_disable,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_SHFT,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_BMSK) |
+				VIDC_SETFIELD(param->dpb_flush,
 					VIDC_1080P_SI_RG10_DPB_FLUSH_SHFT,
 					VIDC_1080P_SI_RG10_DPB_FLUSH_BMSK) |
 				VIDC_SETFIELD(param->dpb_count,
@@ -673,10 +679,17 @@
 void vidc_1080p_decode_init_buffers_ch0(
 	struct vidc_1080p_dec_init_buffers_param *param)
 {
+	u32 dpb_config;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
+	dpb_config = VIDC_SETFIELD(param->dmx_disable,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_SHFT,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_BMSK) |
+				VIDC_SETFIELD(param->dpb_count,
+					VIDC_1080P_SI_RG10_NUM_DPB_SHFT,
+					VIDC_1080P_SI_RG10_NUM_DPB_BMSK);
 	VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
-	VIDC_HWIO_OUT(REG_404623, param->dpb_count);
+	VIDC_HWIO_OUT(REG_404623, dpb_config);
 	VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_DEC_TYPE_INIT_BUFFERS |
 		param->inst_id);
@@ -685,10 +698,17 @@
 void vidc_1080p_decode_init_buffers_ch1(
 	struct vidc_1080p_dec_init_buffers_param *param)
 {
+	u32 dpb_config;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
+	dpb_config = VIDC_SETFIELD(param->dmx_disable,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_SHFT,
+					VIDC_1080P_SI_RG10_DMX_DISABLE_BMSK) |
+				VIDC_SETFIELD(param->dpb_count,
+					VIDC_1080P_SI_RG10_NUM_DPB_SHFT,
+					VIDC_1080P_SI_RG10_NUM_DPB_BMSK);
 	VIDC_HWIO_OUT(REG_652528,  param->shared_mem_addr_offset);
-	VIDC_HWIO_OUT(REG_220637, param->dpb_count);
+	VIDC_HWIO_OUT(REG_220637, dpb_config);
 	VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_DEC_TYPE_INIT_BUFFERS |
 		param->inst_id);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 415030a..55db33c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -340,6 +340,7 @@
 	u32 release_dpb_bit_mask;
 	u32 dpb_count;
 	u32 dpb_flush;
+	u32 dmx_disable;
 	enum vidc_1080p_decode decode;
 };
 struct vidc_1080p_dec_init_buffers_param{
@@ -347,6 +348,7 @@
 	u32 inst_id;
 	u32 shared_mem_addr_offset;
 	u32 dpb_count;
+	u32 dmx_disable;
 };
 struct vidc_1080p_seq_hdr_info{
 	u32 img_size_x;
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 03d4681..79f56bd 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
@@ -432,6 +432,8 @@
 					return;
 				}
 			}
+			resource_context.disable_dmx =
+			resource_context.vidc_platform_data->disable_dmx;
 #ifdef CONFIG_MSM_BUS_SCALING
 			resource_context.vidc_bus_client_pdata =
 			resource_context.vidc_platform_data->
@@ -439,6 +441,7 @@
 #endif
 		} else {
 			resource_context.memtype = -1;
+			resource_context.disable_dmx = 0;
 		}
 		resource_context.core_type = VCD_CORE_1080P;
 		if (!ddl_pmem_alloc(&resource_context.firmware_addr,
@@ -482,3 +485,7 @@
 {
 	return resource_context.res_ion_client;
 }
+
+u32 res_trk_get_disable_dmx(void){
+	return resource_context.disable_dmx;
+}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index 4766019..a90ccec 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -47,6 +47,7 @@
 	u32 core_type;
 	struct ddl_buf_addr firmware_addr;
 	struct ion_client *res_ion_client;
+	u32 disable_dmx;
 };
 
 #if DEBUG
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index 30a784c..04f28c6 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -32,4 +32,5 @@
 u32 res_trk_get_mem_type(void);
 u32 res_trk_get_enable_ion(void);
 struct ion_client *res_trk_get_ion_client(void);
+u32 res_trk_get_disable_dmx(void);
 #endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 65f9b54..4696d0b 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -184,6 +184,10 @@
 		return;
 	}
 
+	kfree(vcd_frame_data->desc_buf);
+	vcd_frame_data->desc_buf = NULL;
+	vcd_frame_data->desc_size = 0;
+
 	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
 	if (!vdec_msg) {
 		ERR("vid_dec_input_frame_done(): cannot allocate vid_dec_msg "
@@ -651,6 +655,57 @@
 		return true;
 }
 
+static u32 vid_dec_get_disable_dmx_support(struct video_client_ctx *client_ctx,
+					   u32 *disable_dmx)
+{
+
+	struct vcd_property_hdr vcd_property_hdr;
+	if (!client_ctx || !disable_dmx)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX_SUPPORT;
+	vcd_property_hdr.sz = sizeof(u32);
+	if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+						 disable_dmx))
+		return false;
+	else
+		return true;
+}
+static u32 vid_dec_get_disable_dmx(struct video_client_ctx *client_ctx,
+					   u32 *disable_dmx)
+{
+
+	struct vcd_property_hdr vcd_property_hdr;
+	if (!client_ctx || !disable_dmx)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
+	vcd_property_hdr.sz = sizeof(u32);
+	if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+						 disable_dmx))
+		return false;
+	else
+		return true;
+}
+
+static u32 vid_dec_set_disable_dmx(struct video_client_ctx *client_ctx)
+{
+
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_disable_dmx;
+	if (!client_ctx)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
+	vcd_property_hdr.sz = sizeof(u32);
+	vcd_disable_dmx = true;
+	DBG("%s() : Setting Disable DMX: %d\n",
+		__func__, vcd_disable_dmx);
+
+	if (vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+						 &vcd_disable_dmx))
+		return false;
+	else
+		return true;
+}
+
 static u32 vid_dec_set_picture_order(struct video_client_ctx *client_ctx,
 					u32 *picture_order)
 {
@@ -1104,7 +1159,8 @@
 }
 
 static u32 vid_dec_decode_frame(struct video_client_ctx *client_ctx,
-				struct vdec_input_frameinfo *input_frame_info)
+				struct vdec_input_frameinfo *input_frame_info,
+				u8 *desc_buf, u32 desc_size)
 {
 	struct vcd_frame_data vcd_input_buffer;
 	unsigned long kernel_vaddr, phy_addr, user_vaddr;
@@ -1137,6 +1193,8 @@
 		vcd_input_buffer.time_stamp = input_frame_info->timestamp;
 		/* Rely on VCD using the same flags as OMX */
 		vcd_input_buffer.flags = input_frame_info->flags;
+		vcd_input_buffer.desc_buf = desc_buf;
+		vcd_input_buffer.desc_size = desc_size;
 
 		vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
 					      &vcd_input_buffer);
@@ -1502,17 +1560,38 @@
 	case VDEC_IOCTL_DECODE_FRAME:
 	{
 		struct vdec_input_frameinfo input_frame_info;
+		u8 *desc_buf = NULL;
+		u32 desc_size = 0;
 		DBG("VDEC_IOCTL_DECODE_FRAME\n");
 		if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
 			return -EFAULT;
 		if (copy_from_user(&input_frame_info, vdec_msg.in,
 				   sizeof(input_frame_info)))
 			return -EFAULT;
+		if (client_ctx->dmx_disable) {
+			if (input_frame_info.desc_addr) {
+				desc_size = input_frame_info.desc_size;
+				desc_buf = kzalloc(desc_size, GFP_KERNEL);
+				if (desc_buf) {
+					if (copy_from_user(desc_buf,
+						input_frame_info.desc_addr,
+							desc_size)) {
+						kfree(desc_buf);
+						desc_buf = NULL;
+						return -EFAULT;
+					}
+				}
+			} else
+				return -EINVAL;
+		}
+		result = vid_dec_decode_frame(client_ctx, &input_frame_info,
+					desc_buf, desc_size);
 
-		result = vid_dec_decode_frame(client_ctx, &input_frame_info);
-
-		if (!result)
+		if (!result) {
+			kfree(desc_buf);
+			desc_buf = NULL;
 			return -EIO;
+		}
 		break;
 	}
 	case VDEC_IOCTL_FILL_OUTPUT_BUFFER:
@@ -1683,6 +1762,48 @@
 			return -EIO;
 		break;
 	}
+
+	case VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT:
+	{
+		u32 disable_dmx;
+		DBG("VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT\n");
+		if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		result = vid_dec_get_disable_dmx_support(client_ctx,
+					&disable_dmx);
+		if (result) {
+			if (copy_to_user(vdec_msg.out, &disable_dmx,
+					sizeof(u32)))
+				return -EFAULT;
+		} else
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_GET_DISABLE_DMX:
+	{
+		u32 disable_dmx;
+		DBG("VDEC_IOCTL_GET_DISABLE_DMX\n");
+		if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+			return -EFAULT;
+		result = vid_dec_get_disable_dmx(client_ctx,
+					&disable_dmx);
+		if (result) {
+			if (copy_to_user(vdec_msg.out, &disable_dmx,
+					sizeof(u32)))
+				return -EFAULT;
+		} else
+			return -EIO;
+		break;
+	}
+	case VDEC_IOCTL_SET_DISABLE_DMX:
+	{
+		DBG("VDEC_IOCTL_SET_DISABLE_DMX\n");
+		result =  vid_dec_set_disable_dmx(client_ctx);
+		if (!result)
+			return -EIO;
+		client_ctx->dmx_disable = 1;
+		break;
+	}
 	case VDEC_IOCTL_SET_PICTURE_ORDER:
 	{
 		u32 picture_order;
@@ -1875,6 +1996,7 @@
 	client_ctx->stop_msg = 0;
 	client_ctx->stop_called = false;
 	client_ctx->stop_sync_cb = false;
+	client_ctx->dmx_disable = 0;
 	if (vcd_get_ion_status()) {
 		client_ctx->user_ion_client = vcd_get_ion_client();
 		if (!client_ctx->user_ion_client) {
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.h b/drivers/video/msm/vidc/common/init/vidc_init.h
index 2bd8ecd..9dda277 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.h
+++ b/drivers/video/msm/vidc/common/init/vidc_init.h
@@ -56,6 +56,7 @@
 	struct ion_handle *seq_hdr_ion_handle;
 	struct ion_handle *h264_mv_ion_handle;
 	struct ion_handle *recon_buffer_ion_handle[4];
+	u32 dmx_disable;
 };
 
 void __iomem *vidc_get_ioaddr(void);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.h b/drivers/video/msm/vidc/common/vcd/vcd_api.h
index 4fcd085..badab1e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.h
@@ -67,6 +67,8 @@
 	enum vcd_frame frame;
 	u32 ip_frm_tag;
 	u32 intrlcd_ip_frm_tag;
+	u8 *desc_buf;
+	u32 desc_size;
 };
 
 struct vcd_sequence_hdr {
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_property.h b/drivers/video/msm/vidc/common/vcd/vcd_property.h
index 3f7b131..a3069e3 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_property.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_property.h
@@ -48,6 +48,8 @@
 #define VCD_I_DEC_PICTYPE (VCD_START_BASE + 0x20)
 #define VCD_I_CONT_ON_RECONFIG (VCD_START_BASE + 0x21)
 #define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
+#define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
+#define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index c5567cb..f11e43e 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -187,7 +187,7 @@
  */
 static struct inode *anon_inode_mkinode(void)
 {
-	struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
+	struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb);
 
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
@@ -233,7 +233,7 @@
 	return 0;
 
 err_mntput:
-	mntput(anon_inode_mnt);
+	kern_unmount(anon_inode_mnt);
 err_unregister_filesystem:
 	unregister_filesystem(&anon_inode_fs_type);
 err_exit:
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 7aafeb8..0b686ce 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1030,6 +1030,7 @@
 static void __exit exit_hugetlbfs_fs(void)
 {
 	kmem_cache_destroy(hugetlbfs_inode_cachep);
+	kern_unmount(hugetlbfs_vfsmount);
 	unregister_filesystem(&hugetlbfs_fs_type);
 	bdi_destroy(&hugetlbfs_backing_dev_info);
 }
diff --git a/fs/inode.c b/fs/inode.c
index 43566d1..e964818 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -369,9 +369,11 @@
 
 static inline void inode_sb_list_del(struct inode *inode)
 {
-	spin_lock(&inode_sb_list_lock);
-	list_del_init(&inode->i_sb_list);
-	spin_unlock(&inode_sb_list_lock);
+	if (!list_empty(&inode->i_sb_list)) {
+		spin_lock(&inode_sb_list_lock);
+		list_del_init(&inode->i_sb_list);
+		spin_unlock(&inode_sb_list_lock);
+	}
 }
 
 static unsigned long hash(struct super_block *sb, unsigned long hashval)
@@ -843,6 +845,29 @@
 EXPORT_SYMBOL(get_next_ino);
 
 /**
+ *	new_inode_pseudo 	- obtain an inode
+ *	@sb: superblock
+ *
+ *	Allocates a new inode for given superblock.
+ *	Inode wont be chained in superblock s_inodes list
+ *	This means :
+ *	- fs can't be unmount
+ *	- quotas, fsnotify, writeback can't work
+ */
+struct inode *new_inode_pseudo(struct super_block *sb)
+{
+	struct inode *inode = alloc_inode(sb);
+
+	if (inode) {
+		spin_lock(&inode->i_lock);
+		inode->i_state = 0;
+		spin_unlock(&inode->i_lock);
+		INIT_LIST_HEAD(&inode->i_sb_list);
+	}
+	return inode;
+}
+
+/**
  *	new_inode 	- obtain an inode
  *	@sb: superblock
  *
@@ -860,13 +885,9 @@
 
 	spin_lock_prefetch(&inode_sb_list_lock);
 
-	inode = alloc_inode(sb);
-	if (inode) {
-		spin_lock(&inode->i_lock);
-		inode->i_state = 0;
-		spin_unlock(&inode->i_lock);
+	inode = new_inode_pseudo(sb);
+	if (inode)
 		inode_sb_list_add(inode);
-	}
 	return inode;
 }
 EXPORT_SYMBOL(new_inode);
diff --git a/fs/namespace.c b/fs/namespace.c
index fe59bd1..7b4fa8f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2721,6 +2721,25 @@
 
 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 {
-	return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+	struct vfsmount *mnt;
+	mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+	if (!IS_ERR(mnt)) {
+		/*
+		 * it is a longterm mount, don't release mnt until
+		 * we unmount before file sys is unregistered
+		*/
+		mnt_make_longterm(mnt);
+	}
+	return mnt;
 }
 EXPORT_SYMBOL_GPL(kern_mount_data);
+
+void kern_unmount(struct vfsmount *mnt)
+{
+	/* release long term mount so mount point can be released */
+	if (!IS_ERR_OR_NULL(mnt)) {
+		mnt_make_shortterm(mnt);
+		mntput(mnt);
+	}
+}
+EXPORT_SYMBOL(kern_unmount);
diff --git a/fs/pipe.c b/fs/pipe.c
index da42f7d..0e0be1d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -948,7 +948,7 @@
 
 static struct inode * get_pipe_inode(void)
 {
-	struct inode *inode = new_inode(pipe_mnt->mnt_sb);
+	struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
 	struct pipe_inode_info *pipe;
 
 	if (!inode)
@@ -1291,8 +1291,8 @@
 
 static void __exit exit_pipe_fs(void)
 {
+	kern_unmount(pipe_mnt);
 	unregister_filesystem(&pipe_fs_type);
-	mntput(pipe_mnt);
 }
 
 fs_initcall(init_pipe_fs);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b5b9792..d10b5b5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1869,6 +1869,7 @@
 extern int unregister_filesystem(struct file_system_type *);
 extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data);
 #define kern_mount(type) kern_mount_data(type, NULL)
+extern void kern_unmount(struct vfsmount *mnt);
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
@@ -2276,7 +2277,8 @@
 extern void iget_failed(struct inode *);
 extern void end_writeback(struct inode *);
 extern void __destroy_inode(struct inode *);
-extern struct inode *new_inode(struct super_block *);
+extern struct inode *new_inode_pseudo(struct super_block *sb);
+extern struct inode *new_inode(struct super_block *sb);
 extern void free_inode_nonrcu(struct inode *inode);
 extern int should_remove_suid(struct dentry *);
 extern int file_remove_suid(struct file *);
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
index 6f6cb39..23d0fb0 100644
--- a/include/linux/mfd/pm8xxx/ccadc.h
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -73,7 +73,7 @@
 
 /**
  * pm8xxx_ccadc_get_battery_current - return the battery current based on vsense
- *				resitor in milliamperes
+ *				resitor in microamperes
  * @result:	The pointer where the voltage will be updated. A -ve
  *		result means that the current is flowing in
  *		the battery - during battery charging
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 5d186df..82db9a4 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -109,6 +109,7 @@
 	unsigned int			i_test;
 	unsigned int			v_failure;
 	unsigned int			calib_delay_ms;
+	unsigned int			max_voltage_uv;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
@@ -129,7 +130,7 @@
 
 /**
  * pm8921_bms_get_battery_current - return the battery current based on vsense
- *				resitor in milliamperes
+ *				resitor in microamperes
  * @result:	The pointer where the voltage will be updated. A -ve
  *		result means that the current is flowing in
  *		the battery - during battery charging
diff --git a/include/linux/mfd/pm8xxx/pm8xxx-adc.h b/include/linux/mfd/pm8xxx/pm8xxx-adc.h
index ba4b29c..a572ae3 100644
--- a/include/linux/mfd/pm8xxx/pm8xxx-adc.h
+++ b/include/linux/mfd/pm8xxx/pm8xxx-adc.h
@@ -97,7 +97,7 @@
 
 #define PM8XXX_ADC_PMIC_0	0x0
 
-#define PM8XXX_CHANNEL_ADC_625_MV	625
+#define PM8XXX_CHANNEL_ADC_625_UV	625000
 #define PM8XXX_CHANNEL_MPP_SCALE1_IDX	20
 #define PM8XXX_CHANNEL_MPP_SCALE3_IDX	40
 
@@ -218,7 +218,6 @@
 
 /**
  * struct pm8xxx_adc_linear_graph - Represent ADC characteristics
- * @offset: Offset with respect to the actual curve
  * @dy: Numerator slope to calculate the gain
  * @dx: Denominator slope to calculate the gain
  * @adc_vref: A/D word of the voltage reference used for the channel
@@ -228,11 +227,10 @@
  * to calibrate the device.
  */
 struct pm8xxx_adc_linear_graph {
-	int32_t offset;
-	int32_t dy;
-	int32_t dx;
-	int32_t adc_vref;
-	int32_t adc_gnd;
+	int64_t dy;
+	int64_t dx;
+	int64_t adc_vref;
+	int64_t adc_gnd;
 };
 
 /**
@@ -292,6 +290,10 @@
  *		 here is a number relative to a reference of a given ADC
  * @physical: The data meaningful for each individual channel whether it is
  *	      voltage, current, temperature, etc.
+ *	      All voltage units are represented in micro - volts.
+ *	      -Battery temperature units are represented as 0.1 DegC
+ *	      -PA Therm temperature units are represented as DegC
+ *	      -PMIC Die temperature units are represented as 0.001 DegC
  */
 struct pm8xxx_adc_chan_result {
 	uint32_t	chan;
@@ -379,6 +381,21 @@
 			const struct pm8xxx_adc_properties *adc_prop,
 			const struct pm8xxx_adc_chan_properties *chan_prop,
 			struct pm8xxx_adc_chan_result *chan_rslt);
+/**
+ * pm8xxx_adc_scale_batt_id() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
+			const struct pm8xxx_adc_properties *adc_prop,
+			const struct pm8xxx_adc_chan_properties *chan_prop,
+			struct pm8xxx_adc_chan_result *chan_rslt);
 #else
 static inline int32_t pm8xxx_adc_scale_default(int32_t adc_code,
 			const struct pm8xxx_adc_properties *adc_prop,
@@ -405,6 +422,11 @@
 			const struct pm8xxx_adc_chan_properties *chan_prop,
 			struct pm8xxx_adc_chan_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t pm8xxx_adc_scale_batt_id(int32_t adc_code,
+			const struct pm8xxx_adc_properties *adc_prop,
+			const struct pm8xxx_adc_chan_properties *chan_prop,
+			struct pm8xxx_adc_chan_result *chan_rslt)
+{ return -ENXIO; }
 #endif
 
 /**
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
index cf753b5d..0699c46 100644
--- a/include/linux/mfd/pmic8058.h
+++ b/include/linux/mfd/pmic8058.h
@@ -144,54 +144,9 @@
 	struct pmic8058_charger_data		*charger_pdata;
 };
 
-#ifdef CONFIG_PMIC8058
-int pm8058_reset_pwr_off(int reset);
-#else
-static inline int pm8058_reset_pwr_off(int reset) { return 0; }
-#endif
-
-
 int pm8058_hard_reset_config(enum pon_config config);
 
 /**
- * pm8058_smpl_control - enables/disables SMPL detection
- * @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
- *
- * This function enables or disables the Sudden Momentary Power Loss detection
- * module.  If SMPL detection is enabled, then when a sufficiently long power
- * loss event occurs, the PMIC will automatically reset itself.  If SMPL
- * detection is disabled, then the PMIC will shutdown when power loss occurs.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_smpl_control(int enable);
-
-/**
- * pm8058_smpl_set_delay - sets the SMPL detection time delay
- * @delay: enum value corresponding to delay time
- *
- * This function sets the time delay of the SMPL detection module.  If power
- * is reapplied within this interval, then the PMIC reset automatically.  The
- * SMPL detection module must be enabled for this delay time to take effect.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_smpl_set_delay(enum pm8058_smpl_delay delay);
-
-/**
- * pm8058_watchdog_reset_control - enables/disables watchdog reset detection
- * @enable: 0 = shutdown when PS_HOLD goes low, 1 = reset when PS_HOLD goes low
- *
- * This function enables or disables the PMIC watchdog reset detection feature.
- * If watchdog reset detection is enabled, then the PMIC will reset itself
- * when PS_HOLD goes low.  If it is not enabled, then the PMIC will shutdown
- * when PS_HOLD goes low.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_watchdog_reset_control(int enable);
-
-/**
  * pm8058_stay_on - enables stay_on feature
  *
  * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
diff --git a/include/linux/mfd/pmic8901.h b/include/linux/mfd/pmic8901.h
index 932f8da..f5b34be 100644
--- a/include/linux/mfd/pmic8901.h
+++ b/include/linux/mfd/pmic8901.h
@@ -23,6 +23,7 @@
 #include <linux/mfd/pm8xxx/mpp.h>
 #include <linux/mfd/pm8xxx/tm.h>
 #include <linux/regulator/pmic8901-regulator.h>
+#include <linux/mfd/pm8xxx/misc.h>
 
 #define PM8901_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
 
@@ -37,19 +38,12 @@
 #define PM8901_TEMPSTAT_IRQ		PM8901_IRQ_BLOCK_BIT(6, 4)
 #define PM8901_OVERTEMP_IRQ		PM8901_IRQ_BLOCK_BIT(6, 5)
 
-struct pm8901_chip;
-
 struct pm8901_platform_data {
-	struct pm8xxx_irq_platform_data *irq_pdata;
-	struct pm8xxx_mpp_platform_data *mpp_pdata;
-	struct pm8901_vreg_pdata	*regulator_pdatas;
-	int				num_regulators;
+	struct pm8xxx_irq_platform_data		*irq_pdata;
+	struct pm8xxx_mpp_platform_data		*mpp_pdata;
+	struct pm8xxx_misc_platform_data	*misc_pdata;
+	struct pm8901_vreg_pdata		*regulator_pdatas;
+	int					num_regulators;
 };
 
-#ifdef CONFIG_PMIC8901
-int pm8901_reset_pwr_off(int reset);
-#else
-static inline int pm8901_reset_pwr_off(int reset) { return 0; }
-#endif
-
 #endif /* __PMIC8901_H__ */
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 768fb3b..9c742b5 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -198,6 +198,15 @@
 #define VDEC_IOCTL_SET_CONT_ON_RECONFIG  \
 	_IO(VDEC_IOCTL_MAGIC, 34)
 
+#define VDEC_IOCTL_SET_DISABLE_DMX \
+	_IOW(VDEC_IOCTL_MAGIC, 35, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX \
+	_IOR(VDEC_IOCTL_MAGIC, 36, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT \
+	_IOR(VDEC_IOCTL_MAGIC, 37, struct vdec_ioctl_msg)
+
 enum vdec_picture {
 	PICTURE_TYPE_I,
 	PICTURE_TYPE_P,
@@ -494,6 +503,8 @@
 	void *client_data;
 	int pmem_fd;
 	size_t pmem_offset;
+	void __user *desc_addr;
+	uint32_t desc_size;
 };
 
 struct vdec_framesize {
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index c83035d..47e8427 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -57,6 +57,7 @@
  *	Note that for writes (IN transfers) some data bytes may still
  *	reside in a device-side FIFO when the request is reported as
  *	complete.
+ *@udc_priv: Vendor private data in usage by the UDC.
  *
  * These are allocated/freed through the endpoint they're used with.  The
  * hardware's driver can add extra per-request data to the memory it returns,
@@ -92,6 +93,7 @@
 
 	int			status;
 	unsigned		actual;
+	unsigned		udc_priv;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -111,7 +113,6 @@
 	struct usb_request *(*alloc_request) (struct usb_ep *ep,
 		gfp_t gfp_flags);
 	void (*free_request) (struct usb_ep *ep, struct usb_request *req);
-
 	int (*queue) (struct usb_ep *ep, struct usb_request *req,
 		gfp_t gfp_flags);
 	int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 13d9b71..45aa228 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2708,6 +2708,11 @@
 			ie->data.ssp_mode = (ev->features[0] & 0x01);
 
 		conn->ssp_mode = (ev->features[0] & 0x01);
+		/*In case if remote device ssp supported/2.0 device
+		reduce the security level to MEDIUM if it is HIGH*/
+		if (!conn->ssp_mode &&
+			(conn->pending_sec_level == BT_SECURITY_HIGH))
+			conn->pending_sec_level = BT_SECURITY_MEDIUM;
 	}
 
 	if (conn->state != BT_CONFIG)
diff --git a/net/socket.c b/net/socket.c
index 1ad42d3..129d9ae 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -467,7 +467,7 @@
 	struct inode *inode;
 	struct socket *sock;
 
-	inode = new_inode(sock_mnt->mnt_sb);
+	inode = new_inode_pseudo(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 3545934..de7900e 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1984,6 +1984,7 @@
 void exit_sel_fs(void)
 {
 	kobject_put(selinuxfs_kobj);
+	kern_unmount(selinuxfs_mount);
 	unregister_filesystem(&sel_fs_type);
 }
 #endif
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 3b257a6..c583ce2 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -61,7 +61,7 @@
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
-snd-soc-msm8960-objs := msm8960.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o
 obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
 
 # Generic MSM drivers
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
new file mode 100644
index 0000000..870bd20
--- /dev/null
+++ b/sound/soc/msm/apq8064.c
@@ -0,0 +1,1161 @@
+/* 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9310.h"
+
+/* 8064 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8064_SPK_ON 1
+#define MSM8064_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS		2
+#define MSM_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN 44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK 46
+
+static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
+static int msm_spk_control;
+static int msm_ext_bottom_spk_pamp;
+static int msm_ext_top_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+struct tabla_mbhc_calibration tabla_calib = {
+	.bias = TABLA_MICBIAS2,
+	.tldoh = 100,
+	.bg_fast_settle = 100,
+	.mic_current = TABLA_PID_MIC_5_UA,
+	.mic_pid = 100,
+	.hph_current = TABLA_PID_MIC_5_UA,
+	.setup_plug_removal_delay = 1000000,
+	.shutdown_plug_removal = 100000,
+};
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int msm_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.
+			function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+				__func__, bottom_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Bottom Spk Ampl"
+				" gpio %u\n", __func__, bottom_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+		}
+
+	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				top_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Top Spk Ampl"
+				" gpio %u\n", __func__, top_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+			gpio_direction_output(top_spk_pamp_gpio, 1);
+		}
+	} else {
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
+			" gpio = %u\n", __func__, spk_amp_gpio);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already "
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_bottom_spk_pamp |= spk;
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external "
+				" Bottom Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Top Speaker Ampl already"
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_top_spk_pamp |= spk;
+
+		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+			pr_debug("%s: sleeping 4 ms after turning on "
+				" external Top Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if (!msm_ext_bottom_spk_pamp)
+			return;
+
+		gpio_direction_output(bottom_spk_pamp_gpio, 0);
+		gpio_free(bottom_spk_pamp_gpio);
+		msm_ext_bottom_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom"
+			" Speaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if (!msm_ext_top_spk_pamp)
+			return;
+
+		gpio_direction_output(top_spk_pamp_gpio, 0);
+		gpio_free(top_spk_pamp_gpio);
+		msm_ext_top_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Top"
+			" Spkaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	if (msm_spk_control == MSM8064_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users != 1)
+			return 0;
+
+		codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+		if (codec_clk) {
+			clk_set_rate(codec_clk, 12288000);
+			clk_enable(codec_clk);
+			tabla_mclk_enable(w->codec, 1);
+
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users == 0)
+			return 0;
+
+		clk_users--;
+
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					__func__, clk_users);
+
+			clk_disable(codec_clk);
+			clk_put(codec_clk);
+			tabla_mclk_enable(w->codec, 0);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	/* Speaker path */
+	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 Internal1"},
+	{"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+
+	/**
+	 * AMIC3 and AMIC4 inputs are connected to ANC microphones
+	 * These mics are biased differently on CDP and FLUID
+	 * routing entries below are based on bias arrangement
+	 * on FLUID.
+	 */
+	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
+	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
+	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/**
+	 * The digital Mic routes are setup considering
+	 * fluid as default device.
+	 */
+
+	/**
+	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back top Digital Mic on Fluid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5. Front top Digital Mic on Fluid.
+	 * Digital Mic GM3 on CDP mainboard.
+	 * Conncted to DMIC5 Input on Tabla codec.
+	 */
+	{"DMIC5", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+	/* Tabla digital Mic6 - back bottom digital Mic on Liquid and
+	 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic6"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__,
+					msm_btsco_rate);
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__,
+					msm_btsco_rate);
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
+		msm_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
+		msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
+		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+static int msm_btsco_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+			int_btsco_rate_mixer_controls,
+		ARRAY_SIZE(int_btsco_rate_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s()\n", __func__);
+
+	/*if (machine_is_msm_liquid()) {
+		top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
+		bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
+	}*/
+
+	rtd->pmdown_time = 0;
+
+	err = snd_soc_add_controls(codec, tabla_msm_controls,
+				ARRAY_SIZE(tabla_msm_controls));
+	if (err < 0)
+		return err;
+
+	snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
+				ARRAY_SIZE(msm_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+		(SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
+		&hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	err = snd_soc_jack_new(codec, "Button Jack",
+				SND_JACK_BTN_0, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_calib);
+
+	return 0;
+}
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link fe_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link slimbus0_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link int_fm_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm_btsco_rate;
+	channels->min = channels->max = msm_btsco_ch;
+
+	return 0;
+}
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int msm_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm_aux_pcm_free_gpios();
+}
+
+static void msm_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+}
+
+static struct snd_soc_ops msm_be_ops = {
+	.startup = msm_startup,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+	.startup = msm_auxpcm_startup,
+	.shutdown = msm_auxpcm_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8960 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8960 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8960 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &slimbus0_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &int_fm_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.init = &msm_btsco_init,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+	},
+};
+
+struct snd_soc_card snd_soc_card_msm = {
+	.name		= "msm-snd-card",
+	.dai_link	= msm_dai,
+	.num_links	= ARRAY_SIZE(msm_dai),
+};
+
+static struct platform_device *msm_snd_device;
+
+static int msm_configure_headset_mic_gpios(void)
+{
+	int ret;
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull	   = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+
+	ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(23));
+	else
+		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
+
+	ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(35));
+		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(35));
+	else
+		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
+
+	return 0;
+}
+static void msm_free_headset_mic_gpios(void)
+{
+	if (msm_headset_gpios_configured) {
+		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
+		gpio_free(PM8921_GPIO_PM_TO_SYS(35));
+	}
+}
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	if (!cpu_is_apq8064()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV;
+	}
+
+	msm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_snd_device);
+	if (ret) {
+		platform_device_put(msm_snd_device);
+		return ret;
+	}
+
+	if (msm_configure_headset_mic_gpios()) {
+		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+		msm_headset_gpios_configured = 0;
+	} else
+		msm_headset_gpios_configured = 1;
+
+	return ret;
+
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+	if (!cpu_is_apq8064()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	msm_free_headset_mic_gpios();
+	platform_device_unregister(msm_snd_device);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index bfc004e..d3f02a9 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -24,6 +24,7 @@
 #include <sound/pcm.h>
 #include <sound/jack.h>
 #include <asm/mach-types.h>
+#include <mach/socinfo.h>
 #include "msm-pcm-routing.h"
 #include "../codecs/wcd9310.h"
 
@@ -1125,6 +1126,10 @@
 {
 	int ret;
 
+	if (!cpu_is_msm8960()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV ;
+	}
 	msm8960_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm8960_snd_device) {
 		pr_err("Platform device allocation failed\n");
@@ -1151,6 +1156,10 @@
 
 static void __exit msm8960_audio_exit(void)
 {
+	if (!cpu_is_msm8960()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
 	msm8960_free_headset_mic_gpios();
 	platform_device_unregister(msm8960_snd_device);
 }