Merge "spi_qsd: Ensure the DMA callback is called before completion." into msm-3.0
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 002431a..308f992 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,17 +7,15 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-lpass"
-- reg:		      Three pairs of physical base addresses and region sizes
+- reg:		      Two pairs of physical base addresses and region sizes
 		      of memory mapped registers. The first region corresponds
-		      to QDSP6SS_PUB, the second corresponds to LPASS_CC, and
-		      the third to LPASS_HALTREQ.
+		      to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
 	qcom,lpass@fe200000 {
 	        compatible = "qcom,pil-q6v5-lpass";
 	        reg = <0xfe200000 0x00100>,
-	              <0xfe000000 0x40000>,
 	              <0xfd485100 0x00010>;
 
 	        qcom,firmware-name = "lpass";
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index 8c00535..d6e23ad 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -30,11 +30,19 @@
 		status = "disable";
 	};
 
-	qcom,sdcc@f980b000 {
+	qcom,sdcc@f9824000 {
 		status = "disable";
 	};
 
-	qcom,sdcc@f984b000 {
+	qcom,sdcc@f9864000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f98a4000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f98e4000 {
 		status = "disable";
 	};
 
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
index ab6b8ba..ae3f2dd 100644
--- a/arch/arm/boot/dts/msmcopper-sim.dts
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -17,4 +17,22 @@
 / {
 	model = "Qualcomm MSM Copper Simulator";
 	compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+
+	qcom,sdcc@f9824000 {
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98a4000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9864000 {
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98e4000 {
+		status = "disable";
+	};
 };
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 89a726e..66f5fa1 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -75,30 +75,50 @@
 		qcom,hsusb-otg-otg-control = <1>;
 	};
 
-	qcom,sdcc@f980b000 {
+	qcom,sdcc@f9824000 {
 		cell-index = <1>;
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf980b000 0x1000>;
+		reg = <0xf9824000 0x1000>;
 		interrupts = <0 123 0>;
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 96000000 192000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
 		qcom,sdcc-bus-width = <8>;
 		qcom,sdcc-hs200;
 		qcom,sdcc-nonremovable;
-		qcom,sdcc-disable_cmd23;
 	};
 
-	qcom,sdcc@f984b000 {
+	qcom,sdcc@f98a4000 {
+		cell-index = <2>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x1000>;
+		interrupts = <0 125 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <4>;
+	};
+
+	qcom,sdcc@f9864000 {
 		cell-index = <3>;
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf984b000 0x1000>;
+		reg = <0xf9864000 0x1000>;
 		interrupts = <0 127 0>;
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
 		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98e4000 {
+		cell-index = <4>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98e4000 0x1000>;
+		interrupts = <0 129 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
+		qcom,sdcc-bus-width = <4>;
 	};
 
 	qcom,sps@f9980000 {
@@ -256,7 +276,6 @@
 	qcom,lpass@fe200000 {
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
-		      <0xfe000000 0x40000>,
 		      <0xfd485100 0x00010>;
 
 		qcom,firmware-name = "lpass";
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 875b479..99747ba 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -212,10 +212,13 @@
 {
 	unsigned int i;
 	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_lock(&irq_controller_lock);
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 #endif
 		gic->enabled_irqs[i]
 			= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
@@ -225,7 +228,7 @@
 		writel_relaxed(gic->wakeup_irqs[i],
 			base + GIC_DIST_ENABLE_SET + i * 4);
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_unlock(&irq_controller_lock);
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 #endif
 	}
 	mb();
@@ -248,17 +251,28 @@
 	u32 enabled;
 	unsigned long pending[32];
 	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 
 	if (!msm_show_resume_irq_mask)
 		return;
 
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#else
 	raw_spin_lock(&irq_controller_lock);
+#endif
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 		enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
 		pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
 		pending[i] &= enabled;
 	}
-	raw_spin_unlock(&irq_controller_lock);
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#else
+	raw_spin_lock(&irq_controller_lock);
+#endif
 
 	for (i = find_first_bit(pending, gic->max_irq);
 	     i < gic->max_irq;
@@ -272,11 +286,13 @@
 {
 	unsigned int i;
 	void __iomem *base = gic_data_dist_base(gic);
-
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 	gic_show_resume_irq(gic);
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_lock(&irq_controller_lock);
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 #endif
 		/* disable all of them */
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
@@ -284,7 +300,7 @@
 		writel_relaxed(gic->enabled_irqs[i],
 			base + GIC_DIST_ENABLE_SET + i * 4);
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_unlock(&irq_controller_lock);
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 #endif
 	}
 	mb();
@@ -1128,8 +1144,9 @@
 	unsigned long value = 0;
 	struct gic_chip_data *gic = &gic_data[0];
 	void __iomem *base = gic_data_dist_base(gic);
+	unsigned long flags;
 
-	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 	/*
 	 * PPI and SGI to be included.
 	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
@@ -1146,13 +1163,14 @@
 			for (bit = 0; bit < 32; bit++) {
 				bit = find_next_bit(&value, 32, bit);
 				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
-					raw_spin_unlock(&irq_controller_lock);
+					raw_spin_unlock_irqrestore(
+						&irq_controller_lock, flags);
 					return 1;
 				}
 			}
 		}
 	}
-	raw_spin_unlock(&irq_controller_lock);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
 	return 0;
 }
@@ -1165,14 +1183,13 @@
 
 	gic_cpu_save(0);
 	gic_dist_save(0);
-	 /* Disable all the Interrupts, if we enter from idle pc */
-	if (from_idle) {
-		for (i = 0; (i * 32) < gic->max_irq; i++) {
-			raw_spin_lock(&irq_controller_lock);
-			writel_relaxed(0xffffffff, base
-					+ GIC_DIST_ENABLE_CLEAR + i * 4);
-			raw_spin_unlock(&irq_controller_lock);
-		}
+
+	/* Disable all the Interrupts, before we enter pc */
+	for (i = 0; (i * 32) < gic->max_irq; i++) {
+		raw_spin_lock(&irq_controller_lock);
+		writel_relaxed(0xffffffff, base
+				+ GIC_DIST_ENABLE_CLEAR + i * 4);
+		raw_spin_unlock(&irq_controller_lock);
 	}
 }
 
@@ -1193,8 +1210,9 @@
 	struct gic_chip_data *gic = &gic_data[0];
 	void __iomem *base = gic_data_dist_base(gic);
 	unsigned int value = 0;
+	unsigned long flags;
 
-	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
 	value |= BIT(8);
@@ -1220,6 +1238,6 @@
 	value |= BIT(8);
 	__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
 	mb();
-	raw_spin_unlock(&irq_controller_lock);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index eb2c2c8..c644cf9 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -126,6 +126,12 @@
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_FB=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index f195d68..9a2fa39 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -241,7 +241,7 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_OV5647=y
 CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
 CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index bc350a7..869fb6d 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -242,7 +242,7 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_OV5647=y
 CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
 CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index fb5cff7..11b1f73 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -321,6 +321,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5c01299..886a691 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -330,6 +330,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
@@ -342,12 +343,12 @@
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_GEMINI=y
-CONFIG_S5K3L1YX=y
-CONFIG_IMX091=y
 CONFIG_MSM_EEPROM=y
 CONFIG_IMX074_EEPROM=y
 CONFIG_IMX091_EEPROM=y
+CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 83e6666..c9d0000 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -8,7 +8,6 @@
 	select MSM_VIC
 	select CPU_V6
 	select MSM_REMOTE_SPINLOCK_SWP
-	select MSM_PM if PM
 
 config ARCH_MSM7X25
 	bool "MSM7x25"
@@ -17,7 +16,6 @@
 	select CPU_V6
 	select MSM_REMOTE_SPINLOCK_SWP
 	select MULTI_IRQ_HANDLER
-	select MSM_PM if PM
 
 config ARCH_MSM7X27
 	bool "MSM7x27"
@@ -2037,10 +2035,6 @@
 config MSM_NATIVE_RESTART
 	bool
 
-config MSM_PM
-	depends on PM
-	bool
-
 config MSM_PM2
 	depends on PM
 	bool
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d633aa7..2295679 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -152,8 +152,8 @@
 obj-$(CONFIG_MSM_HW3D) += hw3d.o
 obj-$(CONFIG_PM) += pm-boot.o
 obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
 obj-$(CONFIG_MSM_PM2) += pm2.o
-obj-$(CONFIG_MSM_PM) += pm.o
 obj-$(CONFIG_MSM_NOPM) += no-pm.o
 
 obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
@@ -318,7 +318,7 @@
 ifdef CONFIG_VCM
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
-obj-$(CONFIG_MSM_OCMEM) += ocmem.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 041e755..a65c5b0 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -653,23 +653,23 @@
 
 /* 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, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   925000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   937500 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   962500 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   987500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1037500 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1062500 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1125000 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1137500 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1162500 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1187500 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1200000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1225000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 91fd400..1a0a287 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -127,6 +127,7 @@
 	/* TABLA CODEC RESET */
 	PM8921_GPIO_OUTPUT(34, 1, MED),
 	PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
+	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
 };
 
 static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
@@ -146,6 +147,8 @@
 	PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
 	/*MPP9 is used to detect docking station connection/removal on Liquid*/
 	PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
+	/* PCIE_RESET_N */
+	PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
 };
 
 void __init apq8064_pm8xxx_gpio_mpp_init(void)
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 58e83a0..3d2dbaa 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -157,6 +157,8 @@
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.1"),
 	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
 	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("vp_pcie",             "msm_pcie"),
+	REGULATOR_SUPPLY("vptx_pcie",           "msm_pcie"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8921_s4",		NULL),
@@ -213,6 +215,7 @@
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
+	REGULATOR_SUPPLY("vdd_pcie_vph",        "msm_pcie"),
 };
 VREG_CONSUMERS(LVS7) = {
 	REGULATOR_SUPPLY("8921_lvs7",		NULL),
@@ -256,6 +259,7 @@
 	REGULATOR_SUPPLY("lvds_vccs_3p3v",      "lvds.0"),
 	REGULATOR_SUPPLY("dsi1_vccs_3p3v",      "mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_mux_vdd",        "hdmi_msm.0"),
+	REGULATOR_SUPPLY("pcie_ext_3p3v",       "msm_pcie"),
 };
 VREG_CONSUMERS(EXT_TS_SW) = {
 	REGULATOR_SUPPLY("ext_ts_sw",		NULL),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ed17cc4..c123138 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -69,6 +69,7 @@
 #include <sound/cs8427.h>
 #include <media/gpio-ir-recv.h>
 #include <linux/fmem.h>
+#include <mach/msm_pcie.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -114,6 +115,10 @@
 #define MSM_MM_FW_SIZE		0x200000
 #define APQ8064_FW_START	(APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
 
+/* PCIe power enable pmic gpio */
+#define PCIE_PWR_EN_PMIC_GPIO 13
+#define PCIE_RST_N_PMIC_MPP 1
+
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
 static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -1998,6 +2003,22 @@
 	msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
 }
 
+/* PCIe gpios */
+static struct msm_pcie_gpio_info_t msm_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = {
+	{"rst_n", PM8921_MPP_PM_TO_SYS(PCIE_RST_N_PMIC_MPP), 0},
+	{"pwr_en", PM8921_GPIO_PM_TO_SYS(PCIE_PWR_EN_PMIC_GPIO), 1},
+};
+
+static struct msm_pcie_platform msm_pcie_platform_data = {
+	.gpio = msm_pcie_gpio_info,
+};
+
+static void __init mpq8064_pcie_init(void)
+{
+	msm_device_pcie.dev.platform_data = &msm_pcie_platform_data;
+	platform_device_register(&msm_device_pcie);
+}
+
 static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= PM8921_MPP_PM_TO_SYS(7),
@@ -2877,6 +2898,7 @@
 		machine_is_mpq8064_dtv()) {
 		enable_avc_i2c_bus();
 		platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
+		mpq8064_pcie_init();
 	} else {
 		ethernet_init();
 		platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index e23b76c..3c3843a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 400000000,
+			.gpu_freq = 450000000,
 			.bus_freq = 3,
 			.io_fraction = 0,
 		},
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 978eb09..1c6c600 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -55,6 +55,21 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting external_vfr[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+};
+
 static struct gpiomux_setting gsbi_uart = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -424,6 +439,16 @@
 	},
 };
 
+static struct msm_gpiomux_config msm8960_external_vfr_configs[] __initdata = {
+	{
+		.gpio      = 23,        /* EXTERNAL VFR */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &external_vfr[0],
+			[GPIOMUX_ACTIVE] = &external_vfr[1],
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm8960_gsbi8_uart_configs[] __initdata = {
 	{
 		.gpio      = 34,        /* GSBI8 UART3 */
@@ -953,15 +978,19 @@
 	else
 		msm_gpiomux_install(msm8960_gsbi5_uart_configs,
 			ARRAY_SIZE(msm8960_gsbi5_uart_configs));
-	/* For 8960 Fusion 2.2 Primary IPC */
-	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		/* For 8960 Fusion 2.2 Primary IPC */
 		msm_gpiomux_install(msm8960_fusion_gsbi_configs,
 			ARRAY_SIZE(msm8960_fusion_gsbi_configs));
+		/* For SGLTE 8960 Fusion External VFR */
+		msm_gpiomux_install(msm8960_external_vfr_configs,
+			ARRAY_SIZE(msm8960_external_vfr_configs));
+	}
 
 #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
 	msm_gpiomux_install(msm8960_sdcc2_configs,
 		ARRAY_SIZE(msm8960_sdcc2_configs));
 #endif
-
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 3df5000..624cf5e 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -105,6 +105,20 @@
 };
 #endif
 
+static struct gpiomux_setting wlan_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting wlan_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
 static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
 	{
 		.gpio = 24,
@@ -307,6 +321,17 @@
 };
 #endif
 
+static struct msm_gpiomux_config msm9615_wlan_configs[] __initdata = {
+	{
+		.gpio      = 21,/* WLAN_RESET_N */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &wlan_active_config,
+			[GPIOMUX_SUSPENDED] = &wlan_suspend_config,
+		},
+	},
+};
+
+
 int __init msm9615_init_gpiomux(void)
 {
 	int rc;
@@ -333,6 +358,9 @@
 	msm_gpiomux_install(msm9615_audio_codec_configs,
 			ARRAY_SIZE(msm9615_audio_codec_configs));
 
+	msm_gpiomux_install(msm9615_wlan_configs,
+			ARRAY_SIZE(msm9615_wlan_configs));
+
 #ifdef CONFIG_FB_MSM_EBI2
 	msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
 			ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 3b99e6c..06affd4 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -127,6 +127,103 @@
 };
 #endif
 
+struct pm8xxx_gpio_init {
+	unsigned		gpio;
+	struct pm_gpio		config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8018_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8018_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8018_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8018_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8018_GPIO_DISABLE(_gpio) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8018_GPIO_VIN_S3, \
+			 0, 0, 0, 1)
+
+#define PM8018_GPIO_OUTPUT(_gpio, _val, _strength) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_INPUT(_gpio, _pull) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8018 GPIO configurations */
+static struct pm8xxx_gpio_init pm8018_gpios[] __initdata = {
+	PM8018_GPIO_OUTPUT(2,	0,	HIGH) /* EXT_LDO_EN_WLAN */
+};
+
+/* Initial PM8018 MPP configurations */
+static struct pm8xxx_mpp_init pm8018_mpps[] __initdata = {
+};
+
+void __init msm9615_pm8xxx_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8018_gpios[i].gpio,
+					&pm8018_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8018_mpps[i].mpp,
+					&pm8018_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
@@ -876,7 +973,7 @@
 		&msm_hsic_peripheral_pdata;
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
-
+	msm9615_pm8xxx_gpio_mpp_init();
 	acpuclk_init(&acpuclk_9615_soc_data);
 
 	/* Ensure ar6000pm device is registered before MMC/SDC */
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index eb06b81..d33f478 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -463,10 +463,14 @@
 			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
 			"spmi-pmic-arb.0", NULL),
-	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF980B000, \
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
-	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF984B000, \
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
 			"msm_sdcc.3", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
+			"msm_sdcc.4", NULL),
 	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
 			"pil-q6v5-lpass", NULL),
 	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index c069aab..251c97a 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -75,7 +75,7 @@
 	.gpio_no_mux = 1,
 };
 
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
 static struct gpio ov7692_cam_req_gpio[] = {
 	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
 	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
@@ -194,7 +194,7 @@
 };
 #endif
 
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
 static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
 	.mount_angle = 90,
 	.cam_vreg = msm_cam_vreg,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 803550a..9ec618d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -760,9 +760,9 @@
 static void msm7x27a_cfg_uart2dm_serial(void) { }
 #endif
 
-struct fmem_platform_data fmem_pdata;
+static struct fmem_platform_data fmem_pdata;
 
-struct platform_device fmem_device = {
+static struct platform_device fmem_device = {
 	.name = "fmem",
 	.id = 1,
 	.dev = { .platform_data = &fmem_pdata },
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index b0799c2..e172481 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2639,7 +2639,11 @@
 #define MSM_SMI_SIZE          0x4000000
 
 #define KERNEL_SMI_BASE       (MSM_SMI_BASE)
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+#define KERNEL_SMI_SIZE       0x000000
+#else
 #define KERNEL_SMI_SIZE       0x600000
+#endif
 
 #define USER_SMI_BASE         (KERNEL_SMI_BASE + KERNEL_SMI_SIZE)
 #define USER_SMI_SIZE         (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
@@ -2648,7 +2652,7 @@
 #define MSM_ION_SF_SIZE		0x4000000 /* 64MB */
 #define MSM_ION_CAMERA_SIZE     MSM_PMEM_ADSP_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE		0x3600000 /* (54MB) Must be a multiple of 64K */
+#define MSM_ION_MM_SIZE		0x3c00000 /* (60MB) Must be a multiple of 64K */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
 #define MSM_ION_WB_SIZE		0xC00000 /* 12MB */
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f565075..b74b285 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,6 +31,7 @@
 #include <linux/memblock.h>
 #include <linux/input/ft5x06_ts.h>
 #include <linux/msm_adc.h>
+#include <linux/fmem.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -382,6 +383,9 @@
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
 	.cached = 1,
 	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
 };
 
 static struct platform_device android_pmem_adsp_device = {
@@ -618,6 +622,14 @@
 	},
 };
 
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
 	&android_pmem_device,
@@ -630,6 +642,7 @@
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
 	&msm_adc_device,
+	&fmem_device,
 };
 
 static struct platform_device *qrd7627a_devices[] __initdata = {
@@ -687,12 +700,44 @@
 	},
 };
 
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
 static void __init size_pmem_devices(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
+
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_mdp_size;
 	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+	fmem_pdata.align = PAGE_SIZE;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
+
 #endif
 }
 
@@ -704,9 +749,10 @@
 static void __init reserve_pmem_memory(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
-	reserve_memory_for(&android_pmem_adsp_pdata);
-	reserve_memory_for(&android_pmem_pdata);
-	reserve_memory_for(&android_pmem_audio_pdata);
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
 	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
 #endif
 }
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 3a0b87e..1ebf597 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4992,9 +4992,9 @@
 	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
 	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
-	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		""),
-	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	""),
-	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		"msm_pcie"),
+	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	"msm_pcie"),
+	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		"msm_pcie"),
 	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 03667d7..80403f8 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4906,8 +4906,8 @@
 
 	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, ""),
 	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, ""),
-	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, ""),
-	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, ""),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
 	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
 
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f6eee76..29a90e4 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -82,6 +82,25 @@
 #define MSM_HSUSB4_PHYS		0x12530000
 #define MSM_HSUSB4_SIZE		SZ_4K
 
+/* Address of PCIE20 PARF */
+#define PCIE20_PARF_PHYS   0x1b600000
+#define PCIE20_PARF_SIZE   SZ_128
+
+/* Address of PCIE20 ELBI */
+#define PCIE20_ELBI_PHYS   0x1b502000
+#define PCIE20_ELBI_SIZE   SZ_256
+
+/* Address of PCIE20 */
+#define PCIE20_PHYS   0x1b500000
+#define PCIE20_SIZE   SZ_4K
+
+/* AXI address for PCIE device BAR resources */
+#define PCIE_AXI_BAR_PHYS   0x08000000
+#define PCIE_AXI_BAR_SIZE   SZ_8M
+
+/* AXI address for PCIE device config space */
+#define PCIE_AXI_CONF_PHYS   0x08c00000
+#define PCIE_AXI_CONF_SIZE   SZ_4K
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
@@ -1518,6 +1537,46 @@
 	},
 };
 
+static struct resource resources_msm_pcie[] = {
+	{
+		.name   = "parf",
+		.start  = PCIE20_PARF_PHYS,
+		.end    = PCIE20_PARF_PHYS + PCIE20_PARF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "elbi",
+		.start  = PCIE20_ELBI_PHYS,
+		.end    = PCIE20_ELBI_PHYS + PCIE20_ELBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "pcie20",
+		.start  = PCIE20_PHYS,
+		.end    = PCIE20_PHYS + PCIE20_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_bar",
+		.start  = PCIE_AXI_BAR_PHYS,
+		.end    = PCIE_AXI_BAR_PHYS + PCIE_AXI_BAR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_conf",
+		.start  = PCIE_AXI_CONF_PHYS,
+		.end    = PCIE_AXI_CONF_PHYS + PCIE_AXI_CONF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_pcie = {
+	.name           = "msm_pcie",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_msm_pcie),
+	.resource       = resources_msm_pcie,
+};
+
 #ifdef CONFIG_HW_RANDOM_MSM
 /* PRNG device */
 #define MSM_PRNG_PHYS           0x1A500000
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8f42ede..d01a229 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -167,6 +167,8 @@
 extern struct platform_device msm_device_dmov_adm0;
 extern struct platform_device msm_device_dmov_adm1;
 
+extern struct platform_device msm_device_pcie;
+
 extern struct platform_device msm_device_nand;
 
 extern struct platform_device msm_device_tssc;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index d433b9e..d3b2274 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -59,20 +59,19 @@
 	int channel_active;
 	int sd;
 	size_t sd_size;
-	struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
-	struct mutex lock;
-	spinlock_t list_lock;
+	spinlock_t lock;
 	unsigned int irq;
 	struct clk *clk;
 	struct clk *pclk;
 	struct clk *ebiclk;
 	unsigned int clk_ctl;
-	struct delayed_work work;
+	struct timer_list timer;
 };
 
-static void msm_dmov_clock_work(struct work_struct *);
+static void msm_dmov_clock_timer(unsigned long);
+static int msm_dmov_clk_toggle(int, int);
 
 #ifdef CONFIG_ARCH_MSM8X60
 
@@ -164,19 +163,15 @@
 	{
 		.crci_conf = adm0_crci_conf,
 		.chan_conf = adm0_chan_conf,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
 	}, {
 		.crci_conf = adm1_crci_conf,
 		.chan_conf = adm1_chan_conf,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
 	}
 };
 #else
@@ -184,11 +179,9 @@
 	{
 		.crci_conf = NULL,
 		.chan_conf = NULL,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
 	}
 };
 #endif
@@ -230,153 +223,94 @@
 #define PRINT_FLOW(format, args...) \
 	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
 
-static int msm_dmov_clk_on(int adm)
+static int msm_dmov_clk_toggle(int adm, int on)
 {
-	int ret;
+	int ret = 0;
 
-	ret = clk_prepare_enable(dmov_conf[adm].clk);
-	if (ret)
-		return ret;
-	if (dmov_conf[adm].pclk) {
-		ret = clk_prepare_enable(dmov_conf[adm].pclk);
-		if (ret) {
-			clk_disable_unprepare(dmov_conf[adm].clk);
-			return ret;
+	if (on) {
+		ret = clk_enable(dmov_conf[adm].clk);
+		if (ret)
+			goto err;
+		if (dmov_conf[adm].pclk) {
+			ret = clk_enable(dmov_conf[adm].pclk);
+			if (ret) {
+				clk_disable(dmov_conf[adm].clk);
+				goto err;
+			}
 		}
-	}
-	if (dmov_conf[adm].ebiclk) {
-		ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
-		if (ret) {
-			if (dmov_conf[adm].pclk)
-				clk_disable_unprepare(dmov_conf[adm].pclk);
-			clk_disable_unprepare(dmov_conf[adm].clk);
+		if (dmov_conf[adm].ebiclk) {
+			ret = clk_enable(dmov_conf[adm].ebiclk);
+			if (ret) {
+				if (dmov_conf[adm].pclk)
+					clk_disable(dmov_conf[adm].pclk);
+				clk_disable(dmov_conf[adm].clk);
+			}
 		}
+	} else {
+		clk_disable(dmov_conf[adm].clk);
+		if (dmov_conf[adm].pclk)
+			clk_disable(dmov_conf[adm].pclk);
+		if (dmov_conf[adm].ebiclk)
+			clk_disable(dmov_conf[adm].ebiclk);
 	}
+err:
 	return ret;
 }
 
-static void msm_dmov_clk_off(int adm)
+static void msm_dmov_clock_timer(unsigned long adm)
 {
-	clk_disable_unprepare(dmov_conf[adm].clk);
-	if (dmov_conf[adm].pclk)
-		clk_disable_unprepare(dmov_conf[adm].pclk);
-	if (dmov_conf[adm].ebiclk)
-		clk_disable_unprepare(dmov_conf[adm].ebiclk);
-}
-
-static void msm_dmov_clock_work(struct work_struct *work)
-{
-	struct msm_dmov_conf *conf =
-		container_of(to_delayed_work(work), struct msm_dmov_conf, work);
-	int adm = DMOV_IRQ_TO_ADM(conf->irq);
-	mutex_lock(&conf->lock);
-	if (conf->clk_ctl == CLK_TO_BE_DIS) {
-		BUG_ON(conf->channel_active);
-		msm_dmov_clk_off(adm);
-		conf->clk_ctl = CLK_DIS;
+	unsigned long irq_flags;
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+		BUG_ON(dmov_conf[adm].channel_active);
+		msm_dmov_clk_toggle(adm, 0);
+		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	mutex_unlock(&conf->lock);
-}
-
-enum {
-	NOFLUSH = 0,
-	GRACEFUL,
-	NONGRACEFUL,
-};
-
-/* Caller must hold the list lock */
-static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm)
-{
-	struct msm_dmov_cmd *cmd;
-
-	if (list_empty(&dmov_conf[adm].ready_commands[ch]))
-		return NULL;
-
-	cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
-			 list);
-	list_del(&cmd->list);
-	if (cmd->exec_func)
-		cmd->exec_func(cmd);
-	list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
-	if (!dmov_conf[adm].channel_active)
-		enable_irq(dmov_conf[adm].irq);
-	dmov_conf[adm].channel_active |= BIT(ch);
-	PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch);
-	writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
-
-	return cmd;
-}
-
-static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
-{
-	struct msm_dmov_cmd *cmd =
-		container_of(work, struct msm_dmov_cmd, work);
-	unsigned id = cmd->id;
-	unsigned status;
-	unsigned long flags;
-	int adm = DMOV_ID_TO_ADM(id);
-	int ch = DMOV_ID_TO_CHAN(id);
-
-	mutex_lock(&dmov_conf[adm].lock);
-	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
-		status = msm_dmov_clk_on(adm);
-		if (status != 0)
-			goto error;
-	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
-		cancel_delayed_work_sync(&dmov_conf[adm].work);
-	dmov_conf[adm].clk_ctl = CLK_EN;
-
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-
-	cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd),
-			 list);
-	list_del(&cmd->list);
-	list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
-	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
-	if (status & DMOV_STATUS_CMD_PTR_RDY) {
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
-			id, status);
-		cmd = start_ready_cmd(ch, adm);
-		/*
-		 * We added something to the ready list, and still hold the
-		 * list lock. Thus, no need to check for cmd == NULL
-		 */
-		if (cmd->toflush) {
-			int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0;
-			writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
-		}
-	} else {
-		cmd->toflush = 0;
-		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
-		    !list_empty(&dmov_conf[adm].ready_commands[ch]))
-			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
-				"status %x\n", id, status);
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
-		    "%x\n", id, status);
-	}
-	if (!dmov_conf[adm].channel_active) {
-		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
-	}
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-error:
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 
 void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
 {
+	unsigned long irq_flags;
+	unsigned int status;
 	int adm = DMOV_ID_TO_ADM(id);
 	int ch = DMOV_ID_TO_CHAN(id);
-	unsigned long flags;
-	cmd->id = id;
-	cmd->toflush = 0;
-	INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
 
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-	list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
+		status = msm_dmov_clk_toggle(adm, 1);
+		if (status != 0)
+			goto error;
+	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
+		del_timer(&dmov_conf[adm].timer);
+	dmov_conf[adm].clk_ctl = CLK_EN;
 
-	schedule_work(&cmd->work);
+	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
+	if (status & DMOV_STATUS_CMD_PTR_RDY) {
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
+			id, status);
+		if (cmd->exec_func)
+			cmd->exec_func(cmd);
+		list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+		if (!dmov_conf[adm].channel_active)
+			enable_irq(dmov_conf[adm].irq);
+		dmov_conf[adm].channel_active |= 1U << ch;
+		PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
+		writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
+	} else {
+		if (!dmov_conf[adm].channel_active) {
+			dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+			mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+		}
+		if (list_empty(&dmov_conf[adm].active_commands[ch]))
+			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
+				"status %x\n", id, status);
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
+		    "%x\n", id, status);
+		list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
+	}
+error:
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
 
@@ -395,18 +329,14 @@
 	int ch = DMOV_ID_TO_CHAN(id);
 	int adm = DMOV_ID_TO_ADM(id);
 	int flush = graceful ? DMOV_FLUSH_TYPE : 0;
-	struct msm_dmov_cmd *cmd;
-
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	/* XXX not checking if flush cmd sent already */
 	if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
 		PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
 		writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
 	}
-	list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list)
-		cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL;
 	/* spin_unlock_irqrestore has the necessary barrier */
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_flush);
 
@@ -468,7 +398,7 @@
 	errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
 }
 
-static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
+static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
 {
 	unsigned int int_status;
 	unsigned int mask;
@@ -481,12 +411,11 @@
 	struct msm_dmov_cmd *cmd;
 	int adm = DMOV_IRQ_TO_ADM(irq);
 
-	mutex_lock(&dmov_conf[adm].lock);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	/* read and clear isr */
 	int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
 	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
 
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
 	while (int_status) {
 		mask = int_status & -int_status;
 		ch = fls(mask) - 1;
@@ -554,38 +483,51 @@
 			ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
 						  adm));
 			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
-			if (ch_status & DMOV_STATUS_CMD_PTR_RDY)
-				start_ready_cmd(ch, adm);
+			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
+			    !list_empty(&dmov_conf[adm].ready_commands[ch])) {
+				cmd = list_entry(dmov_conf[adm].
+					ready_commands[ch].next, typeof(*cmd),
+					list);
+				list_del(&cmd->list);
+				if (cmd->exec_func)
+					cmd->exec_func(cmd);
+				list_add_tail(&cmd->list,
+					&dmov_conf[adm].active_commands[ch]);
+				PRINT_FLOW("msm_datamover_irq_handler id %d,"
+						 "start command\n", id);
+				writel_relaxed(cmd->cmdptr,
+					       DMOV_REG(DMOV_CMD_PTR(ch), adm));
+			}
 		} while (ch_status & DMOV_STATUS_RSLT_VALID);
 		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
-		    list_empty(&dmov_conf[adm].ready_commands[ch]))
+				list_empty(&dmov_conf[adm].ready_commands[ch]))
 			dmov_conf[adm].channel_active &= ~(1U << ch);
 		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 	}
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
 
 	if (!dmov_conf[adm].channel_active && valid) {
 		disable_irq_nosync(dmov_conf[adm].irq);
 		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
+		mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
 	}
 
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 	return valid ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int msm_dmov_suspend_late(struct device *dev)
 {
+	unsigned long irq_flags;
 	struct platform_device *pdev = to_platform_device(dev);
 	int adm = (pdev->id >= 0) ? pdev->id : 0;
-	mutex_lock(&dmov_conf[adm].lock);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
 		BUG_ON(dmov_conf[adm].channel_active);
-		cancel_delayed_work_sync(&dmov_conf[adm].work);
-		msm_dmov_clk_off(adm);
+		del_timer(&dmov_conf[adm].timer);
+		msm_dmov_clk_toggle(adm, 0);
 		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 	return 0;
 }
 
@@ -700,8 +642,8 @@
 	if (!dmov_conf[adm].base)
 		return -ENOMEM;
 
-	ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
-				   IRQF_ONESHOT, "msmdatamover", NULL);
+	ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
+		0, "msmdatamover", NULL);
 	if (ret) {
 		PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
 			dmov_conf[adm].irq);
@@ -713,7 +655,7 @@
 		PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
 		goto out_irq;
 	}
-	ret = msm_dmov_clk_on(adm);
+	ret = msm_dmov_clk_toggle(adm, 1);
 	if (ret) {
 		PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
 		goto out_irq;
@@ -721,7 +663,6 @@
 
 	config_datamover(adm);
 	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
-		INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
 
@@ -730,7 +671,7 @@
 		     DMOV_REG(DMOV_RSLT_CONF(i), adm));
 	}
 	wmb();
-	msm_dmov_clk_off(adm);
+	msm_dmov_clk_toggle(adm, 0);
 	return ret;
 out_irq:
 	free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
new file mode 100644
index 0000000..1622e13
--- /dev/null
+++ b/arch/arm/mach-msm/idle-macros.S
@@ -0,0 +1,153 @@
+/* Copyright (c) 2012, 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/hardware/cache-l2x0.h>
+
+/* Add 300 NOPs after 'wfi' for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+	.rept   \rept
+	nop
+	.endr
+#endif
+.endm
+
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip\@
+	mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
+	.if     \on
+	orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
+	.else
+	bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
+	.endif
+	mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
+	isb
+skip\@:
+.endm
+
+/*
+ * Enable the "L2" cache, not require to restore the controller registers
+ */
+.macro ENABLE_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_enable\@
+	ldr     r0, =apps_power_collapse
+	ldr     r0, [r0]
+	cmp     r0, #POWER_COLLAPSED
+	bne     skip_enable\@
+	ldr     r0, =l2x0_base_addr
+	ldr	r0, [r0]
+	mov	r1, #0x1
+	str	r1, [r0, #L2X0_CTRL]
+	dmb
+skip_enable\@:
+.endm
+
+/*
+ * Perform the required operation
+ * operation: type of operation on l2 cache (e.g: clean&inv or inv)
+ * l2_enable: enable or disable
+ */
+.macro DO_CACHE_OPERATION, operation, l2_enable
+	ldr     r2, =l2x0_base_addr
+	ldr	r2, [r2]
+	ldr     r0, =0xffff
+	str     r0, [r2, #\operation]
+wait\@:
+	ldr	r0, [r2, #\operation]
+	ldr	r1, =0xffff
+	ands    r0, r0, r1
+	bne     wait\@
+l2x_sync\@:
+	mov	r0, #0x0
+	str	r0, [r2, #L2X0_CACHE_SYNC]
+sync\@:
+	ldr	r0, [r2, #L2X0_CACHE_SYNC]
+	ands	r0, r0, #0x1
+	bne	sync\@
+	mov     r1, #\l2_enable
+	str     r1, [r2, #L2X0_CTRL]
+.endm
+
+/*
+ * Clean and invalidate the L2 cache.
+ * 1. Check the target type
+ * 2. Check whether we are coming from PC are not
+ * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
+ * 4. Start L2 clean & invalidation operation
+ * 5. Disable the L2 cache
+ */
+.macro SUSPEND_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_suspend\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_suspend\@
+	ldr	r0, =l2x0_saved_ctrl_reg_val
+	ldr	r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	ldr	r2, [r1, #L2X0_AUX_CTRL]
+	str	r2, [r0, #0x0] /* store aux_ctlr reg value */
+	ldr     r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	str     r2, [r0, #0x4] /* store data latency reg value */
+	ldr     r2, [r1, #L2X0_PREFETCH_CTRL]
+	str     r2, [r0, #0x8] /* store prefetch_ctlr reg value */
+	DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
+	dmb
+skip_suspend\@:
+.endm
+
+/*
+ * Coming back from a successful PC
+ * 1. Check the target type
+ * 2. Check whether we are going to PC are not
+ * 3. Disable the L2 cache
+ * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
+ * 5. Invalidate the cache
+ * 6. Enable the L2 cache
+ */
+.macro RESUME_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_resume\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_resume\@
+	ldr     r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	mov     r0, #0x0
+	str     r0, [r1, #L2X0_CTRL]
+	ldr     r0, =l2x0_saved_ctrl_reg_val
+	ldr     r2, [r0, #0x0]
+	str	r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
+	ldr	r2, [r0, #0x4]
+	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	ldr	r2, [r0, #0x8]
+	str     r2, [r1, #L2X0_PREFETCH_CTRL]
+	DO_CACHE_OPERATION L2X0_INV_WAY ON
+skip_resume\@:
+.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index b73ddc8..b75f76f 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -20,39 +20,13 @@
 #include <asm/assembler.h>
 
 #include "idle.h"
+#include "idle-macros.S"
 
 #ifdef CONFIG_ARCH_MSM_KRAIT
 #define SCM_SVC_BOOT 0x1
 #define SCM_CMD_TERMINATE_PC 0x2
 #endif
 
-/* Switch between smp_to_amp/amp_to_smp configuration */
-.macro SET_SMP_COHERENCY, on = 0
-ldr     r0, =target_type
-ldr     r0, [r0]
-mov     r1, #TARGET_IS_8625
-cmp     r0, r1
-bne     skip\@
-mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
-.if     \on
-orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
-.else
-bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
-.endif
-mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
-isb
-skip\@:
-.endm
-
-/* Add NOPs for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
-	.rept	\rept
-	nop
-	.endr
-#endif
-.endm
-
 ENTRY(msm_arch_idle)
 	wfi
 #ifdef CONFIG_ARCH_MSM8X60
@@ -135,16 +109,19 @@
 	bic     r0, r4, #(1 << 2)        /* clear dcache bit   */
 	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
 	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-	dsb
+	isb
 
+	SUSPEND_8x25_L2
 	SET_SMP_COHERENCY OFF
 	wfi
 	DELAY_8x25 300
 
 	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
 	isb
-#endif
+	ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
 	SET_SMP_COHERENCY ON
+#endif
+
 #if defined(CONFIG_MSM_FIQ_SUPPORT)
 	cpsie   f
 #endif
@@ -237,7 +214,6 @@
 	dsb
 	isb
 
-	SET_SMP_COHERENCY ON
 #ifdef CONFIG_ARCH_MSM_KRAIT
 	mrc	p15, 0, r1, c0, c0, 0
 	ldr	r3, =0xff00fc00
@@ -247,7 +223,11 @@
 	mrceq	p15, 7, r3, c15, c0, 2
 	biceq	r3, r3, #0x400
 	mcreq	p15, 7, r3, c15, c0, 2
+#else
+	RESUME_8x25_L2
+	SET_SMP_COHERENCY ON
 #endif
+
 #ifdef CONFIG_MSM_JTAG
 	stmfd   sp!, {lr}
 	bl      msm_jtag_restore_state
@@ -302,6 +282,14 @@
 target_type:
 	.long  0x0
 
+	.globl apps_power_collapse
+apps_power_collapse:
+	.long 0x0
+
+	.globl l2x0_base_addr
+l2x0_base_addr:
+	.long 0x0
+
 /*
  * Default the l2 flush flag to 1 so that caches are flushed during power
  * collapse unless the  L2 driver decides to flush them only during L2
@@ -309,3 +297,13 @@
  */
 msm_pm_flush_l2_flag:
 	.long 0x1
+
+/*
+ * Save & restore l2x0 registers while system is entering and resuming
+ * from Power Collapse.
+ * 1. aux_ctrl_save (0x0)
+ * 2. data_latency_ctrl (0x4)
+ * 3. prefetch control (0x8)
+ */
+l2x0_saved_ctrl_reg_val:
+	.space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index bfd632f..4abdd04 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -25,6 +25,7 @@
 #define ON	1
 #define OFF	0
 #define TARGET_IS_8625	1
+#define POWER_COLLAPSED 1
 
 #ifndef __ASSEMBLY__
 
@@ -40,6 +41,8 @@
 extern unsigned long msm_pm_pc_pgd;
 extern unsigned long msm_pm_boot_vector[NR_CPUS];
 extern uint32_t target_type;
+extern uint32_t apps_power_collapse;
+extern uint32_t *l2x0_base_addr;
 #else
 static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
 {
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 90d236b..ba5b8ac 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -653,7 +653,8 @@
 void msm_camio_camif_pad_reg_reset_2(void);
 
 void msm_camio_vfe_blk_reset(void);
-void msm_camio_vfe_blk_reset_2(int flag);
+void msm_camio_vfe_blk_reset_2(void);
+void msm_camio_vfe_blk_reset_3(void);
 
 int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo);
 void msm_camio_3d_disable(void);
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index ba621e6..70519ff 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -35,10 +35,7 @@
 			      unsigned int result,
 			      struct msm_dmov_errdata *err);
 	void (*exec_func)(struct msm_dmov_cmd *cmd);
-	struct work_struct work;
-	unsigned id;    /* For internal use */
 	void *user;	/* Pointer for caller's reference */
-	u8 toflush;
 };
 
 struct msm_dmov_pdata {
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d46b4..daf32a5 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -74,4 +74,8 @@
 };
 
 struct ocmem_zone *get_zone(unsigned);
+unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int free_head(struct ocmem_zone *, unsigned long, unsigned long);
+unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
 #endif
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 9b8bc61..2cff7f0 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -151,13 +151,43 @@
 	.notifier_call	= panic_wdog_handler,
 };
 
+struct wdog_disable_work_data {
+	struct work_struct work;
+	struct completion complete;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+	struct wdog_disable_work_data *work_data =
+		container_of(work, struct wdog_disable_work_data, work);
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	mb();
+	if (has_vic) {
+		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+	} else {
+		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		if (!appsbark_fiq) {
+			free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+					percpu_pdata);
+			free_percpu(percpu_pdata);
+		}
+	}
+	enable = 0;
+	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
+	cancel_delayed_work(&dogwork_struct);
+	/* may be suspended after the first write above */
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	complete(&work_data->complete);
+	pr_info("MSM Watchdog deactivated.\n");
+}
+
 static int wdog_enable_set(const char *val, struct kernel_param *kp)
 {
 	int ret = 0;
 	int old_val = runtime_disable;
+	struct wdog_disable_work_data work_data;
 
 	mutex_lock(&disable_lock);
-
 	if (!enable) {
 		printk(KERN_INFO "MSM Watchdog is not active.\n");
 		ret = -EINVAL;
@@ -165,43 +195,20 @@
 	}
 
 	ret = param_set_int(val, kp);
-
 	if (ret)
 		goto done;
 
-	switch (runtime_disable) {
-
-	case 1:
-		if (!old_val) {
-			__raw_writel(0, msm_tmr0_base + WDT0_EN);
-			mb();
-			if (has_vic) {
-				free_irq(WDT0_ACCSCSSNBARK_INT, 0);
-			} else {
-				disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
-				if (!appsbark_fiq) {
-					free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
-							percpu_pdata);
-					free_percpu(percpu_pdata);
-				}
-			}
-			enable = 0;
-			atomic_notifier_chain_unregister(&panic_notifier_list,
-			       &panic_blk);
-			cancel_delayed_work(&dogwork_struct);
-			/* may be suspended after the first write above */
-			__raw_writel(0, msm_tmr0_base + WDT0_EN);
-			printk(KERN_INFO "MSM Watchdog deactivated.\n");
-		}
-	break;
-
-	default:
+	if (runtime_disable == 1) {
+		if (old_val)
+			goto done;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
+	} else {
 		runtime_disable = old_val;
 		ret = -EINVAL;
-	break;
-
 	}
-
 done:
 	mutex_unlock(&disable_lock);
 	return ret;
@@ -332,9 +339,49 @@
 	}
 }
 
+struct fiq_handler wdog_fh = {
+	.name = MODULE_NAME,
+};
+
 static void init_watchdog_work(struct work_struct *work)
 {
 	u64 timeout = (bark_time * WDT_HZ)/1000;
+	void *stack;
+	int ret;
+
+	if (has_vic) {
+		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+				  "apps_wdog_bark", NULL);
+		if (ret)
+			return;
+	} else if (appsbark_fiq) {
+		claim_fiq(&wdog_fh);
+		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
+		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+		if (!stack) {
+			pr_info("No free pages available - %s fails\n",
+					__func__);
+			return;
+		}
+
+		msm_wdog_fiq_setup(stack);
+		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+	} else {
+		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+		if (!percpu_pdata) {
+			pr_err("%s: memory allocation failed for percpu data\n",
+					__func__);
+			return;
+		}
+
+		/* Must request irq before sending scm command */
+		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
+		if (ret) {
+			free_percpu(percpu_pdata);
+			return;
+		}
+	}
 
 	configure_bark_dump();
 
@@ -358,15 +405,9 @@
 	return;
 }
 
-struct fiq_handler wdog_fh = {
-	.name = MODULE_NAME,
-};
-
 static int msm_watchdog_probe(struct platform_device *pdev)
 {
 	struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
-	int ret;
-	void *stack;
 
 	if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
 		printk(KERN_INFO "MSM Watchdog Not Initialized\n");
@@ -382,41 +423,6 @@
 
 	msm_tmr0_base = msm_timer_get_timer0_base();
 
-	if (has_vic) {
-		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
-				  "apps_wdog_bark", NULL);
-		if (ret)
-			return ret;
-	} else if (appsbark_fiq) {
-		claim_fiq(&wdog_fh);
-		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
-		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
-		if (!stack) {
-			pr_info("No free pages available - %s fails\n",
-					__func__);
-			return -ENOMEM;
-		}
-
-		msm_wdog_fiq_setup(stack);
-		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
-	} else {
-		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
-		if (!percpu_pdata) {
-			pr_err("%s: memory allocation failed for percpu data\n",
-					__func__);
-			return -ENOMEM;
-		}
-
-		*__this_cpu_ptr(percpu_pdata) = pdata;
-		/* Must request irq before sending scm command */
-		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
-			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
-		if (ret) {
-			free_percpu(percpu_pdata);
-			return ret;
-		}
-	}
-
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
 	 * This initialization will be done in SBLs on a later releases
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d1c474b..a0e01b4 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -32,4 +32,16 @@
 }
 
 void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
+
+int msm_pm_idle_prepare(struct cpuidle_device *dev)
+{
+	return -ENOSYS;
+}
+
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+{
+	return -ENOSYS;
+}
+
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index af39dc3..ed0b2f0 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -29,6 +29,7 @@
 	unsigned long p_start;
 	unsigned long p_size;
 	unsigned long p_min;
+	unsigned int p_tail;
 };
 
 struct ocmem_plat_data {
@@ -70,19 +71,20 @@
 	unsigned long start;
 	unsigned long size;
 	unsigned long min;
+	unsigned int tail;
 };
 
 /* This static table will go away with device tree support */
 static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
-	/* name,	id,	start,	size,	min */
-	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
-	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
-	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
-	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0 },
-	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
-	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
-	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
-	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+	/* name,        id,     start,  size,   min, tail */
+	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
+	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
+	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
+	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0, 0 },
+	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
+	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
+	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000, 0},
+	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
 };
 
 static inline int get_id(const char *name)
@@ -142,6 +144,7 @@
 		parts[j].p_size = qt[i].size;
 		parts[j].p_start = qt[i].start;
 		parts[j].p_min = qt[i].min;
+		parts[j].p_tail = qt[i].tail;
 		j++;
 	}
 	BUG_ON(j != nr_parts);
@@ -225,6 +228,13 @@
 		zone->max_regions = 0;
 		INIT_LIST_HEAD(&zone->region_list);
 		zone->z_ops = z_ops;
+		if (part->p_tail) {
+			z_ops->allocate = allocate_tail;
+			z_ops->free = free_tail;
+		} else {
+			z_ops->allocate = allocate_head;
+			z_ops->free = free_head;
+		}
 		active_zones++;
 
 		if (active_zones == 1)
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
new file mode 100644
index 0000000..71cacda
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -0,0 +1,105 @@
+/* Copyright (c) 2012, 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 <mach/ocmem.h>
+#include <mach/ocmem_priv.h>
+#include <linux/genalloc.h>
+
+/* All allocator operations are serialized by ocmem driver */
+
+/* The allocators work as follows:
+	Constraints:
+	1) There is no IOMMU access to OCMEM hence successive allocations
+		in the zone must be physically contiguous
+	2) Allocations must be freed in reverse order within a zone.
+
+	z->z_start: Fixed pointer to the start of a zone
+	z->z_end:   Fixed pointer to the end of a zone
+
+	z->z_head:  Movable pointer to the next free area when growing at head
+			Fixed on zones that grow from tail
+
+	z->z_tail:  Movable pointer to the next free area when growing at tail
+			Fixed on zones that grow from head
+
+	z->z_free:  Free space in a zone that is updated on an allocation/free
+
+	reserve:    Enable libgenpool to simulate tail allocations
+*/
+
+unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+{
+
+	unsigned long offset;
+
+	offset  = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_head += size;
+	z->z_free -= size;
+	return offset;
+}
+
+unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+{
+	unsigned long offset;
+	unsigned long reserve;
+	unsigned long head;
+
+	if (z->z_tail < (z->z_head + size))
+		return -ENOMEM;
+
+	reserve = z->z_tail - z->z_head - size;
+	if (reserve) {
+		head = gen_pool_alloc(z->z_pool, reserve);
+		offset = gen_pool_alloc(z->z_pool, size);
+		gen_pool_free(z->z_pool, head, reserve);
+	} else
+		offset = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_tail -= size;
+	z->z_free -= size;
+	return offset;
+}
+
+int free_head(struct ocmem_zone *z, unsigned long offset,
+			unsigned long size)
+{
+	if (offset > z->z_head) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_head -= size;
+	z->z_free += size;
+	return 0;
+}
+
+int free_tail(struct ocmem_zone *z, unsigned long offset,
+				unsigned long size)
+{
+	if (offset > z->z_tail) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_tail += size;
+	z->z_free += size;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 0ecea85..7208a48 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -137,8 +137,11 @@
 	const struct firmware *fw = NULL;
 	const u8 *data;
 
-	if (memblock_is_region_memory(phdr->p_paddr, phdr->p_memsz)) {
-		dev_err(&pil->dev, "Kernel memory would be overwritten");
+	if (memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
+		dev_err(&pil->dev,
+			"kernel memory would be overwritten [%#08lx, %#08lx)\n",
+			(unsigned long)phdr->p_paddr,
+			(unsigned long)(phdr->p_paddr + phdr->p_memsz));
 		return -EPERM;
 	}
 
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 5eac539..8691ac7 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,37 +18,19 @@
 #include <linux/iopoll.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
 /* Register Offsets */
 #define QDSP6SS_RST_EVB			0x010
-#define LPASS_Q6SS_BCR			0x06000
-#define LPASS_Q6SS_AHB_LFABIF_CBCR	0x22000
-#define LPASS_Q6SS_XO_CBCR		0x26000
 #define AXI_HALTREQ			0x0
 #define AXI_HALTACK			0x4
 #define AXI_IDLE			0x8
 
 #define HALT_ACK_TIMEOUT_US		100000
 
-static void clk_reg_enable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val |= BIT(0);
-	writel_relaxed(val, reg);
-}
-
-static void clk_reg_disable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val &= ~BIT(0);
-	writel_relaxed(val, reg);
-}
-
 static int pil_lpass_shutdown(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
@@ -64,17 +46,18 @@
 		dev_err(pil->dev, "Port halt failed\n");
 	writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
 
-	/* Make sure Q6 registers are accessible */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	/*
+	 * If the shutdown function is called before the reset function, clocks
+	 * will not be enabled yet. Enable them here so that register writes
+	 * performed during the shutdown succeed.
+	 */
+	if (drv->is_booted == false)
+		pil_q6v5_enable_clks(pil);
 
 	pil_q6v5_shutdown(pil);
+	pil_q6v5_disable_clks(pil);
 
-	/* Disable clocks and assert subsystem resets. */
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	writel_relaxed(1, drv->clk_base + LPASS_Q6SS_BCR);
+	drv->is_booted = false;
 
 	return 0;
 }
@@ -82,21 +65,25 @@
 static int pil_lpass_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
 
-	/*
-	 * Bring subsystem out of reset and enable required
-	 * regulators and clocks.
-	 */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	ret = pil_q6v5_enable_clks(pil);
+	if (ret)
+		return ret;
 
 	/* Program Image Address */
 	writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
 				drv->reg_base + QDSP6SS_RST_EVB);
 
-	return pil_q6v5_reset(pil);
+	ret = pil_q6v5_reset(pil);
+	if (ret) {
+		pil_q6v5_disable_clks(pil);
+		return ret;
+	}
+
+	drv->is_booted = true;
+
+	return 0;
 }
 
 static struct pil_reset_ops pil_lpass_ops = {
@@ -124,7 +111,7 @@
 	desc->ops = &pil_lpass_ops;
 	desc->owner = THIS_MODULE;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 	if (!drv->axi_halt_base)
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index cd58a4c..3b9d542 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -20,6 +20,8 @@
 #include <linux/of.h>
 #include <linux/clk.h>
 
+#include <mach/clk.h>
+
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
@@ -76,6 +78,42 @@
 }
 EXPORT_SYMBOL(pil_q6v5_init_image);
 
+int pil_q6v5_enable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->bus_clk);
+	if (ret)
+		goto err_bus_clk;
+
+	return 0;
+
+err_bus_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	return ret;
+}
+EXPORT_SYMBOL(pil_q6v5_enable_clks);
+
+void pil_q6v5_disable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	clk_disable_unprepare(drv->bus_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+EXPORT_SYMBOL(pil_q6v5_disable_clks);
+
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -173,12 +211,6 @@
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	drv->clk_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
-	if (!drv->clk_base)
-		return ERR_PTR(-ENOMEM);
-
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)
 		return ERR_PTR(-ENOMEM);
@@ -192,6 +224,14 @@
 	if (IS_ERR(drv->xo))
 		return ERR_CAST(drv->xo);
 
+	drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->bus_clk))
+		return ERR_CAST(drv->bus_clk);
+
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return ERR_CAST(drv->core_clk);
+
 	desc->dev = &pdev->dev;
 
 	return desc;
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index b17d4e7..5f283da 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -21,14 +21,15 @@
 
 struct q6v5_data {
 	void __iomem *reg_base;
-	void __iomem *clk_base;
+	struct clk *xo;
+	struct clk *bus_clk;
+	struct clk *core_clk;
 	void __iomem *axi_halt_base;
 	void __iomem *rmb_base;
 	unsigned long start_addr;
 	struct regulator *vreg;
-	bool vreg_enabled;
+	bool is_booted;
 	int self_auth;
-	struct clk *xo;
 	struct pil_device *pil;
 };
 
@@ -38,6 +39,8 @@
 			size_t size);
 void pil_q6v5_shutdown(struct pil_desc *pil);
 int pil_q6v5_reset(struct pil_desc *pil);
+int pil_q6v5_enable_clks(struct pil_desc *pil);
+void pil_q6v5_disable_clks(struct pil_desc *pil);
 struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
 
 #endif
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index cbe5201..070e2c5 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -21,11 +21,9 @@
 #include <linux/ktime.h>
 #include <linux/pm.h>
 #include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
 #include <linux/smp.h>
 #include <linux/suspend.h>
 #include <linux/tick.h>
-#include <linux/uaccess.h>
 #include <linux/wakelock.h>
 #include <linux/delay.h>
 #include <mach/msm_iomap.h>
@@ -319,220 +317,6 @@
 }
 
 /******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_RETENTION,
-	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
-	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-static DEFINE_PER_CPU_SHARED_ALIGNED(
-	struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	unsigned long flags;
-	struct msm_pm_time_stats *stats;
-	int64_t bt;
-	int i;
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	stats = __get_cpu_var(msm_pm_stats).stats;
-
-	stats[id].total_time += t;
-	stats[id].count++;
-
-	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
-
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	stats[id].bucket[i]++;
-
-	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
-		stats[id].min_time[i] = t;
-	if (t > stats[id].max_time[i])
-		stats[id].max_time[i] = t;
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	unsigned int cpu = off / MSM_PM_STAT_COUNT;
-	int id = off % MSM_PM_STAT_COUNT;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (cpu < num_possible_cpus()) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-
-		s = stats[id].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"[cpu %u] %s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			cpu, stats[id].name,
-			stats[id].count,
-			s, ns);
-
-		bucket_time = stats[id].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, stats[id].bucket[i],
-			stats[id].min_time[i],
-			stats[id].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	unsigned int cpu;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats;
-		int i;
-
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
-			memset(stats[i].bucket,
-				0, sizeof(stats[i].bucket));
-			memset(stats[i].min_time,
-				0, sizeof(stats[i].min_time));
-			memset(stats[i].max_time,
-				0, sizeof(stats[i].max_time));
-			stats[i].count = 0;
-			stats[i].total_time = 0;
-		}
-	}
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
  * Configure Hardware before/after Low Power Mode
  *****************************************************************************/
 
@@ -805,6 +589,38 @@
 	msm_timer_exit_idle((int) timer_halted);
 }
 
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	if (msm_pm_use_qtimer)
+		return sched_clock();
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+
+	return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+	if (msm_pm_use_qtimer)
+		return sched_clock() - time;
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+		} else
+			time = 0;
+	}
+
+	return time;
+}
+
 /******************************************************************************
  * External Idle/Suspend Functions
  *****************************************************************************/
@@ -926,9 +742,7 @@
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
 {
 	int64_t time;
-#ifdef CONFIG_MSM_IDLE_STATS
 	int exit_stat;
-#endif
 
 	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: mode %d\n",
@@ -939,23 +753,17 @@
 	switch (sleep_mode) {
 	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 		msm_pm_swfi();
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_RETENTION:
 		msm_pm_retention();
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_RETENTION;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
 		msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
@@ -987,10 +795,7 @@
 					notify_rpm, collapsed);
 		}
 		msm_pm_timer_exit_idle(timer_halted);
-
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-#endif
 		break;
 	}
 
@@ -1000,9 +805,7 @@
 	}
 
 	time = ktime_to_ns(ktime_get()) - time;
-#ifdef CONFIG_MSM_IDLE_STATS
 	msm_pm_add_stat(exit_stat, time);
-#endif
 
 	do_div(time, 1000);
 	return (int) time;
@@ -1097,11 +900,8 @@
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	int i;
-
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
-	int64_t time = msm_timer_get_sclk_time(&period);
-#endif
+	int64_t time = msm_pm_timer_enter_suspend(&period);
 
 	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s\n", __func__);
@@ -1163,19 +963,8 @@
 			pr_err("%s: cannot find the lowest power limit\n",
 				__func__);
 		}
-
-#ifdef CONFIG_MSM_IDLE_STATS
-		if (time != 0) {
-			int64_t end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
+		time = msm_pm_timer_exit_suspend(time, period);
 		msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
-#endif /* CONFIG_MSM_IDLE_STATS */
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: standalone power collapse\n", __func__);
@@ -1217,10 +1006,14 @@
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
 	unsigned long pmdval;
-#ifdef CONFIG_MSM_IDLE_STATS
-	unsigned int cpu;
-	struct proc_dir_entry *d_entry;
-#endif
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_RETENTION,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+	};
+
 	/* Page table for cores to come back up safely. */
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
@@ -1257,49 +1050,9 @@
 	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
 		     virt_to_phys(&msm_pm_pc_pgd));
 
-#ifdef CONFIG_MSM_IDLE_STATS
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats =
-			per_cpu(msm_pm_stats, cpu).stats;
-
-		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
-		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
-		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_RETENTION].name = "retention";
-		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
-			"idle-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
-			"idle-power-collapse";
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
-		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
-			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-	}
-
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif  /* CONFIG_MSM_IDLE_STATS */
-
-
 	msm_pm_mode_sysfs_add();
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
 	msm_spm_allow_x_cpu_set_vdd(false);
 
 	suspend_set_ops(&msm_pm_ops);
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
new file mode 100644
index 0000000..936820a
--- /dev/null
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2012, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include "pm.h"
+
+struct msm_pm_time_stats {
+	const char *name;
+	int64_t first_bucket_time;
+	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int count;
+	int64_t total_time;
+	bool enabled;
+};
+
+struct msm_pm_cpu_time_stats {
+	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
+};
+
+static DEFINE_SPINLOCK(msm_pm_stats_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(
+	struct msm_pm_cpu_time_stats, msm_pm_stats);
+
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	unsigned long flags;
+	struct msm_pm_time_stats *stats;
+	int64_t bt;
+	int i;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	stats = __get_cpu_var(msm_pm_stats).stats;
+
+	if (!stats[id].enabled)
+		goto add_bail;
+
+	stats[id].total_time += t;
+	stats[id].count++;
+
+	bt = t;
+	do_div(bt, stats[id].first_bucket_time);
+
+	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+		i = DIV_ROUND_UP(fls((uint32_t)bt),
+					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+	else
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	stats[id].bucket[i]++;
+
+	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
+		stats[id].min_time[i] = t;
+	if (t > stats[id].max_time[i])
+		stats[id].max_time[i] = t;
+
+add_bail:
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+}
+
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	unsigned int cpu = off / MSM_PM_STAT_COUNT;
+	int id = off % MSM_PM_STAT_COUNT;
+	char *p = page;
+
+	if (count < 1024) {
+		*start = (char *) 0;
+		*eof = 0;
+		return 0;
+	}
+
+	if (cpu < num_possible_cpus()) {
+		unsigned long flags;
+		struct msm_pm_time_stats *stats;
+		int i;
+		int64_t bucket_time;
+		int64_t s;
+		uint32_t ns;
+
+		spin_lock_irqsave(&msm_pm_stats_lock, flags);
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+
+		/* Skip the disabled ones */
+		if (!stats[id].enabled) {
+			*p = '\0';
+			p++;
+			goto again;
+		}
+
+		s = stats[id].total_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		SNPRINTF(p, count,
+			"[cpu %u] %s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			cpu, stats[id].name,
+			stats[id].count,
+			s, ns);
+
+		bucket_time = stats[id].first_bucket_time;
+		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+			s = bucket_time;
+			ns = do_div(s, NSEC_PER_SEC);
+			SNPRINTF(p, count,
+				"   <%6lld.%09u: %7d (%lld-%lld)\n",
+				s, ns, stats[id].bucket[i],
+				stats[id].min_time[i],
+				stats[id].max_time[i]);
+
+			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+		}
+
+		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, stats[id].bucket[i],
+			stats[id].min_time[i],
+			stats[id].max_time[i]);
+
+again:
+		*start = (char *) 1;
+		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
+
+		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	}
+
+	return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+	unsigned long count, void *data)
+{
+	char buf[sizeof(MSM_PM_STATS_RESET)];
+	int ret;
+	unsigned long flags;
+	unsigned int cpu;
+
+	if (count < sizeof(MSM_PM_STATS_RESET)) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EFAULT;
+		goto write_proc_failed;
+	}
+
+	if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats;
+		int i;
+
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
+			memset(stats[i].bucket,
+				0, sizeof(stats[i].bucket));
+			memset(stats[i].min_time,
+				0, sizeof(stats[i].min_time));
+			memset(stats[i].max_time,
+				0, sizeof(stats[i].max_time));
+			stats[i].count = 0;
+			stats[i].total_time = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	return count;
+
+write_proc_failed:
+	return ret;
+}
+#undef MSM_PM_STATS_RESET
+
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size)
+{
+	unsigned int cpu;
+	struct proc_dir_entry *d_entry;
+	int i = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats =
+			per_cpu(msm_pm_stats, cpu).stats;
+
+		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
+		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
+		stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
+		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_RETENTION].name = "retention";
+		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
+			"idle-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
+			"idle-failed-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
+			"idle-power-collapse";
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+			"idle-failed-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
+		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
+			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
+		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
+		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		for (i = 0; i < size; i++)
+			stats[enable_stats[i]].enabled = true;
+
+	}
+
+	d_entry = create_proc_entry("msm_pm_stats",
+			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+	if (d_entry) {
+		d_entry->read_proc = msm_pm_read_proc;
+		d_entry->write_proc = msm_pm_write_proc;
+		d_entry->data = NULL;
+	}
+}
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
deleted file mode 100644
index d684a5a..0000000
--- a/arch/arm/mach-msm/pm.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/* arch/arm/mach-msm/pm.c
- *
- * MSM Power Management Routines
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/module.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-#include <linux/uaccess.h>
-#include <mach/msm_iomap.h>
-#include <mach/system.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_HAS_WAKELOCK
-#include <linux/wakelock.h>
-#endif
-
-#include "smd_private.h"
-#include "smd_rpcrouter.h"
-#include "acpuclock.h"
-#include "clock.h"
-#include "proc_comm.h"
-#include "idle.h"
-#include "irq.h"
-#include "gpio.h"
-#include "timer.h"
-#include "pm.h"
-#include "pm-boot.h"
-
-enum {
-	MSM_PM_DEBUG_SUSPEND = 1U << 0,
-	MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
-	MSM_PM_DEBUG_STATE = 1U << 2,
-	MSM_PM_DEBUG_CLOCK = 1U << 3,
-	MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
-	MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
-	MSM_PM_DEBUG_IDLE = 1U << 6,
-};
-static int msm_pm_debug_mask;
-module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
-module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
-module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
-module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME;
-module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
-#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440)
-#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108)
-#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508)
-
-enum {
-	SLEEP_LIMIT_NONE = 0,
-	SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2
-};
-
-static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
-struct smsm_interrupt_info_ext {
-	uint32_t aArm_en_mask;
-	uint32_t aArm_interrupts_pending;
-	uint32_t aArm_wakeup_reason;
-	uint32_t aArm_rpc_prog;
-	uint32_t aArm_rpc_proc;
-	char aArm_smd_port_name[20];
-	uint32_t aArm_gpio_info;
-};
-static struct msm_pm_smem_addr_t {
-	uint32_t *sleep_delay;
-	uint32_t *limit_sleep;
-	struct smsm_interrupt_info *int_info;
-	struct smsm_interrupt_info_ext *int_info_ext;
-} msm_pm_sma;
-
-static uint32_t msm_pm_max_sleep_time;
-static struct msm_pm_platform_data *msm_pm_modes;
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_SPIN,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_IDLE_SLEEP,
-	MSM_PM_STAT_IDLE_FAILED_SLEEP,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_FAILED_SUSPEND,
-	MSM_PM_STAT_NOT_IDLE,
-	MSM_PM_STAT_COUNT
-};
-
-static struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-} msm_pm_stats[MSM_PM_STAT_COUNT] = {
-	[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
-	[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
-	[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
-	[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
-	[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
-	[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
-	[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
-		"idle-failed-power-collapse",
-	[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_SUSPEND].name = "suspend",
-	[MSM_PM_STAT_SUSPEND].first_bucket_time =
-		CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
-	[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_NOT_IDLE].name = "not-idle",
-	[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-};
-
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	int i;
-	int64_t bt;
-	msm_pm_stats[id].total_time += t;
-	msm_pm_stats[id].count++;
-	bt = t;
-	do_div(bt, msm_pm_stats[id].first_bucket_time);
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-	msm_pm_stats[id].bucket[i]++;
-	if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
-		msm_pm_stats[id].min_time[i] = t;
-	if (t > msm_pm_stats[id].max_time[i])
-		msm_pm_stats[id].max_time[i] = t;
-}
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-#endif
-
-static int
-msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear,
-                  uint32_t wait_state_any_set, uint32_t wait_state_any_clear)
-{
-	int i;
-	uint32_t state;
-
-	for (i = 0; i < 2000000; i++) {
-		state = smsm_get_state(SMSM_MODEM_STATE);
-		if (((state & wait_state_all_set) == wait_state_all_set) &&
-		    ((~state & wait_state_all_clear) == wait_state_all_clear) &&
-		    (wait_state_any_set == 0 || (state & wait_state_any_set) ||
-		     wait_state_any_clear == 0 || (state & wait_state_any_clear)))
-			return 0;
-	}
-	printk(KERN_ERR "msm_pm_wait_state(%x, %x, %x, %x) failed %x\n",
-	       wait_state_all_set, wait_state_all_clear,
-	       wait_state_any_set, wait_state_any_clear, state);
-	return -ETIMEDOUT;
-}
-
-/*
- * Respond to timing out waiting for Modem
- *
- * NOTE: The function never returns.
- */
-static void msm_pm_timeout(void)
-{
-#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
-	printk(KERN_EMERG "%s(): resetting chip\n", __func__);
-	msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
-#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
-	printk(KERN_EMERG "%s(): resetting modem\n", __func__);
-	msm_proc_comm_reset_modem_now();
-#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
-	printk(KERN_EMERG "%s(): halting\n", __func__);
-#endif
-	for (;;)
-		;
-}
-
-static int msm_sleep(int sleep_mode, uint32_t sleep_delay,
-	uint32_t sleep_limit, int from_idle)
-{
-	int collapsed;
-	uint32_t enter_state;
-	uint32_t enter_wait_set = 0;
-	uint32_t enter_wait_clear = 0;
-	uint32_t exit_state;
-	uint32_t exit_wait_clear = 0;
-	uint32_t exit_wait_set = 0;
-	unsigned long pm_saved_acpu_clk_rate = 0;
-	int ret;
-	int rv = -EINTR;
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
-		printk(KERN_INFO "msm_sleep(): "
-			"mode %d delay %u limit %u idle %d\n",
-			sleep_mode, sleep_delay, sleep_limit, from_idle);
-
-	switch (sleep_mode) {
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		enter_state = SMSM_PWRC;
-		enter_wait_set = SMSM_RSA;
-		exit_state = SMSM_WFPI;
-		exit_wait_clear = SMSM_RSA;
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
-		enter_state = SMSM_PWRC_SUSPEND;
-		enter_wait_set = SMSM_RSA;
-		exit_state = SMSM_WFPI;
-		exit_wait_clear = SMSM_RSA;
-		break;
-	case MSM_PM_SLEEP_MODE_APPS_SLEEP:
-		enter_state = SMSM_SLEEP;
-		exit_state = SMSM_SLEEPEXIT;
-		exit_wait_set = SMSM_SLEEPEXIT;
-		break;
-	default:
-		enter_state = 0;
-		exit_state = 0;
-	}
-
-	if (enter_state && !(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RUN)) {
-		if ((MSM_PM_DEBUG_POWER_COLLAPSE | MSM_PM_DEBUG_SUSPEND) &
-			msm_pm_debug_mask)
-			printk(KERN_INFO "msm_sleep(): modem not ready\n");
-		rv = -EBUSY;
-		goto check_failed;
-	}
-
-	memset(msm_pm_sma.int_info, 0, sizeof(*msm_pm_sma.int_info));
-	msm_irq_enter_sleep1(!!enter_state, from_idle,
-		&msm_pm_sma.int_info->aArm_en_mask);
-	msm_gpio_enter_sleep(from_idle);
-
-	if (enter_state) {
-		if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP)
-			sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */
-
-		*msm_pm_sma.sleep_delay = sleep_delay;
-		*msm_pm_sma.limit_sleep = sleep_limit;
-		ret = smsm_change_state(SMSM_APPS_STATE, SMSM_RUN, enter_state);
-		if (ret) {
-			printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state);
-			enter_state = 0;
-			exit_state = 0;
-		}
-		ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0);
-		if (ret) {
-			printk(KERN_EMERG "msm_sleep(): power collapse entry "
-				"timed out waiting for Modem's response\n");
-			msm_pm_timeout();
-		}
-	}
-	if (msm_irq_enter_sleep2(!!enter_state, from_idle))
-		goto enter_failed;
-
-	if (enter_state) {
-		__raw_writel(0x1f, A11S_CLK_SLEEP_EN);
-		__raw_writel(1, A11S_PWRDOWN);
-
-		__raw_writel(0, A11S_STANDBY_CTL);
-		__raw_writel(0, A11RAMBACKBIAS);
-
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): enter "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-	}
-
-	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
-		pm_saved_acpu_clk_rate = acpuclk_power_collapse();
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_INFO "msm_sleep(): %ld enter power collapse"
-			       "\n", pm_saved_acpu_clk_rate);
-		if (pm_saved_acpu_clk_rate == 0)
-			goto ramp_down_failed;
-	}
-	if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) {
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-		msm_pm_boot_config_before_pc(smp_processor_id(),
-				virt_to_phys(msm_pm_collapse_exit));
-		collapsed = msm_pm_collapse();
-		msm_pm_boot_config_after_pc(smp_processor_id());
-		if (collapsed) {
-			cpu_init();
-			local_fiq_enable();
-			rv = 0;
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE)
-			printk(KERN_INFO "msm_pm_collapse(): returned %d\n",
-			       collapsed);
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-	} else {
-		msm_arch_idle();
-		rv = 0;
-	}
-
-	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_INFO "msm_sleep(): exit power collapse %ld"
-			       "\n", pm_saved_acpu_clk_rate);
-		if (acpuclk_set_rate(smp_processor_id(),
-				pm_saved_acpu_clk_rate, SETRATE_PC) < 0)
-			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
-			       "failed\n", pm_saved_acpu_clk_rate);
-	}
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-		printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, "
-		       "A11S_PWRDOWN %x, smsm_get_state %x\n",
-		       __raw_readl(A11S_CLK_SLEEP_EN),
-		       __raw_readl(A11S_PWRDOWN),
-		       smsm_get_state(SMSM_MODEM_STATE));
-ramp_down_failed:
-	msm_irq_exit_sleep1(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-enter_failed:
-	if (enter_state) {
-		__raw_writel(0x00, A11S_CLK_SLEEP_EN);
-		__raw_writel(0, A11S_PWRDOWN);
-		smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state);
-		if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) {
-			printk(KERN_EMERG "msm_sleep(): power collapse exit "
-				"timed out waiting for Modem's response\n");
-			msm_pm_timeout();
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): sleep exit "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-	}
-	msm_irq_exit_sleep2(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-	if (enter_state) {
-		smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN);
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): sleep exit "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-	}
-	msm_irq_exit_sleep3(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-	msm_gpio_exit_sleep();
-	smd_sleep_exit();
-
-check_failed:
-	return rv;
-}
-
-void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
-{
-	int64_t max_sleep_time_bs = max_sleep_time_ns;
-
-	/* Convert from ns -> BS units */
-	do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768);
-
-	if (max_sleep_time_bs > 0x6DDD000)
-		msm_pm_max_sleep_time = (uint32_t) 0x6DDD000;
-	else
-		msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs;
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
-		printk(KERN_INFO "%s: Requested %lldns (%lldbs), Giving %ubs\n",
-			__func__, max_sleep_time_ns,
-			max_sleep_time_bs,
-			msm_pm_max_sleep_time);
-}
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-void arch_idle(void)
-{
-	int ret;
-	int spin;
-	int64_t sleep_time;
-	int low_power = 0;
-	struct msm_pm_platform_data *mode;
-#ifdef CONFIG_MSM_IDLE_STATS
-	int64_t t1;
-	static int64_t t2;
-	int exit_stat;
-#endif
-	int latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int allow_sleep =
-		msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT &&
-#ifdef CONFIG_HAS_WAKELOCK
-		!has_wake_lock(WAKE_LOCK_IDLE) &&
-#endif
-		msm_irq_idle_sleep_allowed();
-
-	if (!atomic_read(&msm_pm_init_done))
-		return;
-
-	sleep_time = msm_timer_enter_idle();
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	t1 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
-	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time);
-#endif
-
-	mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE];
-	if (mode->latency >= latency_qos)
-		sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
-
-	mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN];
-	if (mode->latency >= latency_qos)
-		allow_sleep = false;
-
-	mode = &msm_pm_modes[
-		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT];
-	if (mode->latency >= latency_qos) {
-		/* no time even for SWFI */
-		while (!msm_irq_pending())
-			udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
-		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-		goto abort_idle;
-	}
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)
-		printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n",
-		       sleep_time, allow_sleep);
-	spin = msm_pm_idle_spin_time >> 10;
-	while (spin-- > 0) {
-		if (msm_irq_pending()) {
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-			goto abort_idle;
-		}
-		udelay(1);
-	}
-	if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) {
-		unsigned long saved_rate;
-		saved_rate = acpuclk_wait_for_irq();
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n",
-				saved_rate);
-		if (saved_rate) {
-			msm_arch_idle();
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
-		} else {
-			while (!msm_irq_pending())
-				udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n",
-				saved_rate);
-		if (saved_rate
-		    && acpuclk_set_rate(smp_processor_id(),
-				saved_rate, SETRATE_SWFI) < 0)
-			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
-			       "failed\n", saved_rate);
-	} else {
-		low_power = 1;
-		do_div(sleep_time, NSEC_PER_SEC / 32768);
-		if (sleep_time > 0x6DDD000) {
-			printk("sleep_time too big %lld\n", sleep_time);
-			sleep_time = 0x6DDD000;
-		}
-		ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time,
-			sleep_limit, 1);
-#ifdef CONFIG_MSM_IDLE_STATS
-		switch (msm_pm_idle_sleep_mode) {
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (ret)
-				exit_stat =
-					MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
-			else {
-				exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-				msm_pm_sleep_limit = sleep_limit;
-			}
-			break;
-		case MSM_PM_SLEEP_MODE_APPS_SLEEP:
-			if (ret)
-				exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
-			else
-				exit_stat = MSM_PM_STAT_IDLE_SLEEP;
-			break;
-		default:
-			exit_stat = MSM_PM_STAT_IDLE_WFI;
-		}
-#endif
-	}
-abort_idle:
-	msm_timer_exit_idle(low_power);
-#ifdef CONFIG_MSM_IDLE_STATS
-	t2 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(exit_stat, t2 - t1);
-#endif
-}
-
-static int msm_pm_enter(suspend_state_t state)
-{
-	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int ret;
-#ifdef CONFIG_MSM_IDLE_STATS
-	int64_t period = 0;
-	int64_t time = 0;
-
-	time = msm_timer_get_sclk_time(&period);
-#endif
-
-	clock_debug_print_enabled();
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-	if (msm_pm_sleep_time_override > 0) {
-		int64_t ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
-		msm_pm_set_max_sleep_time(ns);
-		msm_pm_sleep_time_override = 0;
-	}
-#endif
-
-	ret = msm_sleep(msm_pm_sleep_mode,
-		msm_pm_max_sleep_time, sleep_limit, 0);
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	if (msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND ||
-		msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
-		enum msm_pm_time_stats_id id;
-		int64_t end_time;
-
-		if (ret)
-			id = MSM_PM_STAT_FAILED_SUSPEND;
-		else {
-			id = MSM_PM_STAT_SUSPEND;
-			msm_pm_sleep_limit = sleep_limit;
-		}
-
-		if (time != 0) {
-			end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
-
-		msm_pm_add_stat(id, time);
-	}
-#endif
-
-	return 0;
-}
-
-static struct platform_suspend_ops msm_pm_ops = {
-	.enter		= msm_pm_enter,
-	.valid		= suspend_valid_only_mem,
-};
-
-static uint32_t restart_reason = 0x776655AA;
-
-static void msm_pm_power_off(void)
-{
-	msm_rpcrouter_close();
-	msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
-	for (;;) ;
-}
-
-static void msm_pm_restart(char str, const char *cmd)
-{
-	msm_rpcrouter_close();
-	msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
-
-	for (;;) ;
-}
-
-static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
-{
-	if((code == SYS_RESTART) && _cmd) {
-		char *cmd = _cmd;
-		if (!strcmp(cmd, "bootloader")) {
-			restart_reason = 0x77665500;
-		} else if (!strcmp(cmd, "recovery")) {
-			restart_reason = 0x77665502;
-		} else if (!strcmp(cmd, "eraseflash")) {
-			restart_reason = 0x776655EF;
-		} else if (!strncmp(cmd, "oem-", 4)) {
-			unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
-			restart_reason = 0x6f656d00 | code;
-		} else {
-			restart_reason = 0x77665501;
-		}
-	}
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block msm_reboot_notifier = {
-	.notifier_call = msm_reboot_call,
-};
-
-#ifdef CONFIG_MSM_IDLE_STATS
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc(
-	char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	int i;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (!off) {
-		SNPRINTF(p, count, "Last power collapse voted ");
-		if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE)
-			SNPRINTF(p, count, "for TCXO shutdown\n\n");
-		else
-			SNPRINTF(p, count, "against TCXO shutdown\n\n");
-
-		*start = (char *) 1;
-		*eof = 0;
-	} else if (--off < ARRAY_SIZE(msm_pm_stats)) {
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		s = msm_pm_stats[off].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"%s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			msm_pm_stats[off].name,
-			msm_pm_stats[off].count,
-			s, ns);
-
-		bucket_time = msm_pm_stats[off].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, msm_pm_stats[off].bucket[i],
-				msm_pm_stats[off].min_time[i],
-				msm_pm_stats[off].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, msm_pm_stats[off].bucket[i],
-			msm_pm_stats[off].min_time[i],
-			msm_pm_stats[off].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	int i;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	local_irq_save(flags);
-	for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
-		memset(msm_pm_stats[i].bucket,
-			0, sizeof(msm_pm_stats[i].bucket));
-		memset(msm_pm_stats[i].min_time,
-			0, sizeof(msm_pm_stats[i].min_time));
-		memset(msm_pm_stats[i].max_time,
-			0, sizeof(msm_pm_stats[i].max_time));
-		msm_pm_stats[i].count = 0;
-		msm_pm_stats[i].total_time = 0;
-	}
-
-	msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-	local_irq_restore(flags);
-
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-static int __init msm_pm_init(void)
-{
-#ifdef CONFIG_MSM_IDLE_STATS
-	struct proc_dir_entry *d_entry;
-#endif
-	int ret;
-
-	pm_power_off = msm_pm_power_off;
-	arm_pm_restart = msm_pm_restart;
-	msm_pm_max_sleep_time = 0;
-
-	register_reboot_notifier(&msm_reboot_notifier);
-
-	msm_pm_sma.sleep_delay = smem_alloc(SMEM_SMSM_SLEEP_DELAY,
-		sizeof(*msm_pm_sma.sleep_delay));
-	if (msm_pm_sma.sleep_delay == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get SLEEP_DELAY\n");
-		return -ENODEV;
-	}
-
-	msm_pm_sma.limit_sleep = smem_alloc(SMEM_SMSM_LIMIT_SLEEP,
-		sizeof(*msm_pm_sma.limit_sleep));
-	if (msm_pm_sma.limit_sleep == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get LIMIT_SLEEP\n");
-		return -ENODEV;
-	}
-
-	msm_pm_sma.int_info_ext = smem_alloc(SMEM_SMSM_INT_INFO,
-		sizeof(*msm_pm_sma.int_info_ext));
-
-	if (msm_pm_sma.int_info_ext)
-		msm_pm_sma.int_info = (struct smsm_interrupt_info *)
-			msm_pm_sma.int_info_ext;
-	else
-		msm_pm_sma.int_info = smem_alloc(SMEM_SMSM_INT_INFO,
-			sizeof(*msm_pm_sma.int_info));
-
-	if (msm_pm_sma.int_info == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get INT_INFO\n");
-		return -ENODEV;
-	}
-
-	ret = msm_timer_init_time_sync(msm_pm_timeout);
-	if (ret)
-		return ret;
-
-	BUG_ON(msm_pm_modes == NULL);
-
-	atomic_set(&msm_pm_init_done, 1);
-	suspend_set_ops(&msm_pm_ops);
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif
-
-	return 0;
-}
-
-void __init msm_pm_set_platform_data(
-	struct msm_pm_platform_data *data, int count)
-{
-	BUG_ON(MSM_PM_SLEEP_MODE_NR != count);
-	msm_pm_modes = data;
-}
-
-late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 09494a0..ce0d747 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -84,6 +84,8 @@
 
 void __init msm_pm_init_sleep_status_data(
 		struct msm_pm_sleep_status_data *sleep_data);
+
+
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
 int msm_pm_wait_cpu_shutdown(unsigned int cpu);
@@ -99,4 +101,29 @@
 #else
 static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
 #endif
+
+enum msm_pm_time_stats_id {
+	MSM_PM_STAT_REQUESTED_IDLE = 0,
+	MSM_PM_STAT_IDLE_SPIN,
+	MSM_PM_STAT_IDLE_WFI,
+	MSM_PM_STAT_RETENTION,
+	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+	MSM_PM_STAT_SUSPEND,
+	MSM_PM_STAT_FAILED_SUSPEND,
+	MSM_PM_STAT_NOT_IDLE,
+	MSM_PM_STAT_COUNT
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size);
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t);
+#else
+static inline void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats,
+		int size) {}
+static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
+#endif
+
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 6d8f2a2..426d6e6 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -23,10 +23,8 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
 #include <linux/suspend.h>
 #include <linux/reboot.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/tick.h>
 #include <linux/memory.h>
@@ -425,6 +423,7 @@
 	SLEEP_LIMIT_MASK = 0x03,
 };
 
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
 enum {
 	SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
@@ -765,238 +764,6 @@
 
 
 /******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_SPIN,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_FAILED_SUSPEND,
-	MSM_PM_STAT_NOT_IDLE,
-	MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
-	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(
-		struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	unsigned long flags;
-	struct msm_pm_time_stats *stats;
-	int i;
-	int64_t bt;
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	stats = __get_cpu_var(msm_pm_stats).stats;
-
-	stats[id].total_time += t;
-	stats[id].count++;
-
-	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
-
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	stats[id].bucket[i]++;
-
-	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
-		stats[id].min_time[i] = t;
-	if (t > stats[id].max_time[i])
-		stats[id].max_time[i] = t;
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	unsigned int cpu = off / MSM_PM_STAT_COUNT;
-	int id = off % MSM_PM_STAT_COUNT;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (!off) {
-		SNPRINTF(p, count, "Last power collapse voted ");
-		if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
-			SLEEP_LIMIT_NONE)
-			SNPRINTF(p, count, "for TCXO shutdown\n\n");
-		else
-			SNPRINTF(p, count, "against TCXO shutdown\n\n");
-	}
-
-	if (cpu < num_possible_cpus()) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-
-		s = stats[id].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"[cpu %u] %s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			cpu, stats[id].name,
-			stats[id].count,
-			s, ns);
-
-		bucket_time = stats[id].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, stats[id].bucket[i],
-			stats[id].min_time[i],
-			stats[id].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	unsigned int cpu;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats;
-		int i;
-
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
-			memset(stats[i].bucket,
-				0, sizeof(stats[i].bucket));
-			memset(stats[i].min_time,
-				0, sizeof(stats[i].min_time));
-			memset(stats[i].max_time,
-				0, sizeof(stats[i].max_time));
-			stats[i].count = 0;
-			stats[i].total_time = 0;
-		}
-	}
-	msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
  * Shared Memory Bits
  *****************************************************************************/
 
@@ -1187,7 +954,10 @@
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	l2cc_suspend();
+	if (!cpu_is_msm8625())
+		l2cc_suspend();
+	else
+		apps_power_collapse = 1;
 #endif
 
 	collapsed = msm_pm_collapse();
@@ -1214,7 +984,10 @@
 	}
 
 #ifdef CONFIG_CACHE_L2X0
-	l2cc_resume();
+	if (!cpu_is_msm8625())
+		l2cc_resume();
+	else
+		apps_power_collapse = 0;
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1501,6 +1274,30 @@
 	return 0;
 }
 
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+		return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+			} else
+				time = 0;
+		}
+	return time;
+}
 
 /******************************************************************************
  * External Idle/Suspend Functions
@@ -1519,28 +1316,22 @@
 	int ret;
 	int i;
 	unsigned int cpu;
-
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t t1;
 	static DEFINE_PER_CPU(int64_t, t2);
 	int exit_stat;
- #endif
 
 	if (!atomic_read(&msm_pm_init_done))
 		return;
 
 	cpu = smp_processor_id();
-
 	latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	/* get the next timer expiration */
 	timer_expiration = ktime_to_ns(tick_nohz_get_sleep_length());
 
-#ifdef CONFIG_MSM_IDLE_STATS
 	t1 = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - __get_cpu_var(t2));
 	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
 	exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++)
 		allow[i] = true;
@@ -1621,46 +1412,34 @@
 		low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
 		msm_timer_exit_idle(low_power);
 
-#ifdef CONFIG_MSM_IDLE_STATS
 		if (ret)
 			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
 		else {
 			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 			msm_pm_sleep_limit = sleep_limit;
 		}
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		ret = msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ?
 			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
 			MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
 			while (!msm_pm_irq_extns->irq_pending())
 				udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		msm_pm_swfi(false);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
 	} else {
 		while (!msm_pm_irq_extns->irq_pending())
 			udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
 	}
 
-#ifdef CONFIG_MSM_IDLE_STATS
 	__get_cpu_var(t2) = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
-#endif
 }
 
 /*
@@ -1681,10 +1460,8 @@
 	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
 	int ret = -EPERM;
 	int i;
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
 	int64_t time = 0;
-#endif
 
 	/* Must executed by CORE0 */
 	if (smp_processor_id()) {
@@ -1692,9 +1469,7 @@
 		goto suspend_exit;
 	}
 
-#ifdef CONFIG_MSM_IDLE_STATS
-	time = msm_timer_get_sclk_time(&period);
-#endif
+	time = msm_pm_timer_enter_suspend(&period);
 
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
 		"%s(): sleep limit %u\n", __func__, sleep_limit);
@@ -1711,10 +1486,7 @@
 
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
-#ifdef CONFIG_MSM_IDLE_STATS
 		enum msm_pm_time_stats_id id;
-		int64_t end_time;
-#endif
 
 		clock_debug_print_enabled();
 
@@ -1744,7 +1516,6 @@
 		ret = msm_pm_power_collapse(
 			false, msm_pm_max_sleep_time, sleep_limit);
 
-#ifdef CONFIG_MSM_IDLE_STATS
 		if (ret)
 			id = MSM_PM_STAT_FAILED_SUSPEND;
 		else {
@@ -1752,18 +1523,8 @@
 			msm_pm_sleep_limit = sleep_limit;
 		}
 
-		if (time != 0) {
-			end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
-
+		time = msm_pm_timer_exit_suspend(time, period);
 		msm_pm_add_stat(id, time);
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		ret = msm_pm_power_collapse_standalone(false);
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
@@ -1873,12 +1634,21 @@
  */
 static int __init msm_pm_init(void)
 {
-#ifdef CONFIG_MSM_IDLE_STATS
-	struct proc_dir_entry *d_entry;
-	unsigned int cpu;
-#endif
 	int ret;
 	int val;
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_REQUESTED_IDLE,
+		MSM_PM_STAT_IDLE_SPIN,
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+		MSM_PM_STAT_FAILED_SUSPEND,
+		MSM_PM_STAT_NOT_IDLE,
+	};
+
 #ifdef CONFIG_CPU_V7
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
@@ -1956,6 +1726,8 @@
 		 */
 		val = 0x00030002;
 		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+
+		l2x0_base_addr = MSM_L2CC_BASE;
 	}
 
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
@@ -1972,70 +1744,9 @@
 	suspend_set_ops(&msm_pm_ops);
 
 	msm_pm_mode_sysfs_add();
-#ifdef CONFIG_MSM_IDLE_STATS
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats =
-			per_cpu(msm_pm_stats, cpu).stats;
-
-		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
-		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
-		stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
-		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
-			"idle-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
-			"idle-failed-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
-			"idle-power-collapse";
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
-			"idle-failed-power-collapse";
-		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
-		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
-			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
-		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
-		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-	}
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
 
 	atomic_set(&msm_pm_init_done, 1);
-
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif
-
 	return 0;
 }
 
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 34640c3..7b7549a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -194,6 +194,7 @@
 				return -ENOMEM;
 			}
 		}
+		driver->data_ready[i] = 0x0;
 		driver->data_ready[i] |= MSG_MASKS_TYPE;
 		driver->data_ready[i] |= EVENT_MASKS_TYPE;
 		driver->data_ready[i] |= LOG_MASKS_TYPE;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a7a4a2a..4ac2643 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1139,8 +1139,17 @@
 		}
 	}
 #if defined(CONFIG_DIAG_OVER_USB)
+	/* Check for the command/respond msg for the maximum packet length */
+	if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
+		(*(uint16_t *)(buf+2) == 0x0055)) {
+		for (i = 0; i < 4; i++)
+			*(driver->apps_rsp_buf+i) = *(buf+i);
+		*(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
+		ENCODE_RSP_AND_SEND(7);
+		return 0;
+	}
 	/* Check for Apps Only & get event mask request */
-	if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+	else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
 		driver->apps_rsp_buf[0] = 0x81;
 		driver->apps_rsp_buf[1] = 0x0;
 		*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 7f57fe6..052b778 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -243,7 +243,8 @@
 				cp_heap->total_size -
 				cp_heap->allocated_bytes, size);
 
-		if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+		if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+		    cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
 			if (fmem_set_state(FMEM_T_STATE) != 0)
 				pr_err("%s: unable to transition heap to T-state\n",
 					__func__);
@@ -293,7 +294,8 @@
 	mutex_lock(&cp_heap->lock);
 	cp_heap->allocated_bytes -= size;
 
-	if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+	if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+	    cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
 		if (fmem_set_state(FMEM_T_STATE) != 0)
 			pr_err("%s: unable to transition heap to T-state\n",
 				__func__);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 96390ac..2f503ae 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -21,6 +21,7 @@
 #include "kgsl_pwrscale.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_sharedmem.h"
+#include "kgsl_iommu.h"
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
@@ -158,7 +159,7 @@
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_256K },
 	/* A3XX doesn't use the pix_shader_start */
-	{ ADRENO_REV_A320, 3, 2, 0, 0,
+	{ ADRENO_REV_A320, 3, 2, 0, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_512K },
 
@@ -243,7 +244,144 @@
 	return result;
 }
 
-static void adreno_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
+					uint32_t flags)
+{
+	unsigned int pt_val, reg_pt_val;
+	unsigned int link[200];
+	unsigned int *cmds = &link[0];
+	int sizedwords = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_memdesc **reg_map_desc;
+	void *reg_map_array;
+	int num_iommu_units, i;
+
+	if (!adreno_dev->drawctxt_active)
+		return kgsl_mmu_device_setstate(&device->mmu, flags);
+	num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
+							&reg_map_array);
+	reg_map_desc = reg_map_array;
+
+	if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+		goto done;
+
+	if (adreno_is_a225(adreno_dev))
+		cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
+					device->mmu.setstate_memory.gpuaddr +
+					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	else
+		cmds += adreno_add_bank_change_cmds(cmds,
+					KGSL_IOMMU_CONTEXT_USER,
+					device->mmu.setstate_memory.gpuaddr +
+					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+		pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+		/*
+		 * We need to perfrom the following operations for all
+		 * IOMMU units
+		 */
+		for (i = 0; i < num_iommu_units; i++) {
+			reg_pt_val = (pt_val &
+				(KGSL_IOMMU_TTBR0_PA_MASK <<
+				KGSL_IOMMU_TTBR0_PA_SHIFT)) +
+				kgsl_mmu_get_pt_lsb(&device->mmu, i,
+					KGSL_IOMMU_CONTEXT_USER);
+			/*
+			 * Set address of the new pagetable by writng to IOMMU
+			 * TTBR0 register
+			 */
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+			*cmds++ = reg_pt_val;
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+
+			/*
+			 * Read back the ttbr0 register as a barrier to ensure
+			 * above writes have completed
+			 */
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+				reg_pt_val,
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+			/* set the asid */
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR;
+			*cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+
+			/* Read back asid to ensure above write completes */
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR,
+				kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+		}
+		/* invalidate all base pointers */
+		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
+		*cmds++ = 0x7fff;
+
+		if (flags & KGSL_MMUFLAGS_TLBFLUSH)
+			cmds += __adreno_add_idle_indirect_cmds(cmds,
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	}
+	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+		/*
+		 * tlb flush based on asid, no need to flush entire tlb
+		 */
+		for (i = 0; i < num_iommu_units; i++) {
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = (reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) +
+				KGSL_IOMMU_CTX_TLBIASID);
+			*cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) +
+				KGSL_IOMMU_CONTEXTIDR,
+				kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+		}
+	}
+
+	if (adreno_is_a225(adreno_dev))
+		cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
+			reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
+			device->mmu.setstate_memory.gpuaddr +
+			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	else
+		cmds += adreno_add_bank_change_cmds(cmds,
+			KGSL_IOMMU_CONTEXT_PRIV,
+			device->mmu.setstate_memory.gpuaddr +
+			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+	sizedwords += (cmds - &link[0]);
+	if (sizedwords)
+		adreno_ringbuffer_issuecmds(device,
+			KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+done:
+	if (num_iommu_units)
+		kfree(reg_map_array);
+}
+
+static void adreno_gpummu_setstate(struct kgsl_device *device,
 					uint32_t flags)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -253,16 +391,6 @@
 	unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
 
 	/*
-	 * A3XX doesn't support the fast path (the registers don't even exist)
-	 * so just bail out early
-	 */
-
-	if (adreno_is_a3xx(adreno_dev)) {
-		kgsl_mmu_device_setstate(&device->mmu, flags);
-		return;
-	}
-
-	/*
 	 * If possible, then set the state via the command stream to avoid
 	 * a CPU idle.  Otherwise, use the default setstate which uses register
 	 * writes For CFF dump we must idle and use the registers so that it is
@@ -348,6 +476,16 @@
 	}
 }
 
+static void adreno_setstate(struct kgsl_device *device,
+			uint32_t flags)
+{
+	/* call the mmu specific handler */
+	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype())
+		return adreno_gpummu_setstate(device, flags);
+	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		return adreno_iommu_setstate(device, flags);
+}
+
 static unsigned int
 a3xx_getchipid(struct kgsl_device *device)
 {
@@ -362,10 +500,22 @@
 	 */
 
 	if (cpu_is_apq8064()) {
+		unsigned int version = socinfo_get_version();
+
 		/* A320 */
 		majorid = 2;
 		minorid = 0;
-		patchid = 0;
+
+		/*
+		 * V1.1 has some GPU work arounds that we need to communicate
+		 * up to user space via the patchid
+		 */
+
+		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+			(SOCINFO_VERSION_MINOR(version) == 1))
+			patchid = 1;
+		else
+			patchid = 0;
 	} else if (cpu_is_msm8930()) {
 		/* A305 */
 		majorid = 0;
@@ -1129,16 +1279,12 @@
 static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
 {
 	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
-
 	if (k_ctxt != NULL) {
 		struct adreno_context *a_ctxt = k_ctxt->devctxt;
-		/*
-		 * if the context was not created with per context timestamp
-		 * support, we must use the global timestamp since issueibcmds
-		 * will be returning that one.
-		 */
-		if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
-			context_id = a_ctxt->id;
+		if (k_ctxt->id == KGSL_CONTEXT_INVALID || a_ctxt == NULL)
+			context_id = KGSL_CONTEXT_INVALID;
+		else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			context_id = k_ctxt->id;
 	}
 
 	return context_id;
@@ -1149,11 +1295,22 @@
 {
 	int status;
 	unsigned int ref_ts, enableflag;
-	unsigned int context_id = _get_context_id(context);
+	unsigned int context_id;
+
+	mutex_lock(&device->mutex);
+	context_id = _get_context_id(context);
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		status = -EINVAL;
+		goto unlock;
+	}
 
 	status = kgsl_check_timestamp(device, context, timestamp);
 	if (!status) {
-		mutex_lock(&device->mutex);
 		kgsl_sharedmem_readl(&device->memstore, &enableflag,
 			KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
 		mb();
@@ -1187,8 +1344,9 @@
 			adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 				&cmds[0], 2);
 		}
-		mutex_unlock(&device->mutex);
 	}
+unlock:
+	mutex_unlock(&device->mutex);
 
 	return status;
 }
@@ -1247,6 +1405,15 @@
 	msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
 	msecs_part = (msecs - msecs_first + 3) / 4;
 	for (retries = 0; retries < 5; retries++) {
+		/*
+		 * If the context ID is invalid, we are in a race with
+		 * the context being destroyed by userspace so bail.
+		 */
+		if (context_id == KGSL_CONTEXT_INVALID) {
+			KGSL_DRV_WARN(device, "context was detached");
+			status = -EINVAL;
+			goto done;
+		}
 		if (kgsl_check_timestamp(device, context, timestamp)) {
 			/* if the timestamp happens while we're not
 			 * waiting, there's a chance that an interrupt
@@ -1308,6 +1475,14 @@
 	unsigned int timestamp = 0;
 	unsigned int context_id = _get_context_id(context);
 
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		return timestamp;
+	}
 	switch (type) {
 	case KGSL_TIMESTAMP_QUEUED: {
 		struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a7ea20c..4ce56a4 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -16,6 +16,7 @@
 #include "kgsl_device.h"
 #include "adreno_drawctxt.h"
 #include "adreno_ringbuffer.h"
+#include "kgsl_iommu.h"
 
 #define DEVICE_3D_NAME "kgsl-3d"
 #define DEVICE_3D0_NAME "kgsl-3d0"
@@ -223,4 +224,70 @@
 	return (ilog2(size) - 5) << 29;
 }
 
+static inline int __adreno_add_idle_indirect_cmds(unsigned int *cmds,
+						unsigned int nop_gpuaddr)
+{
+	/* Adding an indirect buffer ensures that the prefetch stalls until
+	 * the commands in indirect buffer have completed. We need to stall
+	 * prefetch with a nop indirect buffer when updating pagetables
+	 * because it provides stabler synchronization */
+	*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+	*cmds++ = nop_gpuaddr;
+	*cmds++ = 2;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	return 5;
+}
+
+static inline int adreno_add_change_mh_phys_limit_cmds(unsigned int *cmds,
+						unsigned int new_phys_limit,
+						unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	*cmds++ = cp_type0_packet(MH_MMU_MPU_END, 1);
+	*cmds++ = new_phys_limit;
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
+static inline int adreno_add_bank_change_cmds(unsigned int *cmds,
+					int cur_ctx_bank,
+					unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	*cmds++ = cp_type0_packet(REG_CP_STATE_DEBUG_INDEX, 1);
+	*cmds++ = (cur_ctx_bank ? 0 : 0x20);
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
+/*
+ * adreno_read_cmds - Add pm4 packets to perform read
+ * @device - Pointer to device structure
+ * @cmds - Pointer to memory where read commands need to be added
+ * @addr - gpu address of the read
+ * @val - The GPU will wait until the data at address addr becomes
+ * equal to value
+ */
+static inline int adreno_add_read_cmds(struct kgsl_device *device,
+				unsigned int *cmds, unsigned int addr,
+				unsigned int val, unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+	/* MEM SPACE = memory, FUNCTION = equals */
+	*cmds++ = 0x13;
+	*cmds++ = addr;
+	*cmds++ = val;
+	*cmds++ = 0xFFFFFFFF;
+	*cmds++ = 0xFFFFFFFF;
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index eb936f8..ae846da 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1848,8 +1848,13 @@
 
 	/* NQ and External Memory Swap */
 	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
-	/* Protected mode error checking */
-	GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
+	/* Protected mode error checking
+	 * If iommu is used then protection needs to be turned off
+	 * to enable context bank switching */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		GSL_RB_WRITE(cmds, cmds_gpu, 0);
+	else
+		GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
 	/* Disable header dumping and Header dump address */
 	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
 	/* Header dump size */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index adf2772..cf09f52 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -363,28 +363,54 @@
 		return NULL;
 	}
 
+	kref_init(&context->refcount);
 	context->id = id;
 	context->dev_priv = dev_priv;
 
 	return context;
 }
 
-static void
-kgsl_destroy_context(struct kgsl_device_private *dev_priv,
-		     struct kgsl_context *context)
+/**
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
+ *
+ * This is called when a context becomes unusable, because userspace
+ * has requested for it to be destroyed. The context itself may
+ * exist a bit longer until its reference count goes to zero.
+ * Other code referencing the context can detect that it has been
+ * detached because the context id will be set to KGSL_CONTEXT_INVALID.
+ */
+void
+kgsl_context_detach(struct kgsl_context *context)
 {
 	int id;
-
+	struct kgsl_device *device;
 	if (context == NULL)
 		return;
-
-	/* Fire a bug if the devctxt hasn't been freed */
-	BUG_ON(context->devctxt);
-
+	device = context->dev_priv->device;
 	id = context->id;
-	kfree(context);
 
-	idr_remove(&dev_priv->device->context_idr, id);
+	if (device->ftbl->drawctxt_destroy)
+		device->ftbl->drawctxt_destroy(device, context);
+	/*device specific drawctxt_destroy MUST clean up devctxt */
+	BUG_ON(context->devctxt);
+	/*
+	 * Cancel events after the device-specific context is
+	 * destroyed, to avoid possibly freeing memory while
+	 * it is still in use by the GPU.
+	 */
+	kgsl_cancel_events_ctxt(device, context);
+	idr_remove(&device->context_idr, id);
+	context->id = KGSL_CONTEXT_INVALID;
+	kgsl_context_put(context);
+}
+
+void
+kgsl_context_destroy(struct kref *kref)
+{
+	struct kgsl_context *context = container_of(kref, struct kgsl_context,
+						    refcount);
+	kfree(context);
 }
 
 void kgsl_timestamp_expired(struct work_struct *work)
@@ -758,23 +784,23 @@
 	mutex_lock(&device->mutex);
 	kgsl_check_suspended(device);
 
-	/* clean up any to-be-freed entries that belong to this
-	 * process and this device
-	 */
-	kgsl_cancel_events(device, dev_priv);
-
 	while (1) {
 		context = idr_get_next(&device->context_idr, &next);
 		if (context == NULL)
 			break;
 
-		if (context->dev_priv == dev_priv) {
-			device->ftbl->drawctxt_destroy(device, context);
-			kgsl_destroy_context(dev_priv, context);
-		}
+		if (context->dev_priv == dev_priv)
+			kgsl_context_detach(context);
 
 		next = next + 1;
 	}
+	/*
+	 * Clean up any to-be-freed entries that belong to this
+	 * process and this device. This is done after the context
+	 * are destroyed to avoid possibly freeing memory while
+	 * it is still in use by the GPU.
+	 */
+	kgsl_cancel_events(device, dev_priv);
 
 	device->open_count--;
 	if (device->open_count == 0) {
@@ -1034,6 +1060,7 @@
 {
 	struct kgsl_device_waittimestamp_ctxtid *param = data;
 	struct kgsl_context *context;
+	int result;
 
 	context = kgsl_find_context(dev_priv, param->context_id);
 	if (context == NULL) {
@@ -1041,9 +1068,16 @@
 			param->context_id);
 		return -EINVAL;
 	}
-
-	return _device_waittimestamp(dev_priv, context,
+	/*
+	 * A reference count is needed here, because waittimestamp may
+	 * block with the device mutex unlocked and userspace could
+	 * request for the context to be destroyed during that time.
+	 */
+	kgsl_context_get(context);
+	result = _device_waittimestamp(dev_priv, context,
 			param->timestamp, param->timeout);
+	kgsl_context_put(context);
+	return result;
 }
 
 static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
@@ -1261,7 +1295,7 @@
 	param->drawctxt_id = context->id;
 done:
 	if (result && context)
-		kgsl_destroy_context(dev_priv, context);
+		kgsl_context_detach(context);
 
 	return result;
 }
@@ -1280,14 +1314,7 @@
 		goto done;
 	}
 
-	kgsl_cancel_events_ctxt(dev_priv->device, context);
-
-	if (dev_priv->device->ftbl->drawctxt_destroy)
-		dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
-			context);
-
-	kgsl_destroy_context(dev_priv, context);
-
+	kgsl_context_detach(context);
 done:
 	return result;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0964458..5b6522a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -220,6 +220,7 @@
 	.last_expired_ctxt_id = KGSL_CONTEXT_INVALID
 
 struct kgsl_context {
+	struct kref refcount;
 	uint32_t id;
 
 	/* Pointer to the owning device instance */
@@ -380,4 +381,32 @@
 	return pdev->dev.platform_data;
 }
 
+/**
+ * kgsl_context_get - Get context reference count
+ * @context
+ *
+ * Asynchronous code that holds a pointer to a context
+ * must hold a reference count on it. The kgsl device
+ * mutex must be held while the context reference count
+ * is changed.
+ */
+static inline void
+kgsl_context_get(struct kgsl_context *context)
+{
+	kref_get(&context->refcount);
+}
+
+void kgsl_context_destroy(struct kref *kref);
+
+/**
+ * kgsl_context_put - Release context reference count
+ * @context
+ *
+ */
+static inline void
+kgsl_context_put(struct kgsl_context *context)
+{
+	kref_put(&context->refcount, kgsl_context_destroy);
+}
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index c2d46e2..fb65565 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -23,6 +23,8 @@
 #include "kgsl_mmu.h"
 #include "kgsl_sharedmem.h"
 #include "kgsl_iommu.h"
+#include "adreno_pm4types.h"
+#include "adreno.h"
 
 /*
  * kgsl_iommu_disable_clk - Disable iommu clocks
@@ -499,6 +501,12 @@
 	if (status)
 		goto done;
 
+	/* A nop is required in an indirect buffer when switching
+	 * pagetables in-stream */
+	kgsl_sharedmem_writel(&mmu->setstate_memory,
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET,
+				cp_nop_packet(1));
+
 	dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
 			__func__);
 done:
@@ -580,16 +588,26 @@
 		if (status)
 			return -ENOMEM;
 	}
-	kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+	/* We use the GPU MMU to control access to IOMMU registers on a225,
+	 * hence we still keep the MMU active on a225 */
+	if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
+		struct kgsl_mh *mh = &(mmu->device->mh);
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
+		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
+			mh->mpu_base +
+			iommu->iommu_units
+				[iommu->unit_count - 1].reg_map.gpuaddr -
+				PAGE_SIZE);
+	} else {
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+	}
 
 	mmu->hwpagetable = mmu->defaultpagetable;
 
 	status = kgsl_attach_pagetable_iommu_domain(mmu);
-	if (!status) {
-		mmu->flags |= KGSL_FLAGS_STARTED;
-	} else {
-		kgsl_detach_pagetable_iommu_domain(mmu);
+	if (status) {
 		mmu->hwpagetable = NULL;
+		goto done;
 	}
 	status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 	if (status) {
@@ -621,6 +639,7 @@
 				CONTEXTIDR);
 
 	kgsl_iommu_disable_clk(mmu);
+	mmu->flags |= KGSL_FLAGS_STARTED;
 
 done:
 	if (status) {
@@ -701,6 +720,7 @@
 	 */
 
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 		/* detach iommu attachment */
 		kgsl_detach_pagetable_iommu_domain(mmu);
 		mmu->hwpagetable = NULL;
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index c2e84a6..d4de656 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -55,6 +55,9 @@
 		(pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK <<			\
 				KGSL_IOMMU_TTBR0_PA_SHIFT))
 
+/* offset at which a nop command is placed in setstate_memory */
+#define KGSL_IOMMU_SETSTATE_NOP_OFFSET	1024
+
 /*
  * struct kgsl_iommu_device - Structure holding data about iommu contexts
  * @dev: Device pointer to iommu context
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 663ba0f..b882807 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -545,8 +545,7 @@
 	struct kgsl_device *device = mmu->device;
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return;
-	else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
-						kgsl_mmu_type))
+	else if (device->ftbl->setstate)
 		device->ftbl->setstate(device, flags);
 	else if (mmu->mmu_ops->mmu_device_setstate)
 		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index df4a64b..2db327b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -261,4 +261,37 @@
 		return 0;
 }
 
+static inline int kgsl_mmu_get_pt_lsb(struct kgsl_mmu *mmu,
+					unsigned int unit_id,
+					enum kgsl_iommu_context_id ctx_id)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_lsb)
+		return mmu->mmu_ops->mmu_get_pt_lsb(mmu, unit_id, ctx_id);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_hwpagetable_asid)
+		return mmu->mmu_ops->mmu_get_hwpagetable_asid(mmu);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_enable_clk(struct kgsl_mmu *mmu,
+					int ctx_id)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_enable_clk)
+		return mmu->mmu_ops->mmu_enable_clk(mmu, ctx_id);
+	else
+		return 0;
+}
+
+static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
+		mmu->mmu_ops->mmu_disable_clk(mmu);
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 3a29d71..2aaefba 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -706,6 +706,7 @@
 		}
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
+		kgsl_mmu_disable_clk(&device->mmu);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
 		if (device->idle_wakelock.name)
 			wake_unlock(&device->idle_wakelock);
@@ -749,6 +750,7 @@
 				gpu_freq);
 		_sleep_accounting(device);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+		kgsl_mmu_disable_clk(&device->mmu);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
 		wake_unlock(&device->idle_wakelock);
 		pm_qos_update_request(&device->pm_qos_req_dma,
@@ -888,6 +890,7 @@
 	/* Order pwrrail/clk sequence based upon platform */
 	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
 	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+	kgsl_mmu_disable_clk(&device->mmu);
 	kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_disable);
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index fa42c2c..ece7b0f 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -57,6 +57,7 @@
 #define WLED_OVP_VAL_BIT_SHFT		0x04
 #define WLED_BOOST_LIMIT_MASK		0xE0
 #define WLED_BOOST_LIMIT_BIT_SHFT	0x05
+#define WLED_BOOST_OFF			0x00
 #define WLED_EN_MASK			0x01
 #define WLED_CP_SELECT_MAX		0x03
 #define WLED_CP_SELECT_MASK		0x03
@@ -155,6 +156,7 @@
 	struct led_classdev	cdev;
 	int			id;
 	u8			reg;
+	u8			wled_mod_ctrl_val;
 	struct device		*dev;
 	struct work_struct	work;
 	struct mutex		lock;
@@ -237,6 +239,24 @@
 	if (value > WLED_MAX_LEVEL)
 		value = WLED_MAX_LEVEL;
 
+	if (value == 0) {
+		rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+				WLED_BOOST_OFF);
+		if (rc) {
+			dev_err(led->dev->parent, "can't write wled ctrl config"
+				" register rc=%d\n", rc);
+			return rc;
+		}
+	} else {
+		rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+				led->wled_mod_ctrl_val);
+		if (rc) {
+			dev_err(led->dev->parent, "can't write wled ctrl config"
+				" register rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	duty = (WLED_MAX_DUTY_CYCLE * value) / WLED_MAX_LEVEL;
 
 	num_wled_strings = led->wled_cfg->num_strings;
@@ -629,6 +649,7 @@
 			" register rc=%d\n", rc);
 		return rc;
 	}
+	led->wled_mod_ctrl_val = val;
 
 	/* dump wled registers */
 	wled_dump_regs(led);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 5aaef24..7d53e11 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1090,3 +1090,5 @@
 
 
 endif # V4L_MEM2MEM_DRIVERS
+
+source "drivers/media/video/msm_vidc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 65a2348..444d3d4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -189,6 +189,7 @@
 
 obj-$(CONFIG_MSM_CAMERA) += msm/
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
+obj-$(CONFIG_MSM_VIDC) += msm_vidc/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index fbc3a37..b602c37 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -271,3 +271,9 @@
 	  overlay driver. This allows video rendering
 	  apps to render overlaid video using Video4Linux2
 	  APIs, by using /dev/videoX device
+
+config OV7692
+	bool "Sensor OV7692 (VGA YUV)"
+	depends on MSM_CAMERA
+	---help---
+	  Omni Vision VGA YUV Sensor
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index e4d8368..85470b7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -253,6 +253,8 @@
 			target_step_pos = dest_step_pos;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
+			if (curr_lens_pos == target_lens_pos)
+				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
@@ -273,6 +275,8 @@
 			target_step_pos = step_boundary;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
+			if (curr_lens_pos == target_lens_pos)
+				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 6a5a647..e8be393 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -289,6 +289,8 @@
 			return rc;
 		}
 	}
+	if (csic_dev->hw_version == CSIC_7X)
+		msm_camio_vfe_blk_reset_3();
 
 #if DBG_CSIC
 	enable_irq(csic_dev->irq->start);
@@ -433,12 +435,28 @@
 		goto csic_no_resource;
 	}
 	disable_irq(new_csic_dev->irq->start);
-	iounmap(new_csic_dev->base);
-	new_csic_dev->base = NULL;
 
 	new_csic_dev->pdev = pdev;
+
+	rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_clk_info[2],
+				new_csic_dev->csic_clk, 1, 1);
+	new_csic_dev->base = ioremap(new_csic_dev->mem->start,
+		resource_size(new_csic_dev->mem));
+	if (!new_csic_dev->base) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	msm_camera_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL);
+
+	rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_clk_info[2],
+				new_csic_dev->csic_clk, 1, 0);
+
+	iounmap(new_csic_dev->base);
+	new_csic_dev->base = NULL;
 	msm_cam_register_subdev_node(
 		&new_csic_dev->subdev, CSIC_DEV, pdev->id);
+
 	return 0;
 
 csic_no_resource:
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 45761d5..946b985 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -85,27 +85,18 @@
 	clk_set_rate(clk, rate);
 }
 
-void msm_camio_vfe_blk_reset_2(int vfe_apps_reset)
+void msm_camio_vfe_blk_reset_2(void)
 {
 	uint32_t val;
 
-	if (apps_reset && !vfe_apps_reset)
-		return;
-
 	/* do apps reset */
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val |= 0x10A0001;
-	else
-		val |= 0x1;
+	val |= 0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val &= ~(0x10A0001);
-	else
-		val &= ~0x1;
+	val &= ~0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
@@ -122,6 +113,26 @@
 	usleep_range(10000, 11000);
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	uint32_t val;
+
+	if (!apps_reset)
+		return;
+
+	/* do apps reset */
+	val = readl_relaxed(appbase + 0x00000210);
+	val |= 0x10A0000;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000210);
+	val &= ~(0x10A0000);
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+	mb();
+}
+
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index a1270ea..9dc097b 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -156,6 +156,11 @@
 	return;
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	return;
+}
+
 static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index dd567d1..0f71404 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -258,7 +258,8 @@
 	{VFE_CMD_DUMMY_9, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AF_START, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
 		"VFE_CMD_STATS_AF_START", "VFE_STATS_AUTOFOCUS_CONFIG"},
-	{VFE_CMD_STATS_AF_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AF_STOP, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_AF_STOP", "VFE_STATS_AUTOFOCUS_CONFIG"},
 	{VFE_CMD_STATS_AE_START, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AE_STOP, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AWB_START, VFE_MAX, VFE_MAX},
@@ -341,7 +342,6 @@
 static uint32_t extlen;
 
 struct mutex vfe_lock;
-static int apps_reset;
 static uint8_t vfestopped;
 
 static struct stop_event stopevent;
@@ -489,6 +489,8 @@
 					len = sizeof(fack);
 					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 						cmd_data, len);
+					kfree(data);
+					return;
 				}
 			}
 			y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -557,6 +559,8 @@
 					len = sizeof(fack);
 					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 						cmd_data, len);
+					kfree(data);
+					return;
 				}
 			}
 			y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -666,7 +670,9 @@
 						msgs_map[id].isp_id);
 			break;
 		default:
-			vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+			if (MSG_TABLE_CMD_ACK != id)
+				vfe2x_send_isp_msg(vfe2x_ctrl,
+						msgs_map[id].isp_id);
 			break;
 		}
 	}
@@ -1216,8 +1222,7 @@
 		if (queue == QDSP_CMDQUEUE) {
 			switch (vfecmd.id) {
 			case VFE_CMD_RESET:
-				msm_camio_vfe_blk_reset_2(apps_reset);
-				apps_reset = 0;
+				msm_camio_vfe_blk_reset_2();
 				vfestopped = 0;
 				break;
 			case VFE_CMD_START:
@@ -1270,7 +1275,10 @@
 				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
 						vfe2x_ctrl->tableack_pending) {
 					CDBG("update pending\n");
-					vfe2x_ctrl->update_pending = 1;
+					vfe2x_ctrl->update_pending = 0;
+					vfe2x_send_isp_msg(vfe2x_ctrl,
+						msgs_map[MSG_UPDATE_ACK].
+						isp_id);
 					spin_unlock_irqrestore(
 							&vfe2x_ctrl->table_lock,
 							flags);
@@ -1588,29 +1596,30 @@
 
 config_send:
 	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+	spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 	if (queue == QDSP_TABLEQUEUE &&
 			vfe2x_ctrl->tableack_pending) {
 		CDBG("store table cmd\n");
 		table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
 		if (!table_pending) {
 			rc = -ENOMEM;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			goto config_done;
 		}
 		table_pending->cmd = kzalloc(vfecmd.length + 4, GFP_ATOMIC);
 		if (!table_pending->cmd) {
 			kfree(table_pending);
 			rc = -ENOMEM;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			goto config_done;
 		}
 		memcpy(table_pending->cmd, cmd_data, vfecmd.length + 4);
 		table_pending->queue = queue;
 		table_pending->size = vfecmd.length + 4;
-		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 		list_add_tail(&table_pending->list, &vfe2x_ctrl->table_q);
 		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 	} else {
 		if (queue == QDSP_TABLEQUEUE) {
-			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 			CDBG("sending table cmd\n");
 			vfe2x_ctrl->tableack_pending = 1;
 			rc = msm_adsp_write(vfe_mod, queue,
@@ -1621,7 +1630,6 @@
 				uint32_t *ptr = cmd_data;
 				CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
 			}
-			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 			CDBG("send n-table cmd\n");
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
@@ -1717,8 +1725,6 @@
 	CDBG("msm_cam_clk_enable: disable vfe_clk\n");
 	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
 			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
-	apps_reset = 1;
-
 	msm_adsp_disable(qcam_mod);
 	msm_adsp_disable(vfe_mod);
 
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 13dc446..ea36bf6 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -13,5 +13,5 @@
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
 obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
 obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
-obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
+obj-$(CONFIG_OV7692) += ov7692_v4l2.o
 obj-$(CONFIG_VX6953) += vx6953.o
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
similarity index 100%
rename from drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
rename to drivers/media/video/msm/sensors/ov7692_v4l2.c
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 8cad387..c94fa13 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -365,7 +365,15 @@
 		WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
 		goto err;
 	}
-	b->count = buf_req.actual_count;
+
+	buf_req.actual_count = b->count = max(buf_req.min_count, b->count);
+	rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &buf_req);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set out buf reqs rc = %d", rc);
+		goto err;
+	}
+
 err:
 	return rc;
 }
diff --git a/drivers/media/video/msm_vidc/Kconfig b/drivers/media/video/msm_vidc/Kconfig
new file mode 100644
index 0000000..0b5a5fe
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Kconfig
@@ -0,0 +1,8 @@
+#
+# VIDEO CORE
+#
+
+menuconfig MSM_VIDC
+	bool "Qualcomm MSM Video Core Driver"
+		depends on ARCH_MSMCOPPER && VIDEO_V4L2
+		default y
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
new file mode 100644
index 0000000..12c61c9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_MSM_VIDC) := 	msm_v4l2_vidc.o \
+				msm_vidc_common.o \
+				msm_vidc.o \
+				msm_vdec.o \
+				msm_venc.o \
+				msm_smem.o \
+				vidc_hal.o \
+				vidc_hal_interrupt_handler.o \
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index f125cdc..550fbde 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -41,11 +41,49 @@
 };
 
 struct msm_v4l2_vid_inst {
-	void *vidc_inst;
+	struct msm_vidc_inst vidc_inst;
 	void *mem_client;
 	struct list_head registered_bufs;
 };
 
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+	return container_of(filp->private_data,
+					struct msm_vidc_inst, event_handler);
+}
+
+static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
+			void *fh)
+{
+	struct msm_vidc_inst *vidc_inst;
+	vidc_inst = container_of(filp->private_data,
+			struct msm_vidc_inst, event_handler);
+	return container_of((void *)vidc_inst,
+			struct msm_v4l2_vid_inst, vidc_inst);
+}
+
+static int msm_vidc_v4l2_setup_event_queue(void *inst,
+				struct video_device *pvdev)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+	spin_lock_init(&pvdev->fh_lock);
+	INIT_LIST_HEAD(&pvdev->fh_list);
+	rc = v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+	if (rc < 0)
+		return rc;
+	if (&vidc_inst->event_handler.events == NULL) {
+		rc = v4l2_event_init(&vidc_inst->event_handler);
+		if (rc < 0)
+			return rc;
+	}
+	rc = v4l2_event_alloc(&vidc_inst->event_handler, 32);
+	if (rc < 0)
+		return rc;
+	v4l2_fh_add(&vidc_inst->event_handler);
+	return rc;
+}
+
 struct buffer_info *get_registered_buf(struct list_head *list,
 				int fd, u32 buff_off, u32 size)
 {
@@ -79,7 +117,6 @@
 	struct msm_video_device *vid_dev =
 		container_of(vdev, struct msm_video_device, vdev);
 	struct msm_vidc_core *core = video_drvdata(filp);
-	void *inst;
 	struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
 						GFP_KERNEL);
 	if (!v4l2_inst) {
@@ -93,16 +130,17 @@
 		rc = -ENOMEM;
 		goto fail_mem_client;
 	}
-	inst = msm_vidc_open(core->id, vid_dev->type);
-	if (!inst) {
+	rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
+	if (rc) {
 		pr_err("Failed to create video instance, core: %d, type = %d\n",
 			core->id, vid_dev->type);
 		rc = -ENOMEM;
 		goto fail_open;
 	}
 	INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
-	v4l2_inst->vidc_inst = inst;
-	filp->private_data = v4l2_inst;
+	rc = msm_vidc_v4l2_setup_event_queue(&v4l2_inst->vidc_inst, vdev);
+	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+	filp->private_data = &(v4l2_inst->vidc_inst.event_handler);
 	return rc;
 fail_open:
 	msm_smem_delete_client(v4l2_inst->mem_client);
@@ -117,8 +155,11 @@
 	int rc;
 	struct list_head *ptr, *next;
 	struct buffer_info *binfo;
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	rc = msm_vidc_close(v4l2_inst->vidc_inst);
+	struct msm_vidc_inst *vidc_inst;
+	struct msm_v4l2_vid_inst *v4l2_inst;
+	vidc_inst = get_vidc_inst(filp, NULL);
+	v4l2_inst = get_v4l2_inst(filp, NULL);
+	rc = msm_vidc_close(vidc_inst);
 	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 		binfo = list_entry(ptr, struct buffer_info, list);
 		list_del(&binfo->list);
@@ -133,60 +174,94 @@
 static int msm_v4l2_querycap(struct file *filp, void *fh,
 			struct v4l2_capability *cap)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	return msm_vidc_querycap(v4l2_inst->vidc_inst, cap);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+	return msm_vidc_querycap((void *)vidc_inst, cap);
 }
 
 int msm_v4l2_enum_fmt(struct file *file, void *fh,
 					struct v4l2_fmtdesc *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_enum_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_s_fmt(struct file *file, void *fh,
 					struct v4l2_format *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_s_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_s_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_g_fmt(struct file *file, void *fh,
 					struct v4l2_format *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_g_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_g_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_s_ctrl(struct file *file, void *fh,
 					struct v4l2_control *a)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, a);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_s_ctrl((void *)vidc_inst, a);
 }
 
 int msm_v4l2_g_ctrl(struct file *file, void *fh,
 					struct v4l2_control *a)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, a);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_g_ctrl((void *)vidc_inst, a);
 }
 
 int msm_v4l2_reqbufs(struct file *file, void *fh,
 				struct v4l2_requestbuffers *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_reqbufs(v4l2_inst->vidc_inst, b);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	struct msm_v4l2_vid_inst *v4l2_inst;
+	struct list_head *ptr, *next;
+	int rc;
+	struct buffer_info *bi;
+	struct v4l2_buffer buffer_info;
+	v4l2_inst = get_v4l2_inst(file, NULL);
+	if (b->count == 0) {
+		list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+			bi = list_entry(ptr, struct buffer_info, list);
+			if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				buffer_info.type = bi->type;
+				buffer_info.m.planes[0].reserved[0] =
+					bi->fd;
+				buffer_info.m.planes[0].reserved[1] =
+					bi->buff_off;
+				buffer_info.m.planes[0].length = bi->size;
+				buffer_info.m.planes[0].m.userptr =
+					bi->uvaddr;
+				buffer_info.length = 1;
+				pr_err("Releasing buffer: %d, %d, %d\n",
+				buffer_info.m.planes[0].reserved[0],
+				buffer_info.m.planes[0].reserved[1],
+				buffer_info.m.planes[0].length);
+				rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+					&buffer_info);
+				list_del(&bi->list);
+				msm_smem_free(v4l2_inst->mem_client,
+					bi->handle);
+				kfree(bi);
+			}
+		}
+	}
+	return msm_vidc_reqbufs((void *)vidc_inst, b);
 }
 
 int msm_v4l2_prepare_buf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
 	struct msm_smem *handle;
 	struct buffer_info *binfo;
-	int rc = 0;
-	int i;
+	struct msm_vidc_inst *vidc_inst;
+	struct msm_v4l2_vid_inst *v4l2_inst;
+	int i, rc = 0;
+	vidc_inst = get_vidc_inst(file, fh);
+	v4l2_inst = get_v4l2_inst(file, fh);
 	if (!v4l2_inst->mem_client) {
 		pr_err("Failed to get memory client\n");
 		rc = -ENOMEM;
@@ -229,7 +304,7 @@
 		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
 		b->m.planes[i].m.userptr = handle->device_addr;
 	}
-	rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
+	rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
 exit:
 	return rc;
 }
@@ -237,10 +312,13 @@
 int msm_v4l2_qbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	struct msm_vidc_inst *vidc_inst;
+	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct buffer_info *binfo;
 	int rc = 0;
 	int i;
+	vidc_inst = get_vidc_inst(file, fh);
+	v4l2_inst = get_v4l2_inst(file, fh);
 	for (i = 0; i < b->length; ++i) {
 		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
@@ -258,7 +336,7 @@
 		pr_debug("Queueing device address = %ld\n",
 				binfo->handle->device_addr);
 	}
-	rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+	rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
 err_invalid_buff:
 	return rc;
 }
@@ -266,22 +344,47 @@
 int msm_v4l2_dqbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_dqbuf(v4l2_inst->vidc_inst, b);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_dqbuf((void *)vidc_inst, b);
 }
 
 int msm_v4l2_streamon(struct file *file, void *fh,
 				enum v4l2_buf_type i)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_streamon(v4l2_inst->vidc_inst, i);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_streamon((void *)vidc_inst, i);
 }
 
 int msm_v4l2_streamoff(struct file *file, void *fh,
 				enum v4l2_buf_type i)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_streamoff(v4l2_inst->vidc_inst, i);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	if (sub->type == V4L2_EVENT_ALL)
+		sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+	rc = v4l2_event_subscribe(fh, sub);
+	return rc;
+}
+
+static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	rc = v4l2_event_unsubscribe(fh, sub);
+	return rc;
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+				struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
 }
 static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
 	.vidioc_querycap = msm_v4l2_querycap,
@@ -299,6 +402,9 @@
 	.vidioc_streamoff = msm_v4l2_streamoff,
 	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
 	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
 };
 
 static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -307,8 +413,8 @@
 static unsigned int msm_v4l2_poll(struct file *filp,
 	struct poll_table_struct *pt)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	return msm_vidc_poll(v4l2_inst->vidc_inst, filp, pt);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+	return msm_vidc_poll((void *)vidc_inst, filp, pt);
 }
 
 static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 879d324..3c279c9 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -249,20 +249,26 @@
 		pr_err("Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&inst->lock, flags);
-	list_for_each_safe(ptr, next, &inst->internalbufs) {
-		buf = list_entry(ptr, struct internal_buf, list);
-		list_del(&buf->list);
-		msm_smem_free(inst->mem_client, buf->handle);
-		kfree(buf);
+	if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		spin_lock_irqsave(&inst->lock, flags);
+		if (!list_empty(&inst->internalbufs)) {
+			list_for_each_safe(ptr, next, &inst->internalbufs) {
+				buf = list_entry(ptr, struct internal_buf,
+								 list);
+				list_del(&buf->list);
+				msm_smem_free(inst->mem_client, buf->handle);
+				kfree(buf);
+			}
 		}
-	list_for_each_safe(ptr, next, &inst->extradatabufs) {
-		ebuf = list_entry(ptr, struct extradata_buf, list);
-		list_del(&ebuf->list);
-		msm_smem_free(inst->mem_client, ebuf->handle);
-		kfree(ebuf);
+		if (!list_empty(&inst->extradatabufs)) {
+			list_for_each_safe(ptr, next, &inst->extradatabufs) {
+				ebuf = list_entry(ptr, struct extradata_buf,
+								  list);
+				ebuf->device_addr = 0;
+			}
 		}
-	spin_unlock_irqrestore(&inst->lock, flags);
+		spin_unlock_irqrestore(&inst->lock, flags);
+	}
 
 	pr_debug("Calling streamoff\n");
 	rc = vb2_streamoff(q, i);
@@ -320,6 +326,54 @@
 	return rc;
 }
 
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info;
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+		struct extradata_buf *addr;
+		for (i = 0; i < b->length; i++) {
+			pr_err("Release device_addr = %ld, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+			buffer_info.buffer_size = b->m.planes[i].length;
+			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr =
+				 b->m.planes[i].m.userptr;
+			if (!list_empty(&inst->extradatabufs)) {
+				list_for_each_entry(addr, &inst->
+					extradatabufs, list) {
+					if (addr->device_addr ==
+							buffer_info.
+						align_device_addr) {
+						buffer_info.extradata_addr =
+							addr->handle->
+							device_addr;
+						break;
+					}
+				}
+			}
+			rc = vidc_hal_session_release_buffers(
+				(void *)inst->session, &buffer_info);
+			if (rc)
+				pr_err("vidc_hal_session_release_buffers failed");
+		}
+		break;
+	}
+	default:
+		pr_err("Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+	return rc;
+}
+
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
 {
 	struct vb2_queue *q = NULL;
@@ -345,7 +399,7 @@
 	}
 	rc = vb2_dqbuf(q, b, true);
 	if (rc)
-		pr_err("Failed to qbuf, %d\n", rc);
+		pr_err("Failed to dqbuf, %d\n", rc);
 	return rc;
 }
 
@@ -385,6 +439,10 @@
 
 	if (fmt) {
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
+		if (inst->in_reconfig == true) {
+			inst->height = inst->reconfig_height;
+			inst->width = inst->reconfig_width;
+		}
 		f->fmt.pix_mp.height = inst->height;
 		f->fmt.pix_mp.width = inst->width;
 		for (i = 0; i < fmt->num_planes; ++i) {
@@ -579,7 +637,6 @@
 	struct hal_nal_stream_format_supported stream_format;
 	struct hal_enable_picture enable_picture;
 	struct hal_enable hal_property;
-	struct hal_enable prop;
 	u32 control_idx = 0;
 	enum hal_property property_id = 0;
 	u32 property_val = 0;
@@ -662,12 +719,6 @@
 		}
 	}
 
-	prop.enable = 1;
-	rc = vidc_hal_session_set_property((void *)inst->session,
-			HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
-	if (rc)
-		pr_err("Failed to set smooth streaming\n");
-
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
 		pr_err("Failed to move inst: %p to start done state\n",
@@ -709,6 +760,7 @@
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		inst->in_reconfig = false;
 		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
@@ -732,9 +784,12 @@
 	pr_debug("Streamoff called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
+			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
+			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 6529065..1242fb4 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -26,6 +26,7 @@
 int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 718acf0..5dfea04f 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -365,9 +365,9 @@
 
 static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
 {
-	int stride = (width + 31) & (~31);
-	return height * stride * 3/2;
+	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
 }
+
 static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
 {
 	return height * width * 2;
@@ -375,8 +375,9 @@
 
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
 {
-	return width * height / 2;
+	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
 }
+
 static struct hal_quantization
 	venc_quantization = {I_FRAME_QP, P_FRAME_QP, B_FRAME_QP};
 static struct hal_intra_period
@@ -896,7 +897,7 @@
 		break;
 	}
 	if (property_id) {
-		pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+		pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
 				property_id,
 				msm_venc_ctrls[control_idx].id,
 				control.value);
@@ -1110,7 +1111,7 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
-			pr_err("device_addr = %ld, size = %d\n",
+			pr_debug("device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
 			buffer_info.buffer_size = b->m.planes[i].length;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 7fcb522..d589bf5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,17 @@
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
+	poll_wait(filp, &inst->event_handler.events->wait, wait);
+	if (v4l2_event_pending(&inst->event_handler))
+		return POLLPRI;
 	if (!outq->streaming && !capq->streaming) {
 		pr_err("Returning POLLERR from here: %d, %d\n",
 			outq->streaming, capq->streaming);
 		return POLLERR;
 	}
+	poll_wait(filp, &inst->event_handler.events->wait, wait);
+	if (v4l2_event_pending(&inst->event_handler))
+		return POLLPRI;
 	poll_wait(filp, &capq->done_wq, wait);
 	poll_wait(filp, &outq->done_wq, wait);
 	spin_lock_irqsave(&capq->done_lock, flags);
@@ -129,6 +135,14 @@
 	return -EINVAL;
 }
 
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_release_buf(instance, b);
+	return -EINVAL;
+}
+
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -208,9 +222,9 @@
 	return vb2_queue_init(q);
 }
 
-void *msm_vidc_open(int core_id, int session_type)
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
 {
-	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
 	struct msm_vidc_core *core = NULL;
 	unsigned long flags;
 	int rc = 0;
@@ -227,11 +241,6 @@
 		goto err_invalid_core;
 	}
 
-	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-	if (!inst) {
-		pr_err("Unable to allocate video instance\n");
-		goto err_no_mem;
-	}
 	mutex_init(&inst->sync_lock);
 	spin_lock_init(&inst->lock);
 	inst->session_type = session_type;
@@ -254,6 +263,7 @@
 		msm_vdec_ctrl_init(inst);
 	} else if (session_type == MSM_VIDC_ENCODER) {
 		msm_venc_inst_init(inst);
+		msm_venc_ctrl_init(inst);
 	}
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 			session_type);
@@ -275,15 +285,14 @@
 	spin_lock_irqsave(&core->lock, flags);
 	list_add_tail(&inst->list, &core->instances);
 	spin_unlock_irqrestore(&core->lock, flags);
-	return inst;
+	return rc;
 fail_init:
 	msm_smem_delete_client(inst->mem_client);
 fail_mem_client:
 	kfree(inst);
 	inst = NULL;
-err_no_mem:
 err_invalid_core:
-	return inst;
+	return rc;
 }
 
 static void cleanup_instance(struct msm_vidc_inst *inst)
@@ -292,25 +301,25 @@
 	struct list_head *ptr, *next;
 	struct vb2_buf_entry *entry;
 	struct internal_buf *buf;
-	struct extradata_buf *ebuf;
+
 	if (inst) {
 		spin_lock_irqsave(&inst->lock, flags);
-		list_for_each_safe(ptr, next, &inst->pendingq) {
-			entry = list_entry(ptr, struct vb2_buf_entry, list);
-			list_del(&entry->list);
-			kfree(entry);
+		if (!list_empty(&inst->pendingq)) {
+			list_for_each_safe(ptr, next, &inst->pendingq) {
+				entry = list_entry(ptr, struct vb2_buf_entry,
+						list);
+				list_del(&entry->list);
+				kfree(entry);
+			}
 		}
-		list_for_each_safe(ptr, next, &inst->internalbufs) {
-			buf = list_entry(ptr, struct internal_buf, list);
-			list_del(&buf->list);
-			msm_smem_free(inst->mem_client, buf->handle);
-			kfree(buf);
-		}
-		list_for_each_safe(ptr, next, &inst->extradatabufs) {
-			ebuf = list_entry(ptr, struct extradata_buf, list);
-			list_del(&ebuf->list);
-			msm_smem_free(inst->mem_client, ebuf->handle);
-			kfree(ebuf);
+		if (!list_empty(&inst->internalbufs)) {
+			list_for_each_safe(ptr, next, &inst->internalbufs) {
+				buf = list_entry(ptr, struct internal_buf,
+						list);
+				list_del(&buf->list);
+				msm_smem_free(inst->mem_client, buf->handle);
+				kfree(buf);
+			}
 		}
 		spin_unlock_irqrestore(&inst->lock, flags);
 		msm_smem_delete_client(inst->mem_client);
@@ -328,15 +337,13 @@
 	mutex_lock(&core->sync_lock);
 	list_for_each_safe(ptr, next, &core->instances) {
 		temp = list_entry(ptr, struct msm_vidc_inst, list);
-		if (temp == inst) {
+		if (temp == inst)
 			list_del(&inst->list);
-			kfree(inst);
-		}
 	}
 	mutex_unlock(&core->sync_lock);
 	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
 	if (rc)
-		pr_err("Failed to move video instance to init state\n");
+		pr_err("Failed to move video instance to uninit state\n");
 	cleanup_instance(inst);
 	pr_debug("Closed the instance\n");
 	return 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index e889b1c..8a51301 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -183,15 +183,54 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 		return;
 	} else {
 		pr_err("Failed to get valid response for session init\n");
 	}
 }
 
+static void handle_event_change(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_cb_event *event_notify;
+	struct msm_vidc_core *core;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+		event_notify = (struct msm_vidc_cb_event *) response->data;
+		inst->reconfig_height = event_notify->height;
+		inst->reconfig_width = event_notify->width;
+		inst->in_reconfig = true;
+		v4l2_event_queue(vdev, &dqevent);
+		return;
+	} else {
+		pr_err("Failed to get valid response for event_change\n");
+	}
+}
+
 static void handle_session_prop_info(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
@@ -223,11 +262,22 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for start done\n");
+		pr_err("Failed to get valid response for start\n");
 	}
 }
 
@@ -235,11 +285,22 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for stop done\n");
+		pr_err("Failed to get valid response for stop\n");
 	}
 }
 
@@ -251,18 +312,51 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for release"
-			   " resource done\n");
+		pr_err("Failed to get valid response for release resource\n");
 	}
 }
 
+static void handle_session_flush(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
+		v4l2_event_queue(vdev, &dqevent);
+	} else {
+		pr_err("Failed to get valid response for flush\n");
+	}
+}
+
+
 static void handle_session_close(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for session close\n");
 	}
@@ -320,7 +414,7 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
-		pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+		pr_debug("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -361,6 +455,12 @@
 	case SESSION_END_DONE:
 		handle_session_close(cmd, data);
 		break;
+	case VIDC_EVENT_CHANGE:
+		handle_event_change(cmd, data);
+		break;
+	case SESSION_FLUSH_DONE:
+		handle_session_flush(cmd, data);
+		break;
 	default:
 		pr_err("response unhandled\n");
 		break;
@@ -793,18 +893,20 @@
 			pr_debug("Sent etb to HAL\n");
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			struct extradata_buf *addr;
-			struct list_head *ptr, *next;
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 			frame_data.extradata_addr = 0;
-			list_for_each_safe(ptr, next, &inst->extradatabufs) {
-				addr = list_entry(ptr,
-						struct extradata_buf, list);
-				if (addr->device_addr ==
-						frame_data.device_addr) {
-					frame_data.extradata_addr =
-						addr->handle->device_addr;
-					break;
+			if (!list_empty(&inst->extradatabufs)) {
+				list_for_each_entry(addr, &inst->extradatabufs,
+									list) {
+					if (addr->device_addr ==
+							frame_data.
+						device_addr) {
+						frame_data.extradata_addr =
+							addr->
+							handle->device_addr;
+						break;
+					}
 				}
 			}
 			pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
@@ -850,6 +952,23 @@
 	return rc;
 }
 
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	mutex_lock(&inst->sync_lock);
+	if (dec->cmd != V4L2_DEC_CMD_STOP)
+		return -EINVAL;
+	rc = vidc_hal_session_flush((void *)inst->session, HAL_FLUSH_OUTPUT);
+	if (rc) {
+		pr_err("Failed to get property\n");
+		goto exit;
+	}
+exit:
+	mutex_unlock(&inst->sync_lock);
+	return rc;
+}
+
 int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
 	struct extradata_buf *binfo)
 {
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index dce2dee..2c7853b 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -21,6 +21,7 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/videobuf2-core.h>
 #include <media/msm_vidc.h>
@@ -32,6 +33,8 @@
 #define MAX_DEBUGFS_NAME 50
 #define DEFAULT_TIMEOUT 3
 
+#define V4L2_EVENT_VIDC_BASE  10
+
 #define SYS_MSG_START VIDC_EVENT_CHANGE
 #define SYS_MSG_END SYS_DEBUG
 #define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
@@ -72,6 +75,11 @@
 	MSM_VIDC_CORE_UNINIT,
 };
 
+enum vidc_resposes_id {
+	MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
+	MSM_VIDC_DECODER_EVENT_CHANGE,
+};
+
 struct buf_info {
 	struct list_head list;
 	struct vb2_buffer *buf;
@@ -146,6 +154,10 @@
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+	struct v4l2_fh event_handler;
+	bool in_reconfig;
+	u32 reconfig_width;
+	u32 reconfig_height;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index b32c190..036091b 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -18,7 +18,7 @@
 
 #define CONTAINS(__a, __sz, __t) ({\
 	int __rc = __t >= __a && \
-			__t <= __a + __sz; \
+			__t < __a + __sz; \
 	__rc; \
 })
 
@@ -834,6 +834,8 @@
 	u32 device_id;
 	u32 session_id;
 	u32 status;
+	u32 height;
+	u32 width;
 };
 
 /* Data callback structure */
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 0fbcc1f..cb44d3a 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -74,6 +74,59 @@
 	return vidc_err;
 }
 
+void hal_process_sess_evt_seq_changed(struct hal_device *device,
+	struct hfi_msg_event_notify_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	struct msm_vidc_cb_event event_notify;
+	int num_properties_changed;
+	struct hfi_frame_size frame_sz;
+	u8 *data_ptr;
+	enum HFI_PROPERTY prop_id;
+	HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
+	if (sizeof(struct hfi_msg_event_notify_packet)
+		> pkt->size) {
+		HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+		return;
+	}
+
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	memset(&event_notify, 0, sizeof(struct
+				msm_vidc_cb_event));
+
+	cmd_done.device_id = device->device_id;
+	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+		session_id;
+	cmd_done.status = VIDC_ERR_NONE;
+	cmd_done.size = sizeof(struct msm_vidc_cb_event);
+	num_properties_changed = pkt->event_data2;
+	if (num_properties_changed) {
+		data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+		do {
+			prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+			switch (prop_id) {
+			case HFI_PROPERTY_PARAM_FRAME_SIZE:
+				frame_sz.buffer =
+					(enum HFI_BUFFER)
+						*((((u32 *)data_ptr)+1));
+				frame_sz.width =
+					event_notify.width =
+						*((((u32 *)data_ptr)+2));
+				frame_sz.height =
+					event_notify.height =
+						*((((u32 *)data_ptr)+3));
+				data_ptr += 4;
+			break;
+			default:
+			break;
+			}
+			num_properties_changed--;
+		} while (num_properties_changed > 0);
+	}
+	cmd_done.data = &event_notify;
+	device->callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
 static void hal_process_event_notify(struct hal_device *device,
 	struct hfi_msg_event_notify_packet *pkt)
 {
@@ -94,6 +147,7 @@
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		HAL_MSG_INFO("HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+		hal_process_sess_evt_seq_changed(device, pkt);
 		break;
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
 		HAL_MSG_INFO("HFI_EVENT_SESSION_PROPERTY_CHANGED");
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 76d38c1..b128a61 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -564,10 +564,10 @@
 	return ret;
 }
 
-static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
+				     struct wcd9xxx_pdata *pdata)
 {
 	int i;
-	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
 
 	regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
 				    wcd9xxx->supplies);
@@ -780,7 +780,7 @@
 err_device_init:
 	wcd9xxx_free_reset(wcd9xxx);
 err_supplies:
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 err_codec:
 	kfree(wcd9xxx);
 fail:
@@ -790,10 +790,10 @@
 static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
 {
 	struct wcd9xxx *wcd9xxx;
-
+	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
 	pr_debug("exit\n");
 	wcd9xxx = dev_get_drvdata(&client->dev);
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 	wcd9xxx_device_exit(wcd9xxx);
 	return 0;
 }
@@ -922,7 +922,7 @@
 err_reset:
 	wcd9xxx_free_reset(wcd9xxx);
 err_supplies:
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 err_codec:
 	kfree(wcd9xxx);
 err:
@@ -931,6 +931,7 @@
 static int wcd9xxx_slim_remove(struct slim_device *pdev)
 {
 	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = pdev->dev.platform_data;
 
 #ifdef CONFIG_DEBUG_FS
 	debugfs_remove(debugfs_peek);
@@ -940,7 +941,7 @@
 	wcd9xxx = slim_get_devicedata(pdev);
 	wcd9xxx_deinit_slimslave(wcd9xxx);
 	slim_remove_device(wcd9xxx->slim_slave);
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 	wcd9xxx_device_exit(wcd9xxx);
 	return 0;
 }
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 3aff7f17..889c416 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -461,7 +461,13 @@
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		if (idx < 0) {
+			pr_err("%s: Error:-Invalid index found = %d\n",
+				__func__, idx);
+			ret = -EINVAL;
+			goto err;
+		}
 		sph[i] = rx[idx].sph;
 		grph = rx[idx].grph;
 	}
@@ -501,6 +507,12 @@
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM);
+		if (idx < 0) {
+			pr_err("%s: Error:- Invalid index found = %d\n",
+				__func__, idx);
+			ret = -EINVAL;
+			goto err;
+		}
 		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 31c79a0..555dfdd 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2012, 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 as
@@ -32,6 +32,7 @@
 
 #define ISA1200_HCTRL5_VIB_STRT	0xD5
 #define ISA1200_HCTRL5_VIB_STOP	0x6B
+#define ISA1200_POWER_DOWN_MASK 0x7F
 
 struct isa1200_chip {
 	struct i2c_client *client;
@@ -45,6 +46,8 @@
 	unsigned int period_ns;
 	bool is_len_gpio_valid;
 	struct regulator **regs;
+	bool clk_on;
+	u8 hctrl0_val;
 };
 
 static int isa1200_read_reg(struct i2c_client *client, int reg)
@@ -74,32 +77,111 @@
 	int rc = 0;
 
 	if (enable) {
+		/* if hen and len are seperate then enable hen
+		 * otherwise set normal mode bit */
+		if (haptic->is_len_gpio_valid == true)
+			gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
+		else {
+			rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+				haptic->hctrl0_val | ~ISA1200_POWER_DOWN_MASK);
+			if (rc < 0) {
+				pr_err("%s: i2c write failure\n", __func__);
+				return;
+			}
+		}
+
 		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
 			int period_us = haptic->period_ns / 1000;
+
 			rc = pwm_config(haptic->pwm,
 				(period_us * haptic->pdata->duty) / 100,
 				period_us);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: pwm_config fail\n", __func__);
+				goto chip_dwn;
+			}
+
 			rc = pwm_enable(haptic->pwm);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: pwm_enable fail\n", __func__);
+				goto chip_dwn;
+			}
 		} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+			/* vote for clock */
+			if (haptic->pdata->clk_enable && !haptic->clk_on) {
+				rc = haptic->pdata->clk_enable(true);
+				if (rc < 0) {
+					pr_err("%s: clk enable failed\n",
+								__func__);
+					goto chip_dwn;
+				}
+				haptic->clk_on = true;
+			}
+
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
 						ISA1200_HCTRL5_VIB_STRT);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: start vibartion fail\n", __func__);
+				goto dis_clk;
+			}
 		}
 	} else {
-		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
+		/* if hen and len are seperate then pull down hen
+		 * otherwise set power down bit */
+		if (haptic->is_len_gpio_valid == true)
+			gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+		else {
+			rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+				haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+			if (rc < 0) {
+				pr_err("%s: i2c write failure\n", __func__);
+				return;
+			}
+		}
+
+		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
 			pwm_disable(haptic->pwm);
-		else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+		} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
 						ISA1200_HCTRL5_VIB_STOP);
 			if (rc < 0)
 				pr_err("%s: stop vibartion fail\n", __func__);
+
+			/* de-vote clock */
+			if (haptic->pdata->clk_enable && haptic->clk_on) {
+				rc = haptic->pdata->clk_enable(false);
+				if (rc < 0) {
+					pr_err("%s: clk disable failed\n",
+								__func__);
+					return;
+				}
+				haptic->clk_on = false;
+			}
+		}
+	}
+
+	return;
+
+dis_clk:
+	if (haptic->pdata->clk_enable && haptic->clk_on) {
+		rc = haptic->pdata->clk_enable(false);
+		if (rc < 0) {
+			pr_err("%s: clk disable failed\n", __func__);
+			return;
+		}
+		haptic->clk_on = false;
+	}
+chip_dwn:
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	else {
+		rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+			haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+		if (rc < 0) {
+			pr_err("%s: i2c write failure\n", __func__);
+			return;
 		}
 	}
 }
@@ -168,7 +250,8 @@
 static int isa1200_setup(struct i2c_client *client)
 {
 	struct isa1200_chip *haptic = i2c_get_clientdata(client);
-	int value, temp, rc;
+	int temp, rc;
+	u8 value;
 
 	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
 	if (haptic->is_len_gpio_valid == true)
@@ -218,6 +301,20 @@
 		goto reset_hctrl1;
 	}
 
+	/* if hen and len are seperate then pull down hen
+	 * otherwise set power down bit */
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	else {
+		rc = isa1200_write_reg(client, ISA1200_HCTRL0,
+					value & ISA1200_POWER_DOWN_MASK);
+		if (rc < 0) {
+			pr_err("%s: i2c write failure\n", __func__);
+			goto reset_hctrl1;
+		}
+	}
+
+	haptic->hctrl0_val = value;
 	dump_isa1200_reg("new:", client);
 	return 0;
 
@@ -388,6 +485,7 @@
 
 	spin_lock_init(&haptic->lock);
 	INIT_WORK(&haptic->work, isa1200_chip_work);
+	haptic->clk_on = false;
 
 	hrtimer_init(&haptic->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	haptic->timer.function = isa1200_vib_timer_func;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2c42bc7..4c92ee5 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1271,9 +1271,11 @@
 {
 	struct ion_handle *ihandle;	/* Ion handle */
 	struct qseecom_load_img_req load_img_req;
-	int32_t ret;
+	int ret;
+	int set_cpu_ret = 0;
 	ion_phys_addr_t pa = 0;
 	uint32_t len;
+	struct cpumask mask;
 	struct qseecom_load_app_ireq load_req;
 	struct qseecom_command_scm_resp resp;
 
@@ -1302,14 +1304,25 @@
 	load_req.img_len = load_img_req.img_len;
 	load_req.phy_addr = pa;
 
+	/* SCM_CALL tied to Core0 */
+	mask = CPU_MASK_CPU0;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+		goto qseecom_load_external_elf_set_cpu_err;
+	}
+
 	/*  SCM_CALL to load the external elf */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
 			sizeof(struct qseecom_load_app_ireq),
 			&resp, sizeof(resp));
 	if (ret) {
-		pr_err("scm_call to unload failed : ret %d\n",
+		pr_err("scm_call to load failed : ret %d\n",
 				ret);
 		ret = -EFAULT;
+		goto qseecom_load_external_elf_scm_err;
 	}
 
 	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -1324,6 +1337,18 @@
 			ret = -EFAULT;
 		}
 	}
+
+qseecom_load_external_elf_scm_err:
+	/* Restore the CPU mask */
+	mask = CPU_MASK_ALL;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+	}
+
+qseecom_load_external_elf_set_cpu_err:
 	/* Deallocate the handle */
 	if (!IS_ERR_OR_NULL(ihandle))
 		ion_free(qseecom.ion_clnt, ihandle);
@@ -1334,11 +1359,23 @@
 static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
 {
 	int ret = 0;
+	int set_cpu_ret = 0;
 	struct qseecom_command_scm_resp resp;
 	struct qseecom_unload_app_ireq req;
+	struct cpumask mask;
 
 	/* Populate the structure for sending scm call to unload image */
 	req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
+
+	/* SCM_CALL tied to Core0 */
+	mask = CPU_MASK_CPU0;
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret) {
+		pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+				ret);
+		return -EFAULT;
+	}
+
 	/* SCM_CALL to unload the external elf */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
 			sizeof(struct qseecom_unload_app_ireq),
@@ -1346,7 +1383,8 @@
 	if (ret) {
 		pr_err("scm_call to unload failed : ret %d\n",
 				ret);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto qseecom_unload_external_elf_scm_err;
 	}
 	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
 		ret = __qseecom_process_incomplete_cmd(data, &resp);
@@ -1360,6 +1398,17 @@
 			ret = -EFAULT;
 		}
 	}
+
+qseecom_unload_external_elf_scm_err:
+	/* Restore the CPU mask */
+	mask = CPU_MASK_ALL;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+	}
+
 	return ret;
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 925c032..15ddd83 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -228,16 +228,17 @@
 	complete(&mrq->completion);
 }
 
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
 	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
 	if (mmc_card_removed(host->card)) {
 		mrq->cmd->error = -ENOMEDIUM;
 		complete(&mrq->completion);
-		return;
+		return -ENOMEDIUM;
 	}
 	mmc_start_request(host, mrq);
+	return 0;
 }
 
 static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -315,6 +316,7 @@
 {
 	int err = 0;
 	struct mmc_async_req *data = host->areq;
+	int start_err = 0;
 
 	/* Prepare a new request */
 	if (areq)
@@ -323,24 +325,23 @@
 	if (host->areq) {
 		mmc_wait_for_req_done(host, host->areq->mrq);
 		err = host->areq->err_check(host->card, host->areq);
-		if (err) {
-			mmc_post_req(host, host->areq->mrq, 0);
-			if (areq)
-				mmc_post_req(host, areq->mrq, -EINVAL);
-
-			host->areq = NULL;
-			goto out;
-		}
 	}
 
-	if (areq)
-		__mmc_start_req(host, areq->mrq);
+	if (!err && areq)
+		start_err = __mmc_start_req(host, areq->mrq);
 
 	if (host->areq)
 		mmc_post_req(host, host->areq->mrq, 0);
 
-	host->areq = areq;
- out:
+	/* Cancel a prepared request if it was not started. */
+	if ((err || start_err) && areq)
+			mmc_post_req(host, areq->mrq, -EINVAL);
+
+	if (err)
+		host->areq = NULL;
+	else
+		host->areq = areq;
+
 	if (error)
 		*error = err;
 	return data;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4967c4e..717f1d3 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1691,14 +1691,17 @@
 			 * will take care of signaling sdio irq during
 			 * mmc_sdio_resume().
 			 */
-			if (host->sdcc_suspended)
+			if (host->sdcc_suspended) {
 				/*
 				 * This is a wakeup interrupt so hold wakelock
 				 * until SDCC resume is handled.
 				 */
 				wake_lock(&host->sdio_wlock);
-			else
+			} else {
+				spin_unlock(&host->lock);
 				mmc_signal_sdio_irq(host->mmc);
+				spin_lock(&host->lock);
+			}
 			ret = 1;
 			break;
 		}
@@ -1725,7 +1728,9 @@
 		if (status & MCI_SDIOINTROPE) {
 			if (host->sdcc_suspending)
 				wake_lock(&host->sdio_suspend_wlock);
+			spin_unlock(&host->lock);
 			mmc_signal_sdio_irq(host->mmc);
+			spin_lock(&host->lock);
 		}
 		data = host->curr.data;
 
@@ -3105,15 +3110,14 @@
 	 * clocks mci_irqenable will be written to MASK0 register.
 	 */
 
+	spin_lock_irqsave(&host->lock, flags);
 	if (enable) {
-		spin_lock_irqsave(&host->lock, flags);
 		host->mci_irqenable |= MCI_SDIOINTOPERMASK;
 		if (host->clks_on) {
 			writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
 				MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
 			mb();
 		}
-		spin_unlock_irqrestore(&host->lock, flags);
 	} else {
 		host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
 		if (host->clks_on) {
@@ -3122,6 +3126,7 @@
 			mb();
 		}
 	}
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 #ifdef CONFIG_PM_RUNTIME
@@ -3934,10 +3939,13 @@
 	}
 	if (host->plat->is_sdio_al_client) {
 		wake_lock(&host->sdio_wlock);
+		spin_unlock(&host->lock);
 		mmc_signal_sdio_irq(host->mmc);
+		goto out_unlocked;
 	}
 	spin_unlock(&host->lock);
 
+out_unlocked:
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dedf3da..e13b5c3 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1437,6 +1437,8 @@
 			dto -= 13;
 		else
 			dto = 0;
+		/* Use the maximum timeout value allowed in the standard of 14
+		   or 0xE */
 		if (dto > 14)
 			dto = 14;
 	}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e7797b1..b1a16bb 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1555,6 +1555,26 @@
 
 	pr_debug("Enter charge=%d\n", mA);
 
+	if (!the_chip) {
+		pr_err("chip not yet initalized\n");
+		return;
+	}
+
+	/*
+	 * Reject VBUS requests if USB connection is the only available
+	 * power source. This makes sure that if booting without
+	 * battery the iusb_max value is not decreased avoiding potential
+	 * brown_outs.
+	 *
+	 * This would also apply when the battery has been
+	 * removed from the running system.
+	 */
+	if (!get_prop_batt_present(the_chip)
+		&& !is_dc_chg_plugged_in(the_chip)) {
+		pr_err("rejected: no other power source connected\n");
+		return;
+	}
+
 	if (usb_max_current && mA > usb_max_current) {
 		pr_warn("restricting usb current to %d instead of %d\n",
 					usb_max_current, mA);
@@ -3363,13 +3383,6 @@
 		return rc;
 	}
 
-	/* init with the lowest USB current */
-	rc = pm_chg_iusbmax_set(chip, 0);
-	if (rc) {
-		pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
-		return rc;
-	}
-
 	if (chip->safety_time != 0) {
 		rc = pm_chg_tchg_max_set(chip, chip->safety_time);
 		if (rc) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index d74959e..15fc0c1 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -223,6 +223,7 @@
 	char **uevent_envp = NULL;
 	static enum android_device_state last_uevent, next_state;
 	unsigned long flags;
+	int pm_qos_vote = -1;
 
 	spin_lock_irqsave(&cdev->lock, flags);
 	if (cdev->config) {
@@ -232,13 +233,16 @@
 		uevent_envp = dev->connected ? connected : disconnected;
 		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
 		if (dev->connected && strncmp(dev->pm_qos, "low", 3))
-			android_pm_qos_update_latency(dev, 1);
+			pm_qos_vote = 1;
 		else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
-			android_pm_qos_update_latency(dev, 0);
+			pm_qos_vote = 0;
 	}
 	dev->sw_connected = dev->connected;
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
+	if (pm_qos_vote != -1)
+		android_pm_qos_update_latency(dev, pm_qos_vote);
+
 	if (uevent_envp) {
 		/*
 		 * Some userspace modules, e.g. MTP, work correctly only if
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 02b2cc3..b2a013c 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -153,7 +153,7 @@
 	.wNdpOutDivisor = cpu_to_le16(4),
 	.wNdpOutPayloadRemainder = cpu_to_le16(0),
 	.wNdpOutAlignment = cpu_to_le16(4),
-	.wNtbOutMaxDatagrams = cpu_to_le16(4),
+	.wNtbOutMaxDatagrams = 0,
 };
 
 /*
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0e619e6..87244e9 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -708,7 +708,8 @@
 		ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
 		if (ret < 0) {
 			DBG(cdev, "send_file_work: xfer error %d\n", ret);
-			dev->state = STATE_ERROR;
+			if (dev->state != STATE_OFFLINE)
+				dev->state = STATE_ERROR;
 			r = -EIO;
 			break;
 		}
@@ -760,7 +761,8 @@
 			ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
 			if (ret < 0) {
 				r = -EIO;
-				dev->state = STATE_ERROR;
+				if (dev->state != STATE_OFFLINE)
+					dev->state = STATE_ERROR;
 				break;
 			}
 		}
@@ -772,7 +774,8 @@
 			DBG(cdev, "vfs_write %d\n", ret);
 			if (ret != write_req->actual) {
 				r = -EIO;
-				dev->state = STATE_ERROR;
+				if (dev->state != STATE_OFFLINE)
+					dev->state = STATE_ERROR;
 				break;
 			}
 			write_req = NULL;
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index 0ee1827..891a4e2 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -889,7 +889,13 @@
 	if (can_phy_power_collapse(dev) && dev->pdata->ldo_enable)
 		dev->pdata->ldo_enable(1);
 
-	msm_otg_get_resume(dev);
+	if (pm_runtime_enabled(dev->otg.dev)) {
+		msm_otg_get_resume(dev);
+	} else {
+		pm_runtime_get_noresume(dev->otg.dev);
+		msm_otg_resume(dev);
+		pm_runtime_set_active(dev->otg.dev);
+	}
 
 	if (!is_phy_clk_disabled())
 		goto phy_resumed;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index deb4064..0ff0a48 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1192,10 +1192,12 @@
 
 	/*
 	 * if entering host mode tell the charger to not draw any current
-	 * from usb - if exiting host mode let the charger draw current
+	 * from usb before turning on the boost.
+	 * if exiting host mode disable the boost before enabling to draw
+	 * current from the source.
 	 */
-	pm8921_disable_source_current(on);
 	if (on) {
+		pm8921_disable_source_current(on);
 		ret = regulator_enable(vbus_otg);
 		if (ret) {
 			pr_err("unable to enable vbus_otg\n");
@@ -1208,6 +1210,7 @@
 			pr_err("unable to disable vbus_otg\n");
 			return;
 		}
+		pm8921_disable_source_current(on);
 		vbus_is_on = false;
 	}
 }
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 471ed4e..3d35dd5 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -659,6 +659,7 @@
 		goto error_extra;
 
 	INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work);
+	mgmt->hist = NULL;
 
 	mdp_hist_mgmt_array[index] = mgmt;
 	return 0;
@@ -685,7 +686,8 @@
 {
 	struct mdp_hist_mgmt *temp;
 	int i, ret;
-	mdp_hist_wq = alloc_workqueue("mdp_hist_wq", WQ_UNBOUND, 0);
+	mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
+					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
 
 	for (i = 0; i < MDP_HIST_MGMT_MAX; i++)
 		mdp_hist_mgmt_array[i] = NULL;
@@ -897,6 +899,7 @@
 	mgmt->frame_cnt = req->frame_cnt;
 	mgmt->bit_mask = req->bit_mask;
 	mgmt->num_bins = req->num_bins;
+	mgmt->hist = NULL;
 
 	ret = mdp_histogram_enable(mgmt);
 
@@ -1080,8 +1083,11 @@
 		goto error;
 	}
 
-	/* if read was triggered by an underrun, don't wake up readers*/
-	if (mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+	/*
+	 * if read was triggered by an underrun or failed copying,
+	 * don't wake up readers
+	 */
+	if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
 		mgmt->hist = NULL;
 		complete(&mgmt->mdp_hist_comp);
 	}
@@ -1177,6 +1183,11 @@
 		goto error_lock;
 	}
 
+	if (mgmt->hist != NULL) {
+		pr_err("%s; histogram attempted to be read twice\n", __func__);
+		ret = -EPERM;
+		goto error_lock;
+	}
 	mgmt->hist = hist;
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 
@@ -1740,7 +1751,6 @@
 	spin_lock_init(&mdp_spin_lock);
 	mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
 	mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
-	mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
 	mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
 	INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
 			  mdp_pipe_ctrl_workqueue_handler);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 34fd399..2e69ea6 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2354,14 +2354,16 @@
 		return;
 
 	if (mfd->use_ov0_blt) {
-		if (mfd->panel_info.type == LCDC_PANEL)
+		if (mfd->panel_info.type == LCDC_PANEL ||
+		    mfd->panel_info.type == LVDS_PANEL)
 			mdp4_lcdc_overlay_blt_start(mfd);
 		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
 			mdp4_dsi_video_blt_start(mfd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_start(mfd);
 	} else {
-		if (mfd->panel_info.type == LCDC_PANEL)
+		if (mfd->panel_info.type == LCDC_PANEL ||
+		    mfd->panel_info.type == LVDS_PANEL)
 			mdp4_lcdc_overlay_blt_stop(mfd);
 		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
 			mdp4_dsi_video_blt_stop(mfd);
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index baad0a8..7564016 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -178,6 +178,17 @@
 	clk_rate = mfd->fbi->var.pixclock;
 	clk_rate = min(clk_rate, mfd->panel_info.clk_max);
 
+	mipi_dsi_phy_ctrl(1);
+
+	if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
+		target_type = mipi_dsi_pdata->target_type;
+
+	mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
+
+	local_bh_disable();
+	mipi_dsi_clk_enable();
+	local_bh_enable();
+
 	MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
 
@@ -190,17 +201,6 @@
 	width = mfd->panel_info.xres;
 	height = mfd->panel_info.yres;
 
-	mipi_dsi_phy_ctrl(1);
-
-	if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
-		target_type = mipi_dsi_pdata->target_type;
-
-	mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
-
-	local_bh_disable();
-	mipi_dsi_clk_enable();
-	local_bh_enable();
-
 	mipi  = &mfd->panel_info.mipi;
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
 		dummy_xres = mfd->panel_info.lcdc.xres_pad;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6358a0e..1218794 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -2387,6 +2387,7 @@
 	u32 rc, seqhdr_present = 0;
 	struct vcd_property_hdr prop_hdr;
 	struct vcd_sequence_hdr seq_hdr;
+	struct vcd_property_sps_pps_for_idr_enable idr_enable;
 	struct vcd_property_codec codec;
 	*handled = true;
 	prop_hdr.prop_id = DDL_I_SEQHDR_PRESENT;
@@ -2403,29 +2404,64 @@
 	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &codec);
 	if (!VCD_FAILED(rc)) {
 		if (codec.codec != VCD_CODEC_H263) {
-			prop_hdr.prop_id = VCD_I_SEQ_HEADER;
-			prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
-			seq_hdr.sequence_header = frm_entry->virtual;
-			seq_hdr.sequence_header_len =
-				frm_entry->alloc_len;
-			rc = ddl_get_property(cctxt->ddl_handle,
-				&prop_hdr, &seq_hdr);
-			if (!VCD_FAILED(rc)) {
-				frm_entry->data_len =
-					seq_hdr.sequence_header_len;
-				frm_entry->time_stamp = 0;
-				frm_entry->flags |=
-					VCD_FRAME_FLAG_CODECCONFIG;
+			/*
+			 * The seq. header is stored in a seperate internal
+			 * buffer and is memcopied into the output buffer
+			 * that we provide.  In secure sessions, we aren't
+			 * allowed to touch these buffers.  In these cases
+			 * seq. headers are returned to client as part of
+			 * I-frames. So for secure session, just return
+			 * empty buffer.
+			 */
+			if (!cctxt->secure) {
+				prop_hdr.prop_id = VCD_I_SEQ_HEADER;
+				prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
+				seq_hdr.sequence_header = frm_entry->virtual;
+				seq_hdr.sequence_header_len =
+					frm_entry->alloc_len;
+				rc = ddl_get_property(cctxt->ddl_handle,
+						&prop_hdr, &seq_hdr);
+				if (!VCD_FAILED(rc)) {
+					frm_entry->data_len =
+						seq_hdr.sequence_header_len;
+					frm_entry->time_stamp = 0;
+					frm_entry->flags |=
+						VCD_FRAME_FLAG_CODECCONFIG;
+				} else
+					VCD_MSG_ERROR("rc = 0x%x. Failed:"
+							"ddl_get_property: VCD_I_SEQ_HEADER",
+							rc);
+			} else {
+				/*
+				 * First check that the proper props are enabled
+				 * so  client can get the proper info eventually
+				 */
+				prop_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+				prop_hdr.sz = sizeof(idr_enable);
+				rc = ddl_get_property(cctxt->ddl_handle,
+						&prop_hdr, &idr_enable);
+				if (!VCD_FAILED(rc)) {
+					if (!idr_enable.
+						sps_pps_for_idr_enable_flag) {
+						VCD_MSG_ERROR("SPS/PPS per IDR "
+							"needs to be enabled");
+						rc = VCD_ERR_BAD_STATE;
+					} else {
+						/* Send zero len frame */
+						frm_entry->data_len = 0;
+						frm_entry->time_stamp = 0;
+						frm_entry->flags = 0;
+					}
+				}
+
+			}
+
+			if (!VCD_FAILED(rc))
 				cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE,
-					VCD_S_SUCCESS, frm_entry,
-					sizeof(struct vcd_frame_data),
-					cctxt,
-					cctxt->client_data);
-			} else
-			VCD_MSG_ERROR(
-				"rc = 0x%x. Failed:\
-				ddl_get_property: VCD_I_SEQ_HEADER",
-				rc);
+						VCD_S_SUCCESS, frm_entry,
+						sizeof(struct vcd_frame_data),
+						cctxt,
+						cctxt->client_data);
 		} else
 			VCD_MSG_LOW("Codec Type is H.263\n");
 	} else
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index e50a054..537960b 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -52,7 +52,7 @@
 #define APQ8030_TOOLS_ID	4079
 #define MSM8627_TOOLS_ID	4080
 #define MSM8227_TOOLS_ID	4081
-#define MSM8974_TOOLS_ID	4072
+#define MSM8974_TOOLS_ID	4083
 
 #define MSG_MASK_0			(0x00000001)
 #define MSG_MASK_1			(0x00000002)
diff --git a/include/linux/i2c/isa1200.h b/include/linux/i2c/isa1200.h
index 4c36d59..9dab3eb 100644
--- a/include/linux/i2c/isa1200.h
+++ b/include/linux/i2c/isa1200.h
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2012, 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 as
@@ -55,6 +55,7 @@
 	u8 num_regulators;
 	int (*power_on)(int on);
 	int (*dev_setup)(bool on);
+	int (*clk_enable)(bool on);
 };
 
 #endif /* __LINUX_ISA1200_H */
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 7525e38..b693b75 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -84,6 +84,7 @@
 extern void memblock_enforce_memory_limit(phys_addr_t memory_limit);
 extern int memblock_is_memory(phys_addr_t addr);
 extern int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
+extern int memblock_overlaps_memory(phys_addr_t base, phys_addr_t size);
 extern int memblock_is_reserved(phys_addr_t addr);
 extern int memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
 
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index b883ffa..baa6a28 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
 	MSM_VIDC_MAX_DEVICES,
 };
 
-void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type);
 int msm_vidc_close(void *instance);
 int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
@@ -38,10 +38,12 @@
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
 #endif
diff --git a/include/sound/snd_compress_params.h b/include/sound/snd_compress_params.h
index e9f6748..f1e3ea2 100644
--- a/include/sound/snd_compress_params.h
+++ b/include/sound/snd_compress_params.h
@@ -72,6 +72,7 @@
 #define SND_AUDIOCODEC_AC3		     ((__u32) 0x0000000E)
 #define SND_AUDIOCODEC_DTS		     ((__u32) 0x0000000F)
 #define SND_AUDIOCODEC_AC3_PASS_THROUGH		((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO               ((__u32) 0x000000011)
 /*
  * Profile and modes are listed with bit masks. This allows for a
  * more compact representation of fields that will not evolve
diff --git a/mm/memblock.c b/mm/memblock.c
index 5338237..b7abce5 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -720,6 +720,12 @@
 		 memblock.memory.regions[idx].size) >= end;
 }
 
+int __init_memblock memblock_overlaps_memory(phys_addr_t base, phys_addr_t size)
+{
+	memblock_cap_size(base, &size);
+	return memblock_overlaps_region(&memblock.memory, base, size) >= 0;
+}
+
 int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
 {
 	memblock_cap_size(base, &size);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2d5eab2..cad9907 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1741,6 +1741,10 @@
 		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
 		tabla_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+		/* bandgap mode becomes fast,
+		 * mclk should be off or clk buff source souldn't be VBG
+		 * Let's turn off mclk always */
+		WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
 			0x2);
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -1770,9 +1774,10 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	pr_debug("%s\n", __func__);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
-	ndelay(160);
+	usleep_range(50, 50);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+	usleep_range(50, 50);
 	tabla->clock_active = false;
 }
 
@@ -1813,21 +1818,23 @@
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+		/* bandgap mode to fast */
 		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
 		usleep_range(5, 5);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
-			0x80);
+				    0x80);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
-			0x80);
+				    0x80);
 		usleep_range(10, 10);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
-		usleep_range(20, 20);
+		usleep_range(10000, 10000);
 		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
 	} else {
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
-			0);
+				    0);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+		/* clk source to ext clk and clk buff ref to VBG */
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
 	}
 	tabla->config_mode_active = enable ? true : false;
 
@@ -1835,29 +1842,32 @@
 }
 
 static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
-	int config_mode)
+					  int config_mode)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
 
+	/* transit to RCO requires mclk off */
+	WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
 	if (config_mode) {
+		/* enable RCO and switch to it */
 		tabla_codec_enable_config_mode(codec, 1);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
 		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
 		usleep_range(1000, 1000);
-	} else
+	} else {
+		/* switch to MCLK */
 		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
 
-	if (!config_mode && tabla->mbhc_polling_active) {
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		tabla_codec_enable_config_mode(codec, 0);
-
+		if (tabla->mbhc_polling_active) {
+			snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+			tabla_codec_enable_config_mode(codec, 0);
+		}
 	}
 
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+	/* on MCLK */
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
 	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
 	usleep_range(50, 50);
@@ -3689,16 +3699,18 @@
 	if (mclk_enable) {
 		tabla->mclk_enabled = true;
 
-		if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
+		if (tabla->mbhc_polling_active) {
 			tabla_codec_pause_hs_polling(codec);
+			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_AUDIO_MODE);
+						   TABLA_BANDGAP_AUDIO_MODE);
 			tabla_codec_enable_clock_block(codec, 0);
 			tabla_codec_calibrate_hs_polling(codec);
 			tabla_codec_start_hs_polling(codec);
 		} else {
+			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_AUDIO_MODE);
+						   TABLA_BANDGAP_AUDIO_MODE);
 			tabla_codec_enable_clock_block(codec, 0);
 		}
 	} else {
@@ -3712,21 +3724,20 @@
 		tabla->mclk_enabled = false;
 
 		if (tabla->mbhc_polling_active) {
-			if (!tabla->mclk_enabled) {
-				tabla_codec_pause_hs_polling(codec);
-				tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_MBHC_MODE);
-				tabla_enable_rx_bias(codec, 1);
-				tabla_codec_enable_clock_block(codec, 1);
-				tabla_codec_calibrate_hs_polling(codec);
-				tabla_codec_start_hs_polling(codec);
-			}
+			tabla_codec_pause_hs_polling(codec);
+			tabla_codec_disable_clock_block(codec);
+			tabla_codec_enable_bandgap(codec,
+						   TABLA_BANDGAP_MBHC_MODE);
+			tabla_enable_rx_bias(codec, 1);
+			tabla_codec_enable_clock_block(codec, 1);
+			tabla_codec_calibrate_hs_polling(codec);
+			tabla_codec_start_hs_polling(codec);
 			snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
 					0x05, 0x01);
 		} else {
 			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-				TABLA_BANDGAP_OFF);
+						   TABLA_BANDGAP_OFF);
 		}
 	}
 	if (dapm)
@@ -3852,6 +3863,7 @@
 		tx_slot[0] = tx_ch[cnt];
 		tx_slot[1] = tx_ch[1 + cnt];
 		tx_slot[2] = tx_ch[5 + cnt];
+		tx_slot[3] = tx_ch[3 + cnt];
 	} else if (dai->id == AIF3_CAP) {
 		*tx_num = tabla_dai[dai->id - 1].capture.channels_max;
 		tx_slot[cnt] = tx_ch[2 + cnt];
@@ -4569,7 +4581,7 @@
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
-	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -4762,6 +4774,7 @@
 	}
 
 	if (!tabla->mclk_enabled) {
+		tabla_codec_disable_clock_block(codec);
 		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
 		tabla_enable_rx_bias(codec, 1);
 		tabla_codec_enable_clock_block(codec, 1);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 776337d..68f218f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -192,6 +192,7 @@
 	struct msm_audio *prtd = &compr->prtd;
 	struct asm_aac_cfg aac_cfg;
 	struct asm_wma_cfg wma_cfg;
+	struct asm_wmapro_cfg wma_pro_cfg;
 	int ret;
 
 	pr_debug("compressed stream prepare\n");
@@ -250,6 +251,26 @@
 		if (ret < 0)
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
+	case SND_AUDIOCODEC_WMA_PRO:
+		pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+		memset(&wma_pro_cfg, 0x0, sizeof(struct asm_wmapro_cfg));
+		wma_pro_cfg.format_tag = compr->info.codec_param.codec.format;
+		wma_pro_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
+		wma_pro_cfg.sample_rate = runtime->rate;
+		wma_pro_cfg.avg_bytes_per_sec =
+			compr->info.codec_param.codec.bit_rate/8;
+		wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
+		wma_pro_cfg.valid_bits_per_sample =
+		compr->info.codec_param.codec.options.wma.bits_per_sample;
+		wma_pro_cfg.ch_mask =
+			compr->info.codec_param.codec.options.wma.channelmask;
+		wma_pro_cfg.encode_opt =
+			compr->info.codec_param.codec.options.wma.encodeopt;
+		ret = q6asm_media_format_block_wmapro(prtd->audio_client,
+				&wma_pro_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -316,6 +337,7 @@
 	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
 	compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
+	compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_WMA_PRO;
 	/* Add new codecs here */
 }
 
@@ -638,6 +660,10 @@
 			pr_debug("SND_AUDIOCODEC_WMA\n");
 			compr->codec = FORMAT_WMA_V9;
 			break;
+		case SND_AUDIOCODEC_WMA_PRO:
+			pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+			compr->codec = FORMAT_WMA_V10PRO;
+			break;
 		default:
 			pr_debug("FORMAT_LINEAR_PCM\n");
 			compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 3333344..dfb090e 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -38,6 +38,46 @@
 	union afe_port_config port_config;
 };
 
+static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+	dai_data->port_config.hdmi_multi_ch.data_type = value;
+	pr_debug("%s: value = %d\n", __func__, value);
+	return 0;
+}
+
+static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+	ucontrol->value.integer.value[0] =
+		dai_data->port_config.hdmi_multi_ch.data_type;
+	return 0;
+}
+
+
+/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
+ *  0: linear PCM
+ *  1: non-linear PCM
+ */
+static const char *hdmi_format[] = {
+	"LPCM",
+	"Compr"
+};
+
+static const struct soc_enum hdmi_config_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, hdmi_format),
+};
+
+static const struct snd_kcontrol_new hdmi_config_controls[] = {
+	SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
+				 msm_dai_q6_hdmi_format_get,
+				 msm_dai_q6_hdmi_format_put),
+};
 
 /* Current implementation assumes hw_param is called once
  * This may not be the case but what to do when ADM and AFE
@@ -54,7 +94,6 @@
 
 	dai_data->channels = params_channels(params);
 	dai_data->rate = params_rate(params);
-	dai_data->port_config.hdmi_multi_ch.data_type = 0;
 	dai_data->port_config.hdmi_multi_ch.reserved = 0;
 
 	switch (dai_data->channels) {
@@ -78,9 +117,11 @@
 		return -EINVAL;
 	}
 	dev_dbg(dai->dev, "%s() num_ch = %u rate =%u"
-		" channel_allocation = %u\n", __func__, dai_data->channels,
+		" channel_allocation = %u data type = %d\n", __func__,
+		dai_data->channels,
 		dai_data->rate,
-		dai_data->port_config.hdmi_multi_ch.channel_allocation);
+		dai_data->port_config.hdmi_multi_ch.channel_allocation,
+		dai_data->port_config.hdmi_multi_ch.data_type);
 
 	return 0;
 }
@@ -168,6 +209,7 @@
 static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
 {
 	struct msm_dai_q6_hdmi_dai_data *dai_data;
+	const struct snd_kcontrol_new *kcontrol;
 	int rc = 0;
 
 	dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
@@ -180,6 +222,10 @@
 	} else
 		dev_set_drvdata(dai->dev, dai_data);
 
+	kcontrol = &hdmi_config_controls[0];
+
+	rc = snd_ctl_add(dai->card->snd_card,
+					 snd_ctl_new1(kcontrol, dai_data));
 	return rc;
 }