Merge "defconfig: remove support for /dev/mem and /dev/kmem on perf builds"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 3947f75..15b94ca 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -43,6 +43,29 @@
 - qcpm,cpu-sensors:     List of type names in thermal zone device struct which maps
 			to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
 			cpus there are.
+- qcom,freq-mitigation-temp: Threshold temperature to mitigate
+			the CPU max frequency in degC. This will be
+			used when polling based frequency control is disabled.
+			The difference between freq-mitigation-temp
+			and limit-temp is that limit-temp is used during
+			early boot prior to thermal_sys being available for registering
+			temperature thresholds. Also, this emergency frequency
+			mitigation is a single step frequency mitigation to a predefined value
+			as opposed to the step by step frequency mitigation during boot-up.
+- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
+			cpu max frequency.
+- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
+			should mitigate the CPU, when the freq-mitigation-temp
+			threshold is reached.
+- qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be
+			used to determine if KTM should do emergency frequency
+			mitigation for a core or not. A mask of 0x00 indicates the
+			mitigation is disabled for all the cores and a mask of 0x05
+			indicates this mitigation is enabled for cpu-0 and cpu-2.
+			Note: For KTM's frequency mitigation to work, the data for all the
+			above four properties (qcom,freq-mitigation-temp; qcom,
+			freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and
+			qcom,freq-mitigation-control-mask) should be populated.
 - qcom,vdd-restriction-temp: When temperature is below this threshold, will
 			enable vdd restriction which will set higher voltage on
 			key voltage rails, in degC.
@@ -67,6 +90,20 @@
 			phandle_of_regulator is defined by reuglator device tree.
 
 Optional child nodes
+- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
+			dual phase) for rails with PMIC, in degC. If this property exists,
+			then the properties, qti,pmic-opt-curr-temp-hysteresis and
+			qti,pmic-opt-curr-regs should also be defined to enable this
+			feature.
+- qti,pmic-opt-curr-temp-hysteresis: Degree below the threshold to disable the optimum
+			current request for a rail, in degC. If this property exists,
+			then the properties, qti,pmic-opt-curr-temp and
+			qti,pmic-opt-curr-regs should also be defined to enable
+			this feature.
+- qti,pmic-opt-curr-regs: Name of the rails for which the optimum current should be
+			requested. If this property exists, then the properties,
+			qti,pmic-opt-curr-temp and qti,pmic-opt-curr-temp-hysteresis
+			should also be defined to enable this feature.
 - qcom,<vdd restriction child node name>: Define the name of the child node.
 			If this property exisits, qcom,vdd-rstr-reg, qcom,levels
 			need to exist. qcom,min-level is optional if qcom,freq-req
@@ -97,11 +134,18 @@
 		qcom,hotplug-temp-hysteresis = <20>;
 		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
 				"tsens_tz_sensor7", "tsens_tz_sensor8";
+		qcom,freq-mitigation-temp = <110>;
+		qcom,freq-mitigation-temp-hysteresis = <20>;
+		qcom,freq-mitigation-value = <960000>;
+		qcom,freq-mitigation-control-mask = <0x01>;
 		qcom,pmic-sw-mode-temp = <90>;
 		qcom,pmic-sw-mode-temp-hysteresis = <80>;
 		qcom,pmic-sw-mode-regs = "vdd-dig";
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
+		qti,pmic-opt-curr-temp = <85>;
+		qti,pmic-opt-curr-temp-hysteresis = <10>;
+		qti,pmic-opt-curr-regs = "vdd-dig";
 		vdd-dig-supply=<&pm8841_s2_floor_corner>
 
 		qcom,vdd-dig-rstr{
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 56bdc59..a77b5ff 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -102,6 +102,12 @@
 
  - compatible : "qcom,msm-lsm-client"
 
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qti,msm-pcm-loopback"
+
 * msm-dai-q6
 
 [First Level Nodes]
diff --git a/Makefile b/Makefile
index be32c2f..0c11d69 100644
--- a/Makefile
+++ b/Makefile
@@ -864,6 +864,7 @@
 # Generate .S file with all kernel symbols
 quiet_cmd_kallsyms = KSYM    $@
       cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+                     --page-offset=$(CONFIG_PAGE_OFFSET) \
                      $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
 
 .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 8c79bb9..25e5072 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -17,7 +17,7 @@
  *---------------------------------------------------------------------------*/
 &mdss_mdp {
 	dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
-		qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "hx8389b qhd video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
 		qcom,mdss-dsi-panel-destination = "display_1";
@@ -26,89 +26,35 @@
 		qcom,mdss-dsi-stream = <0>;
 		qcom,mdss-dsi-panel-width = <540>;
 		qcom,mdss-dsi-panel-height = <960>;
-		qcom,mdss-dsi-h-front-porch = <48>;
-		qcom,mdss-dsi-h-back-porch = <96>;
-		qcom,mdss-dsi-h-pulse-width = <96>;
+		qcom,mdss-dsi-h-front-porch = <60>;
+		qcom,mdss-dsi-h-back-porch = <39>;
+		qcom,mdss-dsi-h-pulse-width = <39>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <13>;
 		qcom,mdss-dsi-v-front-porch = <9>;
 		qcom,mdss-dsi-v-pulse-width = <3>;
-		qcom,mdss-dsi-v-back-porch = <13>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
-		qcom,mdss-dsi-on-command = [
-				39 01 00 00 00 00 04
-					B9 FF 83 89
-				39 01 00 00 00 00 08
-					BA 41 93 00
-					16 A4 10 18
-				23 01 00 00 00 00 02
-					C6 08
-				39 01 00 00 00 00 03
-					BC 02 00
-				23 01 00 00 00 00 02
-					CC 02
-				39 01 00 00 00 00 14
-					B1 00 00 07
-					E8 50 10 11
-					98 f8 21 29
-					27 27 43 01
-					58 F0 00 E6
-				39 01 00 00 00 00 08
-					B2 00 00 78
-					0C 07 3F 80
-				39 01 00 00 00 00 18
-					b4 82 08 00
-					32 10 04 32
-					10 00 32 10
-					00 37 0a 40
-					08 37 0a 40
-					14 46 50 0a
-				39 01 00 00 00 00 39
-					d5 00 00 00
-					00 01 00 00
-					00 60 00 99
-					88 AA BB 88
-					23 88 01 88
-					67 88 45 01
-					23 88 88 88
-					88 88 88 99
-					BB AA 88 54
-					88 76 88 10
-					88 32 32 10
-					88 88 88 88
-					88 00 04 00
-					00 00 00 00
-					00
-				39 01 00 00 00 00 03
-					CB 07 07
-				39 01 00 00 00 00 05
-					BB 00 00 FF
-					80
-				39 01 00 00 00 00 04
-					DE 05 58 10
-				39 01 00 00 00 00 05
-					B6 00 8A 00
-					8A
-				39 01 00 00 00 00 23
-					E0 01 08 0C
-					1F 25 36 12
-					35 05 09 0D
-					10 11 0F 0F
-					1C 1D 01 08
-					0C 1F 25 36
-					12 35 05 09
-					0D 10 11 0F
-					0F 1C 1D
-				05 01 00 00 96 00 02
-					11 00
-				05 01 00 00 96 00 02
-					29 00
-		];
+		qcom,mdss-dsi-on-command = [39 01 00 00 0A 00 04 B9 FF 83 89
+				15 01 00 00 01 00 02 CC 02
+				39 01 00 00 01 00 03 C0 43 17
+				39 01 00 00 01 00 08 BA 41 93 00 16 A4 10 18
+				39 01 00 00 01 00 14 B1 00 00 06 EB 59 10 11 EE EE 3A 42 3F 3F 43 01 5A F6 00 E6
+				39 01 00 00 01 00 08 B2 00 00 78 0C 07 3F 80
+				39 01 00 00 01 00 04 b7 00 00 50
+				39 01 00 00 01 00 18 B4 80 08 00 32 10 04 32 10 00 32 10 00 37 0a 40 08 37 00 46 02 58 58 02
+				39 01 00 00 01 00 39 D5 00 00 00 00 01 00 00 00 60 00 99 88 AA BB 88 23 88 01 88 67 88 45 01 23 88 88 88 88 88 88 99 BB AA 88 54 88 76 88 10 88 32 32 10 88 88 88 88 88 3C 04 00 00 00 00 00 00
+				39 01 00 00 01 00 23 E0 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18
+				39 01 00 00 05 00 80 C1 01 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0
+				39 01 00 00 01 00 05 B6 00 88 00 88
+				05 01 00 00 78 00 02 11 00
+				05 01 00 00 32 00 02 29 00];
 		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
 					05 01 00 00 78 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
@@ -120,7 +66,7 @@
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
-		qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+		qcom,mdss-dsi-panel-timings = [87 1E 14 00 44 4B 19 21 22 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x04>;
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <26>;
@@ -129,6 +75,5 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
-
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 38ca03b..a1a8480 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -160,7 +160,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index a0da9cc..2e9f6db 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -162,7 +162,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index d63c6e5..04eca14 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -143,7 +143,11 @@
 			"MIC BIAS External", "Handset Mic",
 			"MIC BIAS Internal2", "Headset Mic",
 			"AMIC1", "MIC BIAS External",
-			"AMIC2", "MIC BIAS Internal2";
+			"AMIC2", "MIC BIAS Internal2",
+			"MIC BIAS External", "Digital Mic1",
+			"MIC BIAS External", "Digital Mic2",
+			"DMIC1", "MIC BIAS External",
+			"DMIC2", "MIC BIAS External";
 		qcom,headset-jack-type-NC;
     };
 };
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index e5aa53c..ea37413 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -160,7 +160,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index c819c49..19fb185 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -162,7 +162,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
@@ -198,24 +198,40 @@
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
 			<41 63>,  /* dino_gen_purpose_irq35 */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
-			<0xff 162>, /* lpass_irq_out_spare[5]*/
-			<0xff 234>, /* lpass_irq_out_spare[6]*/
-			<0xff 235>, /* lpass_irq_out_spare[7]*/
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -230,12 +246,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 2ff92ed..b4a3e55 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1684,6 +1684,10 @@
 		compatible = "qcom,msm-lsm-client";
 	};
 
+	qti,msm-pcm-loopback {
+		compatible = "qti,msm-pcm-loopback";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -2179,6 +2183,10 @@
 		qcom,hotplug-temp-hysteresis = <20>;
 		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
 				"tsens_tz_sensor7", "tsens_tz_sensor8";
+		qcom,freq-mitigation-temp = <110>;
+		qcom,freq-mitigation-temp-hysteresis = <20>;
+		qcom,freq-mitigation-value = <960000>;
+		qcom,freq-mitigation-control-mask = <0x01>;
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		qcom,pmic-sw-mode-temp = <85>;
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 366faef..938a2cc 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -214,6 +214,7 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 33>, /*l2_perf_mon*/
 			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
 			<0xff 40>,  /* qtimer_phy_irq */
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index 2693642..71fbeae 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -152,6 +152,9 @@
 	qcom,msm-thermal {
 		vdd-dig-supply = <&pma8084_s2_floor_corner>;
 		vdd-gfx-supply = <&pma8084_s7_floor_corner>;
+		qti,pmic-opt-curr-temp = <85>;
+		qti,pmic-opt-curr-temp-hysteresis = <10>;
+		qti,pmic-opt-curr-regs = "vdd-dig";
 		/delete-property/ qcom,pmic-sw-mode-temp;
 		/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
 		/delete-property/ qcom,pmic-sw-mode-regs;
@@ -180,6 +183,10 @@
 	qcom,use-phase-switching;
 };
 
+&mdss_mdp {
+	vdd-cx-supply = <&pma8084_s2_corner>;
+};
+
 &tspp {
 	vdd_cx-supply = <&pma8084_s2_corner>;
 };
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 14ddc4e..1e32cfa 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -457,7 +457,6 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
 CONFIG_MSM_RDBG=m
 CONFIG_DEVMEM=n
 CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index f672cc0..cedb6dc 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -511,5 +511,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
 CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index a779688..939dc82 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -320,6 +320,7 @@
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
 CONFIG_FB_MSM_MDSS_WRITEBACK=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 0a48930..ff0c498 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -343,6 +343,7 @@
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
 CONFIG_FB_MSM_MDSS_WRITEBACK=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 97f5532..10f2919 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,6 +98,7 @@
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c106913..0b9ba76 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -104,6 +104,7 @@
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 03f8837..affe6bd 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -631,6 +631,28 @@
 	},
 };
 
+static struct gpiomux_setting gpio_cdc_dmic_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_4MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_cdc_dmic_configs[] __initdata = {
+	{
+		.gpio = 100,	/* DMIC CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+		},
+	},
+	{
+		.gpio = 101,	/* DMIC DATA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -668,4 +690,7 @@
 		msm_gpiomux_install(msm_non_qrd_configs,
 			ARRAY_SIZE(msm_non_qrd_configs));
 	}
+	if (of_board_is_cdp())
+		msm_gpiomux_install(msm_cdc_dmic_configs,
+			ARRAY_SIZE(msm_cdc_dmic_configs));
 }
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index fac6575..a910cd26 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -63,9 +63,13 @@
 	if (!dev)
 		return -ENODEV;
 
+	/* Add check for user buf count greater than RD_BUF_SIZE */
+	if (count > RD_BUF_SIZE)
+		count = RD_BUF_SIZE;
+
 	if (copy_from_user(dev->buf, ubuf, count)) {
 		pr_err("error copying for writing");
-		return 0;
+		return -EFAULT;
 	}
 
 	ret = hsic_sysmon_write(id, dev->buf, count, 1000);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 2e15cae..9a27fd2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -73,7 +73,8 @@
 #define USF_TSC_PTR_EVENT_IND  1
 #define USF_MOUSE_EVENT_IND    2
 #define USF_KEYBOARD_EVENT_IND 3
-#define USF_MAX_EVENT_IND      4
+#define USF_TSC_EXT_EVENT_IND  4
+#define USF_MAX_EVENT_IND      5
 
 /* Types of events, produced by the calculators */
 #define USF_NO_EVENT 0
@@ -81,10 +82,12 @@
 #define USF_TSC_PTR_EVENT  (1 << USF_TSC_PTR_EVENT_IND)
 #define USF_MOUSE_EVENT    (1 << USF_MOUSE_EVENT_IND)
 #define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT  (1 << USF_TSC_EXT_EVENT_IND)
 #define USF_ALL_EVENTS         (USF_TSC_EVENT |\
 				USF_TSC_PTR_EVENT |\
 				USF_MOUSE_EVENT |\
-				USF_KEYBOARD_EVENT)
+				USF_KEYBOARD_EVENT |\
+				USF_TSC_EXT_EVENT)
 
 /* min, max array dimension */
 #define MIN_MAX_DIM 2
@@ -146,6 +149,8 @@
 	int tsc_y_tilt[MIN_MAX_DIM];
 	/* Touch screen pressure limits: min & max; for input module */
 	int tsc_pressure[MIN_MAX_DIM];
+	/* The requested side buttons bitmap */
+	uint16_t req_side_buttons_bitmap;
 	/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
 	uint16_t event_types;
 	/* Input event source */
@@ -174,6 +179,8 @@
 	int inclinations[TILTS_DIM];
 /* [0-1023] (10bits); 0 - pen up */
 	uint32_t pressure;
+/* Bitmap for side button state. 1 - down, 0 - up */
+	uint16_t side_buttons_state_bitmap;
 };
 
 /* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index b707df1..b9dcf88 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -291,7 +291,7 @@
 			system_level->num_cpu_votes != num_powered_cores)
 			continue;
 
-		if (latency_us < pwr_param->latency_us)
+		if (latency_us < pwr_param->latency_us && from_idle)
 			continue;
 
 		if (sleep_us < pwr_param->time_overhead_us)
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index ac4ed25..c4e52be 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -36,72 +36,132 @@
 	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
 };
 
+static struct msm_pm_time_stats suspend_stats;
+
 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.
+ *  Function to update stats
  */
-void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+static void update_stats(struct msm_pm_time_stats *stats, 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)
+		return;
 
-	if (!stats[id].enabled)
-		goto add_bail;
-
-	stats[id].total_time += t;
-	stats[id].count++;
+	stats->total_time += t;
+	stats->count++;
 
 	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
+	do_div(bt, stats->first_bucket_time);
 
 	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+			(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
 		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+			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]++;
+	stats->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;
+	if (t < stats->min_time[i] || !stats->max_time[i])
+		stats->min_time[i] = t;
+	if (t > stats->max_time[i])
+		stats->max_time[i] = t;
+}
 
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	struct msm_pm_time_stats *stats;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	if (id == MSM_PM_STAT_SUSPEND) {
+		stats = &suspend_stats;
+	} else {
+		stats = __get_cpu_var(msm_pm_stats).stats;
+		if (!stats[id].enabled)
+			goto add_bail;
+		stats = &stats[id];
+	}
+	update_stats(stats, t);
 add_bail:
 	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 }
 
-/*
- * Write out the power management statistics.
- */
-
-static int msm_pm_stats_show(struct seq_file *m, void *v)
+static void stats_show(struct seq_file *m,
+		struct msm_pm_time_stats *stats,
+		int cpu, int suspend)
 {
-	int cpu;
+	int64_t bucket_time;
+	int64_t s;
+	uint32_t ns;
+	int i;
 	int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
 	int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
 
-	for_each_possible_cpu(cpu) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i, id;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
+	if (!stats || !m)
+		return;
 
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	s = stats->total_time;
+	ns = do_div(s, NSEC_PER_SEC);
+	if (suspend)
+		seq_printf(m,
+			"%s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			stats->name,
+			stats->count,
+			s, ns);
+	else
+		seq_printf(m,
+			"[cpu %u] %s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			cpu, stats->name,
+			stats->count,
+			s, ns);
+
+	bucket_time = stats->first_bucket_time;
+	for (i = 0; i < bucket_count; i++) {
+		s = bucket_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		seq_printf(m,
+			"   <%6lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, stats->bucket[i],
+			stats->min_time[i],
+			stats->max_time[i]);
+			bucket_time <<= bucket_shift;
+	}
+
+	seq_printf(m, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
+		s, ns, stats->bucket[i],
+		stats->min_time[i],
+		stats->max_time[i]);
+}
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_stats_show(struct seq_file *m, void *v)
+{
+	int cpu;
+	int id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats;
+
 		stats = per_cpu(msm_pm_stats, cpu).stats;
 
 		for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
@@ -109,38 +169,14 @@
 			if (!stats[id].enabled)
 				continue;
 
-			s = stats[id].total_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			seq_printf(m,
-				"[cpu %u] %s:\n"
-				"  count: %7d\n"
-				"  total_time: %lld.%09u\n",
-				cpu, stats[id].name,
-				stats[id].count,
-				s, ns);
+			if (id == MSM_PM_STAT_SUSPEND)
+				continue;
 
-			bucket_time = stats[id].first_bucket_time;
-			for (i = 0; i < bucket_count; i++) {
-				s = bucket_time;
-				ns = do_div(s, NSEC_PER_SEC);
-				seq_printf(m,
-					"   <%6lld.%09u: %7d (%lld-%lld)\n",
-					s, ns, stats[id].bucket[i],
-					stats[id].min_time[i],
-					stats[id].max_time[i]);
-
-				bucket_time <<= bucket_shift;
-			}
-
-			seq_printf(m, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
+			stats_show(m, &stats[id], cpu, false);
 		}
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 	}
-
+	stats_show(m, &suspend_stats, cpu, true);
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 	return 0;
 }
 
@@ -259,14 +295,6 @@
 			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;
@@ -275,6 +303,9 @@
 			stats[enable_stats[i]].enabled = true;
 
 	}
+	suspend_stats.name = "system_suspend";
+	suspend_stats.first_bucket_time =
+		CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
 
 	d_entry = proc_create_data("msm_pm_stats", S_IRUGO | S_IWUSR | S_IWGRP,
 			NULL, &msm_pm_stats_fops, NULL);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index bf47366..7ab4ec3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -26,6 +26,8 @@
 #define FORMAT_USPS_EPOS	0x00000000
 #define FORMAT_USRAW		0x00000001
 #define FORMAT_USPROX		0x00000002
+#define FORMAT_USGES_SYNC	0x00000003
+#define FORMAT_USRAW_SYNC	0x00000004
 #define INVALID_FORMAT		0xffffffff
 
 #define IN			0x000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..e6b1324 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
 #include "usfcdev.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.4.2"
-#define USF_VERSION_ID 0x0142
+#define DRV_VERSION "1.5.1"
+#define USF_VERSION_ID 0x0151
 
 /* Standard timeout in the asynchronous ops */
 #define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -57,6 +57,8 @@
 /* Place for US detection result, received from QDSP6 */
 #define APR_US_DETECT_RESULT_IND 0
 
+#define BITS_IN_BYTE 8
+
 /* The driver states */
 enum usf_state_type {
 	USF_IDLE_STATE,
@@ -117,6 +119,8 @@
 	uint16_t conflicting_event_types;
 	/* Bitmap of types of events from devs, conflicting with USF */
 	uint16_t conflicting_event_filters;
+	/* The requested side buttons bitmap */
+	uint16_t req_side_buttons_bitmap;
 };
 
 struct usf_input_dev_type {
@@ -146,6 +150,12 @@
 	0,            /* US_INPUT_SRC_UNDEF */
 };
 
+/* Supported buttons container */
+static const int s_button_map[] = {
+	BTN_STYLUS,
+	BTN_STYLUS2
+};
+
 /* The opened devices container */
 static int s_opened_devs[MAX_DEVS_NUMBER];
 
@@ -176,14 +186,35 @@
 				struct us_input_info_type *input_info,
 				const char *name)
 {
+	int i = 0;
+	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(input_info->req_side_buttons_bitmap) *
+		BITS_IN_BYTE);
+	uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
 	struct input_dev *in_dev = allocate_dev(ind, name);
-
 	if (in_dev == NULL)
 		return -ENOMEM;
 
+	if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
+		pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+		__func__,
+		input_info->req_side_buttons_bitmap,
+		max_side_button_bitmap);
+		return -EINVAL;
+	}
+
 	usf_info->input_ifs[ind] = in_dev;
+	usf_info->req_side_buttons_bitmap =
+		input_info->req_side_buttons_bitmap;
 	in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+
+	for (i = 0; i < num_side_buttons; i++)
+		if (input_info->req_side_buttons_bitmap & (1 << i))
+			in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+			BIT_MASK(s_button_map[i]);
+
 	input_set_abs_params(in_dev, ABS_X,
 			     input_info->tsc_x_dim[MIN_IND],
 			     input_info->tsc_x_dim[MAX_IND],
@@ -260,6 +291,11 @@
 			     struct usf_event_type *event)
 
 {
+	int i = 0;
+	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(usf_info->req_side_buttons_bitmap) *
+		BITS_IN_BYTE);
+
 	struct input_dev *input_if = usf_info->input_ifs[if_ind];
 	struct point_event_type *pe = &(event->event_data.point_event);
 
@@ -273,19 +309,27 @@
 	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
 	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
 
+	for (i = 0; i < num_side_buttons; i++) {
+		uint16_t mask = (1 << i),
+		btn_state = !!(pe->side_buttons_state_bitmap & mask);
+		if (usf_info->req_side_buttons_bitmap & mask)
+			input_report_key(input_if, s_button_map[i], btn_state);
+	}
+
 	if (usf_info->event_src)
 		input_report_key(input_if, usf_info->event_src, 1);
 
 	input_sync(input_if);
 
-	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
 		 __func__,
 		 pe->coordinates[X_IND],
 		 pe->coordinates[Y_IND],
 		 pe->coordinates[Z_IND],
 		 pe->inclinations[X_IND],
 		 pe->inclinations[Y_IND],
-		 pe->pressure);
+		 pe->pressure,
+		 pe->side_buttons_state_bitmap);
 }
 
 static void notify_mouse_event(struct usf_type *usf_info,
@@ -338,6 +382,8 @@
 		prepare_mouse_input_device, notify_mouse_event},
 	{USF_KEYBOARD_EVENT, "usf_kb",
 		prepare_keyboard_input_device, notify_key_event},
+	{USF_TSC_EXT_EVENT, "usf_tsc_ext",
+		prepare_tsc_input_device, notify_tsc_event},
 };
 
 static void usf_rx_cb(uint32_t opcode, uint32_t token,
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index fe7c8c2..51a51c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -628,6 +628,12 @@
 	case FORMAT_USPROX:
 		int_format = US_PROX_FORMAT_V2;
 		break;
+	case FORMAT_USGES_SYNC:
+		int_format = US_GES_SYNC_FORMAT;
+		break;
+	case FORMAT_USRAW_SYNC:
+		int_format = US_RAW_SYNC_FORMAT;
+		break;
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
 		break;
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index cb8ed19..1447854 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -54,7 +54,7 @@
 	u32 num_records;
 	u32 read_idx;
 	u32 len;
-	char buf[256];
+	char buf[320];
 	struct msm_rpmstats_platform_data *platform_data;
 };
 
@@ -64,7 +64,8 @@
 	u64 last_entered_at;
 	u64 last_exited_at;
 	u64 accumulated;
-	u32 reserved[4];
+	u32 client_votes;
+	u32 reserved[3];
 };
 
 static inline u64 get_time_in_sec(u64 counter)
@@ -98,10 +99,12 @@
 	actual_last_sleep = get_time_in_msec(data->accumulated);
 
 	return  snprintf(buf , buflength,
-		"RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
-		"time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
+		"RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+		"time since last mode(sec):%llu\nactual last sleep(msec):%llu\n"
+		"client votes: %#010x\n\n",
 		stat_type, data->count, time_in_last_mode,
-		time_since_last_mode, actual_last_sleep);
+		time_since_last_mode, actual_last_sleep,
+		data->client_votes);
 }
 
 static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -147,6 +150,9 @@
 		data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
 				i, offsetof(struct msm_rpm_stats_data_v2,
 					accumulated));
+		data.client_votes = msm_rpmstats_read_long_register_v2(reg,
+				i, offsetof(struct msm_rpm_stats_data_v2,
+					client_votes));
 		length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
 				&data, sizeof(prvdata->buf) - length);
 		prvdata->read_idx++;
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index b6fbb3c2..cc8cf47 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -125,16 +125,38 @@
 	return n;
 }
 
+struct fastrpc_buf {
+	struct ion_handle *handle;
+	void *virt;
+	ion_phys_addr_t phys;
+	int size;
+	int used;
+};
+
+struct smq_context_list;
+
 struct smq_invoke_ctx {
+	struct hlist_node hn;
 	struct completion work;
 	int retval;
-	atomic_t free;
+	int pid;
+	remote_arg_t *pra;
+	remote_arg_t *rpra;
+	struct fastrpc_buf obuf;
+	struct fastrpc_buf *abufs;
+	struct fastrpc_device *dev;
+	struct fastrpc_apps *apps;
+	int *fds;
+	struct ion_handle **handles;
+	int nbufs;
+	bool smmu;
+	uint32_t sc;
 };
 
 struct smq_context_list {
-	struct smq_invoke_ctx *ls;
-	int size;
-	int last;
+	struct hlist_head pending;
+	struct hlist_head interrupted;
+	spinlock_t hlock;
 };
 
 struct fastrpc_smmu {
@@ -165,22 +187,16 @@
 	struct hlist_node hn;
 	struct ion_handle *handle;
 	void *virt;
+	ion_phys_addr_t phys;
 	uint32_t vaddrin;
 	uint32_t vaddrout;
 	int size;
 };
 
-struct fastrpc_buf {
-	struct ion_handle *handle;
-	void *virt;
-	ion_phys_addr_t phys;
-	int size;
-	int used;
-};
-
 struct file_data {
 	spinlock_t hlock;
 	struct hlist_head hlst;
+	uint32_t mode;
 };
 
 struct fastrpc_device {
@@ -214,6 +230,11 @@
 {
 	struct fastrpc_apps *me = &gfa;
 	if (!IS_ERR_OR_NULL(map->handle)) {
+		if (me->smmu.enabled && map->phys) {
+			ion_unmap_iommu(me->iclient, map->handle,
+					me->smmu.domain_id, 0);
+			map->phys = 0;
+		}
 		if (!IS_ERR_OR_NULL(map->virt)) {
 			ion_unmap_kernel(me->iclient, map->handle);
 			map->virt = 0;
@@ -263,65 +284,186 @@
 	return err;
 }
 
-static int context_list_ctor(struct smq_context_list *me, int size)
+static int context_restore_interrupted(struct fastrpc_apps *me,
+				struct fastrpc_ioctl_invoke_fd *invokefd,
+				struct smq_invoke_ctx **po)
 {
 	int err = 0;
-	VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
-	if (err)
-		goto bail;
-	me->size = size / sizeof(*me->ls);
-	me->last = 0;
- bail:
+	struct smq_invoke_ctx *ctx = 0, *ictx = 0;
+	struct hlist_node *pos, *n;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
+	spin_lock(&me->clst.hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &me->clst.interrupted, hn) {
+		if (ictx->pid == current->pid) {
+			if (invoke->sc != ictx->sc)
+				err = -1;
+			else {
+				ctx = ictx;
+				hlist_del(&ctx->hn);
+				hlist_add_head(&ctx->hn, &me->clst.pending);
+			}
+			break;
+		}
+	}
+	spin_unlock(&me->clst.hlock);
+	if (ctx)
+		*po = ctx;
 	return err;
 }
 
-static void context_list_dtor(struct smq_context_list *me)
+static int context_alloc(struct fastrpc_apps *me, uint32_t kernel,
+				struct fastrpc_ioctl_invoke_fd *invokefd,
+				struct smq_invoke_ctx **po)
 {
-	kfree(me->ls);
-}
+	int err = 0, bufs, size = 0;
+	struct smq_invoke_ctx *ctx = 0;
+	struct smq_context_list *clst = &me->clst;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
 
-static void context_list_alloc_ctx(struct smq_context_list *me,
-					struct smq_invoke_ctx **po)
-{
-	int i = me->last;
-	struct smq_invoke_ctx *ctx;
-
-	for (;;) {
-		i = i % me->size;
-		ctx = &me->ls[i];
-		if (atomic_read(&ctx->free) == 0)
-			if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
-				break;
-		i++;
+	bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+			REMOTE_SCALARS_OUTBUFS(invoke->sc);
+	if (bufs) {
+		size = bufs * sizeof(*ctx->pra);
+		if (invokefd->fds)
+			size = size + bufs * sizeof(*ctx->fds) +
+				bufs * sizeof(*ctx->handles);
 	}
-	me->last = i;
+
+	VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)));
+	if (err)
+		goto bail;
+
+	INIT_HLIST_NODE(&ctx->hn);
+	ctx->pra = (remote_arg_t *)(&ctx[1]);
+	ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]);
+	ctx->handles = invokefd->fds == 0 ? 0 :
+					(struct ion_handle **)(&ctx->fds[bufs]);
+	if (!kernel) {
+		VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra,
+					bufs * sizeof(*ctx->pra)));
+		if (err)
+			goto bail;
+	} else {
+		memmove(ctx->pra, invoke->pra, bufs * sizeof(*ctx->pra));
+	}
+
+	if (invokefd->fds) {
+		if (!kernel) {
+			VERIFY(err, 0 == copy_from_user(ctx->fds, invokefd->fds,
+						bufs * sizeof(*ctx->fds)));
+			if (err)
+				goto bail;
+		} else {
+			memmove(ctx->fds, invokefd->fds,
+						bufs * sizeof(*ctx->fds));
+		}
+	}
+	ctx->sc = invoke->sc;
 	ctx->retval = -1;
+	ctx->pid = current->pid;
+	ctx->apps = me;
 	init_completion(&ctx->work);
+	spin_lock(&clst->hlock);
+	hlist_add_head(&ctx->hn, &clst->pending);
+	spin_unlock(&clst->hlock);
+
 	*po = ctx;
+bail:
+	if (ctx && err)
+		kfree(ctx);
+	return err;
 }
 
-static void context_free(struct smq_invoke_ctx *me)
+static void context_save_interrupted(struct smq_invoke_ctx *ctx)
 {
-	if (me)
-		atomic_set(&me->free, 0);
+	struct smq_context_list *clst = &ctx->apps->clst;
+	spin_lock(&clst->hlock);
+	hlist_del(&ctx->hn);
+	hlist_add_head(&ctx->hn, &clst->interrupted);
+	spin_unlock(&clst->hlock);
 }
 
-static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev);
+
+static void context_free(struct smq_invoke_ctx *ctx, bool lock)
 {
-	me->retval = retval;
-	complete(&me->work);
+	struct smq_context_list *clst = &ctx->apps->clst;
+	struct fastrpc_apps *apps = ctx->apps;
+	struct ion_client *clnt = apps->iclient;
+	struct fastrpc_smmu *smmu = &apps->smmu;
+	struct fastrpc_buf *b;
+	int i, bufs;
+	if (ctx->smmu) {
+		bufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
+			REMOTE_SCALARS_OUTBUFS(ctx->sc);
+		if (ctx->fds) {
+			for (i = 0; i < bufs; i++)
+				if (!IS_ERR_OR_NULL(ctx->handles[i])) {
+					ion_unmap_iommu(clnt, ctx->handles[i],
+						smmu->domain_id, 0);
+					ion_free(clnt, ctx->handles[i]);
+				}
+		}
+		iommu_detach_group(smmu->domain, smmu->group);
+	}
+	for (i = 0, b = ctx->abufs; i < ctx->nbufs; ++i, ++b)
+		free_mem(b);
+
+	kfree(ctx->abufs);
+	if (ctx->dev) {
+		add_dev(apps, ctx->dev);
+		if (ctx->obuf.handle != ctx->dev->buf.handle)
+			free_mem(&ctx->obuf);
+	}
+	if (lock)
+		spin_lock(&clst->hlock);
+	hlist_del(&ctx->hn);
+	if (lock)
+		spin_unlock(&clst->hlock);
+	kfree(ctx);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *ctx, int retval)
+{
+	ctx->retval = retval;
+	complete(&ctx->work);
 }
 
 static void context_notify_all_users(struct smq_context_list *me)
 {
-	int i;
-
-	if (!me->ls)
-		return;
-	for (i = 0; i < me->size; ++i) {
-		if (atomic_read(&me->ls[i].free) != 0)
-			complete(&me->ls[i].work);
+	struct smq_invoke_ctx *ictx = 0;
+	struct hlist_node *pos, *n;
+	spin_lock(&me->hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &me->pending, hn) {
+		complete(&ictx->work);
 	}
+	hlist_for_each_entry_safe(ictx, pos, n, &me->interrupted, hn) {
+		complete(&ictx->work);
+	}
+	spin_unlock(&me->hlock);
+
+}
+
+static void context_list_ctor(struct smq_context_list *me)
+{
+	INIT_HLIST_HEAD(&me->interrupted);
+	INIT_HLIST_HEAD(&me->pending);
+	spin_lock_init(&me->hlock);
+}
+
+static void context_list_dtor(struct fastrpc_apps *me,
+				struct smq_context_list *clst)
+{
+	struct smq_invoke_ctx *ictx = 0;
+	struct hlist_node *pos, *n;
+	spin_lock(&clst->hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &clst->interrupted, hn) {
+		context_free(ictx, 0);
+	}
+	hlist_for_each_entry_safe(ictx, pos, n, &clst->pending, hn) {
+		context_free(ictx, 0);
+	}
+	spin_unlock(&clst->hlock);
 }
 
 static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
@@ -400,13 +542,12 @@
 static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
 			remote_arg_t *rpra, remote_arg_t *upra,
 			struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
-			int *nbufs, int *fds)
+			int *nbufs, int *fds, struct ion_handle **handles)
 {
 	struct fastrpc_apps *me = &gfa;
 	struct smq_invoke_buf *list;
 	struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
 	struct smq_phy_page *pages;
-	struct ion_handle **handles = NULL;
 	void *args;
 	int i, rlen, size, used, inh, bufs = 0, err = 0;
 	int inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -418,8 +559,6 @@
 	used = ALIGN(pbuf->used, BALIGN);
 	args = (void *)((char *)pbuf->virt + used);
 	rlen = pbuf->size - used;
-	if (fds)
-		handles = (struct ion_handle **)(fds + inbufs + outbufs);
 	for (i = 0; i < inbufs + outbufs; ++i) {
 
 		rpra[i].buf.len = pra[i].buf.len;
@@ -614,7 +753,6 @@
 	struct fastrpc_apps *me = &gfa;
 
 	smd_close(me->chan);
-	context_list_dtor(&me->clst);
 	ion_client_destroy(me->iclient);
 	me->iclient = 0;
 	me->chan = 0;
@@ -667,16 +805,14 @@
 		spin_lock_init(&me->wrlock);
 		init_completion(&me->work);
 		mutex_init(&me->smd_mutex);
+		context_list_ctor(&me->clst);
 		for (i = 0; i < RPC_HASH_SZ; ++i)
 			INIT_HLIST_HEAD(&me->htbl[i]);
-		VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
-		if (err)
-			goto context_list_bail;
 		me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
 							DEVICE_NAME);
 		VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
 		if (err)
-			goto ion_bail;
+			goto bail;
 		node = of_find_compatible_node(NULL, NULL,
 						"qcom,msm-audio-ion");
 		if (node)
@@ -697,9 +833,7 @@
 
 	return 0;
 
-ion_bail:
-	context_list_dtor(&me->clst);
-context_list_bail:
+bail:
 	return err;
 }
 
@@ -783,96 +917,88 @@
 
 static int fastrpc_release_current_dsp_process(void);
 
-static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
-			struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
-			int *fds)
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
+			uint32_t kernel,
+			struct fastrpc_ioctl_invoke_fd *invokefd)
 {
-	remote_arg_t *rpra = 0;
-	struct fastrpc_device *dev = 0;
 	struct smq_invoke_ctx *ctx = 0;
-	struct fastrpc_buf obuf, *abufs = 0, *b;
-	struct ion_handle **handles = NULL;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
 	int interrupted = 0;
-	uint32_t sc;
-	int i, bufs, nbufs = 0, err = 0;
+	int err = 0;
 
-	sc = invoke->sc;
-	obuf.handle = 0;
+	if (!kernel) {
+		VERIFY(err, 0 == context_restore_interrupted(me, invokefd,
+								&ctx));
+		if (err)
+			goto bail;
+		if (ctx)
+			goto wait;
+	}
+
+	VERIFY(err, 0 == context_alloc(me, kernel, invokefd, &ctx));
+	if (err)
+		goto bail;
+
 	if (me->smmu.enabled) {
 		VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
 							me->smmu.group));
 		if (err)
-			return err;
+			goto bail;
+		ctx->smmu = 1;
 	}
-	if (REMOTE_SCALARS_LENGTH(sc)) {
-		VERIFY(err, 0 == get_dev(me, &dev));
+	if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+		VERIFY(err, 0 == get_dev(me, &ctx->dev));
 		if (err)
 			goto bail;
-		VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
-						&obuf));
+		VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
+					&ctx->dev->buf, &ctx->obuf));
 		if (err)
 			goto bail;
-		rpra = (remote_arg_t *)obuf.virt;
-		VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
-					&obuf, &abufs, &nbufs, fds));
+		ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
+		VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+				invoke->pra, &ctx->obuf, &ctx->abufs,
+				&ctx->nbufs, ctx->fds, ctx->handles));
 		if (err)
 			goto bail;
 	}
 
-	context_list_alloc_ctx(&me->clst, &ctx);
-	inv_args_pre(sc, rpra);
-	VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
-						ctx, &obuf));
+	inv_args_pre(ctx->sc, ctx->rpra);
+	if (FASTRPC_MODE_SERIAL == mode)
+		inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+	VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle,
+						ctx->sc, ctx, &ctx->obuf));
 	if (err)
 		goto bail;
-	inv_args(sc, rpra, obuf.used);
-	VERIFY(err, 0 == (interrupted =
-			wait_for_completion_interruptible(&ctx->work)));
-	if (err)
-		goto bail;
+	if (FASTRPC_MODE_PARALLEL == mode)
+		inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ wait:
+	if (kernel)
+		wait_for_completion(&ctx->work);
+	else {
+		interrupted = wait_for_completion_interruptible(&ctx->work);
+		VERIFY(err, 0 == (err = interrupted));
+		if (err)
+			goto bail;
+	}
 	VERIFY(err, 0 == (err = ctx->retval));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+	VERIFY(err, 0 == put_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+					invoke->pra));
 	if (err)
 		goto bail;
  bail:
-	if (interrupted) {
-		if (!kernel)
-			(void)fastrpc_release_current_dsp_process();
-		wait_for_completion(&ctx->work);
-	}
-	context_free(ctx);
-
-	if (me->smmu.enabled) {
-		bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
-		if (fds) {
-			handles = (struct ion_handle **)(fds + bufs);
-			for (i = 0; i < bufs; i++)
-				if (!IS_ERR_OR_NULL(handles[i])) {
-					ion_unmap_iommu(me->iclient, handles[i],
-							me->smmu.domain_id, 0);
-					ion_free(me->iclient, handles[i]);
-				}
-		}
-		iommu_detach_group(me->smmu.domain, me->smmu.group);
-	}
-	for (i = 0, b = abufs; i < nbufs; ++i, ++b)
-		free_mem(b);
-
-	kfree(abufs);
-	if (dev) {
-		add_dev(me, dev);
-		if (obuf.handle != dev->buf.handle)
-			free_mem(&obuf);
-	}
+	if (ctx && interrupted == -ERESTARTSYS)
+		context_save_interrupted(ctx);
+	else if (ctx)
+		context_free(ctx, 1);
 	return err;
 }
 
 static int fastrpc_create_current_dsp_process(void)
 {
 	int err = 0;
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	struct fastrpc_apps *me = &gfa;
 	remote_arg_t ra[1];
 	int tgid = 0;
@@ -880,10 +1006,12 @@
 	tgid = current->tgid;
 	ra[0].buf.pv = &tgid;
 	ra[0].buf.len = sizeof(tgid);
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -891,17 +1019,19 @@
 {
 	int err = 0;
 	struct fastrpc_apps *me = &gfa;
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[1];
 	int tgid = 0;
 
 	tgid = current->tgid;
 	ra[0].buf.pv = &tgid;
 	ra[0].buf.len = sizeof(tgid);
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -910,7 +1040,7 @@
 					 struct smq_phy_page *pages,
 					 int num)
 {
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[3];
 	int err = 0;
 	struct {
@@ -936,10 +1066,12 @@
 	ra[2].buf.pv = &routargs;
 	ra[2].buf.len = sizeof(routargs);
 
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	mmap->vaddrout = routargs.vaddrout;
 	if (err)
 		goto bail;
@@ -950,7 +1082,7 @@
 static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
 				 struct fastrpc_ioctl_munmap *munmap)
 {
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[1];
 	int err = 0;
 	struct {
@@ -965,10 +1097,12 @@
 	ra[0].buf.pv = &inargs;
 	ra[0].buf.len = sizeof(inargs);
 
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -1010,7 +1144,7 @@
 	struct fastrpc_mmap *map = 0;
 	struct smq_phy_page *pages = 0;
 	void *buf;
-	int len;
+	unsigned long len;
 	int num;
 	int err = 0;
 
@@ -1031,9 +1165,22 @@
 	VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
-	if (err)
-		goto bail;
+
+	if (me->smmu.enabled) {
+		VERIFY(err, 0 == ion_map_iommu(clnt, map->handle,
+				me->smmu.domain_id, 0,
+				SZ_4K, 0, &map->phys, &len, 0, 0));
+		if (err)
+			goto bail;
+		pages->addr = map->phys;
+		pages->size = len;
+		num = 1;
+	} else {
+		VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1,
+							pages, num)));
+		if (err)
+			goto bail;
+	}
 
 	VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
 	if (err)
@@ -1100,7 +1247,7 @@
 	(void)fastrpc_release_current_dsp_process();
 	cleanup_current_dev();
 	if (fdata) {
-		struct fastrpc_mmap *map;
+		struct fastrpc_mmap *map = 0;
 		struct hlist_node *n, *pos;
 		file->private_data = 0;
 		hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
@@ -1179,48 +1326,23 @@
 {
 	struct fastrpc_apps *me = &gfa;
 	struct fastrpc_ioctl_invoke_fd invokefd;
-	struct fastrpc_ioctl_invoke *invoke = &invokefd.inv;
 	struct fastrpc_ioctl_mmap mmap;
 	struct fastrpc_ioctl_munmap munmap;
-	remote_arg_t *pra = 0;
 	void *param = (char *)ioctl_param;
 	struct file_data *fdata = (struct file_data *)file->private_data;
-	int *fds = 0;
-	int bufs, size = 0, err = 0;
+	int size = 0, err = 0;
 
 	switch (ioctl_num) {
 	case FASTRPC_IOCTL_INVOKE_FD:
 	case FASTRPC_IOCTL_INVOKE:
 		invokefd.fds = 0;
 		size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
-				sizeof(*invoke) : sizeof(invokefd);
+				sizeof(invokefd.inv) : sizeof(invokefd);
 		VERIFY(err, 0 == copy_from_user(&invokefd, param, size));
 		if (err)
 			goto bail;
-		bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
-			REMOTE_SCALARS_OUTBUFS(invoke->sc);
-		if (bufs) {
-			size = bufs * sizeof(*pra);
-			if (invokefd.fds)
-				size = size + bufs * sizeof(*fds) +
-					bufs * sizeof(struct ion_handle *);
-			VERIFY(err, 0 != (pra = kzalloc(size, GFP_KERNEL)));
-			if (err)
-				goto bail;
-		}
-		VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
-						bufs * sizeof(*pra)));
-		if (err)
-			goto bail;
-		if (invokefd.fds) {
-			fds = (int *)(pra + bufs);
-			VERIFY(err, 0 == copy_from_user(fds, invokefd.fds,
-							bufs * sizeof(*fds)));
-		if (err)
-			goto bail;
-		}
-		VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, invoke,
-								pra, fds)));
+		VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
+						0, &invokefd)));
 		if (err)
 			goto bail;
 		break;
@@ -1247,12 +1369,22 @@
 		if (err)
 			goto bail;
 		break;
+	case FASTRPC_IOCTL_SETMODE:
+		switch ((uint32_t)ioctl_param) {
+		case FASTRPC_MODE_PARALLEL:
+		case FASTRPC_MODE_SERIAL:
+			fdata->mode = (uint32_t)ioctl_param;
+			break;
+		default:
+			err = -ENOTTY;
+			break;
+		}
+		break;
 	default:
 		err = -ENOTTY;
 		break;
 	}
  bail:
-	kfree(pra);
 	return err;
 }
 
@@ -1307,7 +1439,9 @@
 {
 	struct fastrpc_apps *me = &gfa;
 
+	context_list_dtor(me, &me->clst);
 	fastrpc_deinit();
+	cleanup_current_dev();
 	device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
 	class_destroy(me->class);
 	cdev_del(&me->cdev);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index da70eb5..f5d7450 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -20,9 +20,16 @@
 #define FASTRPC_IOCTL_MMAP    _IOWR('R', 2, struct fastrpc_ioctl_mmap)
 #define FASTRPC_IOCTL_MUNMAP  _IOWR('R', 3, struct fastrpc_ioctl_munmap)
 #define FASTRPC_IOCTL_INVOKE_FD  _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd)
+#define FASTRPC_IOCTL_SETMODE    _IOWR('R', 5, uint32_t)
 #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
 #define DEVICE_NAME      "adsprpc-smd"
 
+/* Driver should operate in parallel with the co-processor */
+#define FASTRPC_MODE_PARALLEL    0
+
+/* Driver should operate in serial mode with the co-processor */
+#define FASTRPC_MODE_SERIAL      1
+
 /* Retrives number of input buffers from the scalars parameter */
 #define REMOTE_SCALARS_INBUFS(sc)        (((sc) >> 16) & 0x0ff)
 
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 03304dc..c9be39a 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,7 +24,7 @@
 #define DISABLE_LOG_MASK	0
 #define MAX_EVENT_SIZE		512
 #define DCI_CLIENT_INDEX_INVALID -1
-#define DCI_PKT_REQ_MIN_LEN		8
+#define DCI_PKT_REQ_MIN_LEN		5
 #define DCI_LOG_CON_MIN_LEN		14
 #define DCI_EVENT_CON_MIN_LEN		16
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4f5893c..8f7d39c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -318,6 +318,7 @@
 show_one(down_differential, down_differential);
 show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
+show_one(down_differential_multi_core, down_differential_multi_core);
 show_one(optimal_freq, optimal_freq);
 show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
 show_one(sync_freq, sync_freq);
@@ -437,6 +438,20 @@
 	return count;
 }
 
+static ssize_t store_down_differential_multi_core(struct kobject *a,
+			struct attribute *b, const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	dbs_tuners_ins.down_differential_multi_core = input;
+	return count;
+}
+
+
 static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
 				   const char *buf, size_t count)
 {
@@ -695,6 +710,7 @@
 define_one_global_rw(ignore_nice_load);
 define_one_global_rw(powersave_bias);
 define_one_global_rw(up_threshold_multi_core);
+define_one_global_rw(down_differential_multi_core);
 define_one_global_rw(optimal_freq);
 define_one_global_rw(up_threshold_any_cpu_load);
 define_one_global_rw(sync_freq);
@@ -710,6 +726,7 @@
 	&powersave_bias.attr,
 	&io_is_busy.attr,
 	&up_threshold_multi_core.attr,
+	&down_differential_multi_core.attr,
 	&optimal_freq.attr,
 	&up_threshold_any_cpu_load.attr,
 	&sync_freq.attr,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0809308..514385c 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -36,6 +36,7 @@
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <linux/dma-buf.h>
+#include <linux/idr.h>
 #include <linux/msm_ion.h>
 #include <trace/events/kmem.h>
 
@@ -70,6 +71,7 @@
  * @node:		node in the tree of all clients
  * @dev:		backpointer to ion device
  * @handles:		an rb tree of all the handles in this client
+ * @idr:		an idr space for allocating handle ids
  * @lock:		lock protecting the tree of handles
  * @name:		used for debugging
  * @task:		used for debugging
@@ -82,6 +84,7 @@
 	struct rb_node node;
 	struct ion_device *dev;
 	struct rb_root handles;
+	struct idr idr;
 	struct mutex lock;
 	char *name;
 	struct task_struct *task;
@@ -96,7 +99,7 @@
  * @buffer:		pointer to the buffer
  * @node:		node in the client's handle rbtree
  * @kmap_cnt:		count of times this client has mapped to kernel
- * @dmap_cnt:		count of times this client has mapped for dma
+ * @id:			client-unique id allocated by client->idr
  *
  * Modifications to node, map_cnt or mapping should be protected by the
  * lock in the client.  Other fields are never changed after initialization.
@@ -107,6 +110,7 @@
 	struct ion_buffer *buffer;
 	struct rb_node node;
 	unsigned int kmap_cnt;
+	int id;
 };
 
 bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -343,6 +347,7 @@
 		ion_handle_kmap_put(handle);
 	mutex_unlock(&buffer->lock);
 
+	idr_remove(&client->idr, handle->id);
 	if (!RB_EMPTY_NODE(&handle->node))
 		rb_erase(&handle->node, &client->handles);
 
@@ -362,9 +367,16 @@
 	kref_get(&handle->ref);
 }
 
-static int ion_handle_put(struct ion_handle *handle)
+int ion_handle_put(struct ion_handle *handle)
 {
-	return kref_put(&handle->ref, ion_handle_destroy);
+	struct ion_client *client = handle->client;
+	int ret;
+
+	mutex_lock(&client->lock);
+	ret = kref_put(&handle->ref, ion_handle_destroy);
+	mutex_unlock(&client->lock);
+
+	return ret;
 }
 
 static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -374,36 +386,52 @@
 
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
-						     node);
+						   node);
 		if (handle->buffer == buffer)
 			return handle;
 	}
 	return NULL;
 }
 
-static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+						int id)
 {
-	struct rb_node *n = client->handles.rb_node;
+	struct ion_handle *handle;
 
-	while (n) {
-		struct ion_handle *handle_node = rb_entry(n, struct ion_handle,
-							  node);
-		if (handle < handle_node)
-			n = n->rb_left;
-		else if (handle > handle_node)
-			n = n->rb_right;
-		else
-			return true;
-	}
-	return false;
+	mutex_lock(&client->lock);
+	handle = idr_find(&client->idr, id);
+	if (handle)
+		ion_handle_get(handle);
+	mutex_unlock(&client->lock);
+
+	return handle ? handle : ERR_PTR(-EINVAL);
 }
 
-static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
 {
+	WARN_ON(!mutex_is_locked(&client->lock));
+	return (idr_find(&client->idr, handle->id) == handle);
+}
+
+static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+{
+	int rc;
 	struct rb_node **p = &client->handles.rb_node;
 	struct rb_node *parent = NULL;
 	struct ion_handle *entry;
 
+	do {
+		int id;
+		rc = idr_pre_get(&client->idr, GFP_KERNEL);
+		if (!rc)
+			return -ENOMEM;
+		rc = idr_get_new_above(&client->idr, handle, 1, &id);
+		handle->id = id;
+	} while (rc == -EAGAIN);
+
+	if (rc < 0)
+		return rc;
+
 	while (*p) {
 		parent = *p;
 		entry = rb_entry(parent, struct ion_handle, node);
@@ -418,6 +446,8 @@
 
 	rb_link_node(&handle->node, parent, p);
 	rb_insert_color(&handle->node, &client->handles);
+
+	return 0;
 }
 
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
@@ -428,6 +458,7 @@
 	struct ion_device *dev = client->dev;
 	struct ion_buffer *buffer = NULL;
 	struct ion_heap *heap;
+	int ret;
 	unsigned long secure_allocation = flags & ION_FLAG_SECURE;
 	const unsigned int MAX_DBG_STR_LEN = 64;
 	char dbg_str[MAX_DBG_STR_LEN];
@@ -518,12 +549,16 @@
 	 */
 	ion_buffer_put(buffer);
 
-	if (!IS_ERR(handle)) {
-		mutex_lock(&client->lock);
-		ion_handle_add(client, handle);
-		mutex_unlock(&client->lock);
-	}
+	if (IS_ERR(handle))
+		return handle;
 
+	mutex_lock(&client->lock);
+	ret = ion_handle_add(client, handle);
+	mutex_unlock(&client->lock);
+	if (ret) {
+		ion_handle_put(handle);
+		handle = ERR_PTR(ret);
+	}
 
 	return handle;
 }
@@ -542,8 +577,8 @@
 		mutex_unlock(&client->lock);
 		return;
 	}
-	ion_handle_put(handle);
 	mutex_unlock(&client->lock);
+	ion_handle_put(handle);
 }
 EXPORT_SYMBOL(ion_free);
 
@@ -775,6 +810,7 @@
 
 	client->dev = dev;
 	client->handles = RB_ROOT;
+	idr_init(&client->idr);
 	mutex_init(&client->lock);
 
 	client->name = kzalloc(name_len+1, GFP_KERNEL);
@@ -831,6 +867,10 @@
 						     node);
 		ion_handle_destroy(&handle->ref);
 	}
+
+	idr_remove_all(&client->idr);
+	idr_destroy(&client->idr);
+
 	down_write(&dev->lock);
 	if (client->task)
 		put_task_struct(client->task);
@@ -1175,14 +1215,15 @@
 
 	mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
-	mutex_unlock(&client->lock);
 	if (!valid_handle) {
 		WARN(1, "%s: invalid handle passed to share.\n", __func__);
+		mutex_unlock(&client->lock);
 		return ERR_PTR(-EINVAL);
 	}
-
 	buffer = handle->buffer;
 	ion_buffer_get(buffer);
+	mutex_unlock(&client->lock);
+
 	dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
 	if (IS_ERR(dmabuf)) {
 		ion_buffer_put(buffer);
@@ -1215,6 +1256,7 @@
 	struct dma_buf *dmabuf;
 	struct ion_buffer *buffer;
 	struct ion_handle *handle;
+	int ret;
 
 	dmabuf = dma_buf_get(fd);
 	if (IS_ERR_OR_NULL(dmabuf))
@@ -1234,14 +1276,24 @@
 	handle = ion_handle_lookup(client, buffer);
 	if (!IS_ERR_OR_NULL(handle)) {
 		ion_handle_get(handle);
+		mutex_unlock(&client->lock);
 		goto end;
 	}
+	mutex_unlock(&client->lock);
+
 	handle = ion_handle_create(client, buffer);
 	if (IS_ERR_OR_NULL(handle))
 		goto end;
-	ion_handle_add(client, handle);
-end:
+
+	mutex_lock(&client->lock);
+	ret = ion_handle_add(client, handle);
 	mutex_unlock(&client->lock);
+	if (ret) {
+		ion_handle_put(handle);
+		handle = ERR_PTR(ret);
+	}
+
+end:
 	dma_buf_put(dmabuf);
 	return handle;
 }
@@ -1279,17 +1331,20 @@
 	case ION_IOC_ALLOC:
 	{
 		struct ion_allocation_data data;
+		struct ion_handle *handle;
 
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
-		data.handle = ion_alloc(client, data.len, data.align,
+		handle = ion_alloc(client, data.len, data.align,
 					     data.heap_mask, data.flags);
 
-		if (IS_ERR(data.handle))
-			return PTR_ERR(data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+
+		data.handle = (ion_user_handle_t)handle->id;
 
 		if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
-			ion_free(client, data.handle);
+			ion_free(client, handle);
 			return -EFAULT;
 		}
 		break;
@@ -1297,28 +1352,31 @@
 	case ION_IOC_FREE:
 	{
 		struct ion_handle_data data;
-		bool valid;
+		struct ion_handle *handle;
 
 		if (copy_from_user(&data, (void __user *)arg,
 				   sizeof(struct ion_handle_data)))
 			return -EFAULT;
-		mutex_lock(&client->lock);
-		valid = ion_handle_validate(client, data.handle);
-		mutex_unlock(&client->lock);
-		if (!valid)
-			return -EINVAL;
-		ion_free(client, data.handle);
+		handle = ion_handle_get_by_id(client, (int)data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+		ion_free(client, handle);
+		ion_handle_put(handle);
 		break;
 	}
 	case ION_IOC_SHARE:
 	case ION_IOC_MAP:
 	{
 		struct ion_fd_data data;
+		struct ion_handle *handle;
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
 
-		data.fd = ion_share_dma_buf_fd(client, data.handle);
-
+		handle = ion_handle_get_by_id(client, (int)data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+		data.fd = ion_share_dma_buf_fd(client, handle);
+		ion_handle_put(handle);
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
 		if (data.fd < 0)
@@ -1328,15 +1386,17 @@
 	case ION_IOC_IMPORT:
 	{
 		struct ion_fd_data data;
+		struct ion_handle *handle;
 		int ret = 0;
 		if (copy_from_user(&data, (void __user *)arg,
 				   sizeof(struct ion_fd_data)))
 			return -EFAULT;
-		data.handle = ion_import_dma_buf(client, data.fd);
-		if (IS_ERR(data.handle)) {
-			ret = PTR_ERR(data.handle);
-			data.handle = NULL;
-		}
+		handle = ion_import_dma_buf(client, data.fd);
+		if (IS_ERR(handle))
+			ret = PTR_ERR(handle);
+		else
+			data.handle = (ion_user_handle_t)handle->id;
+
 		if (copy_to_user((void __user *)arg, &data,
 				 sizeof(struct ion_fd_data)))
 			return -EFAULT;
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index f5d0287..aa0a9e2 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -396,4 +396,9 @@
 int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
 			int (*f)(struct ion_heap *heap, void *data));
 
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+					int id);
+
+int ion_handle_put(struct ion_handle *handle);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 213bcb1..cdd31e1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -973,11 +973,18 @@
 					sizeof(struct ion_flush_data)))
 			return -EFAULT;
 
-		if (!data.handle) {
+		if (data.handle >= 0) {
+			handle = ion_handle_get_by_id(client, (int)data.handle);
+			if (IS_ERR(handle)) {
+				pr_info("%s: Could not find handle: %d\n",
+					__func__, (int)data.handle);
+				return PTR_ERR(handle);
+			}
+		} else {
 			handle = ion_import_dma_buf(client, data.fd);
 			if (IS_ERR(handle)) {
-				pr_info("%s: Could not import handle: %d\n",
-					__func__, (int)handle);
+				pr_info("%s: Could not import handle: %p\n",
+					__func__, handle);
 				return -EINVAL;
 			}
 		}
@@ -988,28 +995,20 @@
 		end = (unsigned long) data.vaddr + data.length;
 
 		if (start && check_vaddr_bounds(start, end)) {
-			up_read(&mm->mmap_sem);
 			pr_err("%s: virtual address %p is out of bounds\n",
 				__func__, data.vaddr);
-			if (!data.handle)
-				ion_free(client, handle);
-			return -EINVAL;
+			ret = -EINVAL;
+		} else {
+			ret = ion_do_cache_op(client, handle, data.vaddr,
+					data.offset, data.length, cmd);
 		}
-
-		ret = ion_do_cache_op(client,
-				data.handle ? data.handle : handle,
-				data.vaddr, data.offset, data.length,
-				cmd);
-
 		up_read(&mm->mmap_sem);
 
-		if (!data.handle)
-			ion_free(client, handle);
+		ion_free(client, handle);
 
 		if (ret < 0)
 			return ret;
 		break;
-
 	}
 	case ION_IOC_PREFETCH:
 	{
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index e5f5ad7..3d4c66a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4077,6 +4077,7 @@
 static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
 {
 	int ret;
+	struct kgsl_device *device = &adreno_dev->dev;
 	/* SP[3] counter is broken on a330 so disable it if a330 device */
 	if (adreno_is_a330(adreno_dev))
 		a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
@@ -4088,15 +4089,18 @@
 	ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
 			NULL, PERFCOUNTER_FLAG_KERNEL);
 
-	/* VBIF waiting for RAM */
-	ret |= adreno_perfcounter_get(adreno_dev,
+	if (device->pwrctrl.bus_control) {
+		/* VBIF waiting for RAM */
+		ret |= adreno_perfcounter_get(adreno_dev,
 				KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
 				NULL, PERFCOUNTER_FLAG_KERNEL);
-	/* VBIF DDR cycles */
-	ret |= adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+		/* VBIF DDR cycles */
+		ret |= adreno_perfcounter_get(adreno_dev,
+				KGSL_PERFCOUNTER_GROUP_VBIF,
 				VBIF_AXI_TOTAL_BEATS,
 				&adreno_dev->ram_cycles_lo,
 				PERFCOUNTER_FLAG_KERNEL);
+	}
 
 	/* Default performance counter profiling to false */
 	adreno_dev->profile.enabled = false;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe99a4b..9aefda6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2878,7 +2878,7 @@
 	bool full_flush = false;
 
 	if (param->id_list == NULL || param->count == 0
-			|| param->count > (UINT_MAX/sizeof(unsigned int)))
+			|| param->count > (PAGE_SIZE / sizeof(unsigned int)))
 		return -EINVAL;
 
 	id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2be1f01..59b648d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -122,6 +122,8 @@
 {
 	int i, rc = -1;
 	struct msm_isp_buffer_mapped_info *mapped_info;
+	struct buffer_cmd *buf_pending = NULL;
+
 	for (i = 0; i < v4l2_buf->length; i++) {
 		mapped_info = &buf_info->mapped_info[i];
 		mapped_info->handle =
@@ -144,6 +146,15 @@
 		mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
 		CDBG("%s: plane: %d addr:%lu\n",
 			__func__, i, mapped_info->paddr);
+
+		buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
+		if (!buf_pending) {
+			pr_err("No free memory for buf_pending\n");
+			return rc;
+		}
+
+		buf_pending->mapped_info = mapped_info;
+		list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
 	}
 	buf_info->num_planes = v4l2_buf->length;
 	return 0;
@@ -163,11 +174,26 @@
 {
 	int i;
 	struct msm_isp_buffer_mapped_info *mapped_info;
+	struct buffer_cmd *buf_pending = NULL;
+
 	for (i = 0; i < buf_info->num_planes; i++) {
 		mapped_info = &buf_info->mapped_info[i];
-		ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
-			buf_mgr->iommu_domain_num, 0);
-		ion_free(buf_mgr->client, mapped_info->handle);
+
+		list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+			if (!buf_pending)
+				break;
+
+			if (buf_pending->mapped_info == mapped_info) {
+				ion_unmap_iommu(buf_mgr->client,
+					mapped_info->handle,
+					buf_mgr->iommu_domain_num, 0);
+				ion_free(buf_mgr->client, mapped_info->handle);
+
+				list_del_init(&buf_pending->list);
+				kfree(buf_pending);
+				break;
+			}
+		}
 	}
 	return;
 }
@@ -586,7 +612,7 @@
 		}
 	} else {
 		bufq = msm_isp_get_bufq(buf_mgr, info->handle);
-		if (BUF_SRC(bufq->stream_id)) {
+		if (bufq && BUF_SRC(bufq->stream_id)) {
 			rc = msm_isp_put_buf(buf_mgr,
 					info->handle, info->buf_idx);
 			if (rc < 0) {
@@ -691,6 +717,7 @@
 		if (!bufq->bufq_handle)
 			continue;
 		msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
+
 		kfree(bufq->bufs);
 		msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
 	}
@@ -739,9 +766,10 @@
 		pr_err("Invalid buffer queue number\n");
 		return rc;
 	}
-
 	CDBG("%s: E\n", __func__);
+
 	msm_isp_attach_ctx(buf_mgr);
+	INIT_LIST_HEAD(&buf_mgr->buffer_q);
 	buf_mgr->num_buf_q = num_buf_q;
 	buf_mgr->bufq =
 		kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 6d6ff9d..d8d3ba2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -44,6 +44,11 @@
 	struct ion_handle *handle;
 };
 
+struct buffer_cmd {
+	struct list_head list;
+	struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
 struct msm_isp_buffer {
 	/*Common Data structure*/
 	int num_planes;
@@ -138,6 +143,7 @@
 
 	int num_iommu_ctx;
 	struct device *iommu_ctx[2];
+	struct list_head buffer_q;
 };
 
 int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 2c5e136..80a0073 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -140,6 +140,7 @@
 		&vfe_vb2_ops, &vfe_layout);
 	if (rc < 0) {
 		pr_err("%s: Unable to create buffer manager\n", __func__);
+		msm_sd_unregister(&vfe_dev->subdev);
 		kfree(vfe_dev);
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 87bffde..9dd0085 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -106,7 +106,7 @@
 		uint32_t reload_mask);
 	void (*enable_wm) (struct vfe_device *vfe_dev,
 		uint8_t wm_idx, uint8_t enable);
-	void (*cfg_io_format) (struct vfe_device *vfe_dev,
+	int32_t (*cfg_io_format) (struct vfe_device *vfe_dev,
 		enum msm_vfe_axi_stream_src stream_src,
 		uint32_t io_format);
 	void (*cfg_framedrop) (struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index f5529cd..410fe8f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -74,6 +74,8 @@
 			goto fs_failed;
 		}
 	}
+	else
+		goto fs_failed;
 
 	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
 		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
@@ -495,12 +497,17 @@
 	}
 }
 
-static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
 	int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
 	uint32_t io_format_reg;
 	bpp = msm_isp_get_bit_per_pixel(io_format);
+	if (bpp < 0) {
+		pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+			io_format, bpp);
+		return -EINVAL;
+	}
 
 	switch (bpp) {
 	case 8:
@@ -512,6 +519,9 @@
 	case 12:
 		bpp_reg = 1 << 1;
 		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
 	}
 
 	if (stream_src == IDEAL_RAW) {
@@ -537,7 +547,7 @@
 			break;
 		default:
 			pr_err("%s: invalid pack fmt!\n", __func__);
-			return;
+			return -EINVAL;
 		}
 	}
 
@@ -558,9 +568,10 @@
 	case RDI_INTF_2:
 	default:
 		pr_err("%s: Invalid stream source\n", __func__);
-		return;
+		return -EINVAL;
 	}
 	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+	return 0;
 }
 
 static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 50a25bd..ad4b75f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -268,6 +268,8 @@
 			goto fs_failed;
 		}
 	}
+	else
+		goto fs_failed;
 
 	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
 		vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 1);
@@ -724,13 +726,18 @@
 			VFE40_WM_BASE(stream_info->wm[i]) + 0x1C);
 }
 
-static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
 	int bpp, bpp_reg = 0, pack_reg = 0;
 	enum msm_isp_pack_fmt pack_fmt = 0;
 	uint32_t io_format_reg; /*io format register bit*/
 	bpp = msm_isp_get_bit_per_pixel(io_format);
+	if (bpp < 0) {
+		pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+			io_format, bpp);
+		return -EINVAL;
+	}
 
 	switch (bpp) {
 	case 8:
@@ -742,6 +749,9 @@
 	case 12:
 		bpp_reg = 1 << 1;
 		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
 	}
 
 	if (stream_src == IDEAL_RAW) {
@@ -768,7 +778,7 @@
 			break;
 		default:
 			pr_err("%s: invalid pack fmt!\n", __func__);
-			return;
+			return -EINVAL;
 		}
 	}
 
@@ -789,9 +799,10 @@
 	case RDI_INTF_2:
 	default:
 		pr_err("%s: Invalid stream source\n", __func__);
-		return;
+		return -EINVAL;
 	}
 	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+	return 0;
 }
 
 static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 3202cdb..97b6347 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -68,9 +68,17 @@
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
 {
 	int rc = -1, i;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	uint32_t idx = 0;
+
+	if (NULL == stream_cfg_cmd || NULL == axi_data)
+		return rc;
+
+	idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+	if (idx < MAX_NUM_STREAM)
+		stream_info = &axi_data->stream_info[idx];
+	else
+		return rc;
 
 	switch (stream_cfg_cmd->output_format) {
 	case V4L2_PIX_FMT_SBGGR8:
@@ -428,11 +436,22 @@
 	struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
 {
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-		HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-	uint32_t framedrop_period = msm_isp_get_framedrop_period(
-	   stream_cfg_cmd->frame_skip_pattern);
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	uint32_t framedrop_period = 0;
+	uint8_t idx = 0;
+
+	if (NULL == axi_data || NULL == stream_cfg_cmd)
+		return;
+
+	idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+
+	if (idx < MAX_NUM_STREAM)
+		stream_info = &axi_data->stream_info[idx];
+	else
+		return;
+
+	framedrop_period = msm_isp_get_framedrop_period(
+			stream_cfg_cmd->frame_skip_pattern);
 
 	if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
 		stream_info->framedrop_pattern = 0x0;
@@ -520,8 +539,17 @@
 
 			io_format = stream_info->output_format;
 		}
-		vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+		rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
 			vfe_dev, stream_info->stream_src, io_format);
+		if (rc) {
+			pr_err("%s: cfg io format failed\n", __func__);
+			msm_isp_axi_free_wm(&vfe_dev->axi_data,
+				stream_info);
+			msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
+				HANDLE_TO_IDX(
+				stream_cfg_cmd->axi_stream_handle));
+			return rc;
+		}
 	}
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
@@ -763,8 +791,9 @@
 	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
 			vfe_dev->pdev->id, bufq_handle, &buf);
 	if (rc < 0) {
-		vfe_dev->error_info.
-			stream_framedrop_count[stream_idx]++;
+		if(stream_idx < MAX_NUM_STREAM)
+			vfe_dev->error_info.
+				stream_framedrop_count[stream_idx]++;
 		return rc;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index b479857..8b83144 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -39,8 +39,9 @@
 	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
 			vfe_dev->pdev->id, bufq_handle, &buf);
 	if (rc < 0) {
-		vfe_dev->error_info.stats_framedrop_count[
-			STATS_IDX(stream_info->stream_handle)]++;
+		uint8_t idx = STATS_IDX(stream_info->stream_handle);
+		if (idx < MSM_ISP_STATS_MAX)
+			vfe_dev->error_info.stats_framedrop_count[idx]++;
 		return rc;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ea0195d..3cb48d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -77,6 +77,25 @@
 	.name = "msm_camera_isp",
 };
 
+static void msm_isp_print_fourcc_error(const char *origin,
+	uint32_t fourcc_format)
+{
+	int i;
+	char text[5];
+	text[4] = '\0';
+	for (i = 0; i < 4; i++) {
+		text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+		if ((text[i] < '0') || (text[i] > 'z')) {
+			pr_err("%s: Invalid output format %d (unprintable)\n",
+				origin, fourcc_format);
+			return;
+		}
+	}
+	pr_err("%s: Invalid output format %s\n",
+		origin, text);
+	return;
+}
+
 int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client)
 {
 	int rc = 0;
@@ -735,7 +754,7 @@
 		break;
 		/*TD: Add more image format*/
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
+		msm_isp_print_fourcc_error(__func__, output_format);
 		break;
 	}
 	return val;
@@ -771,7 +790,7 @@
 	case V4L2_PIX_FMT_QRGGB12:
 		return QCOM;
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
+		msm_isp_print_fourcc_error(__func__, output_format);
 		break;
 	}
 	return -EINVAL;
@@ -780,6 +799,10 @@
 int msm_isp_get_bit_per_pixel(uint32_t output_format)
 {
 	switch (output_format) {
+	case V4L2_PIX_FMT_Y4:
+		return 4;
+	case V4L2_PIX_FMT_Y6:
+		return 6;
 	case V4L2_PIX_FMT_SBGGR8:
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
@@ -790,6 +813,29 @@
 	case V4L2_PIX_FMT_QRGGB8:
 	case V4L2_PIX_FMT_JPEG:
 	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+	case V4L2_PIX_FMT_YVU410:
+	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YYUV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_YUV422P:
+	case V4L2_PIX_FMT_YUV411P:
+	case V4L2_PIX_FMT_Y41P:
+	case V4L2_PIX_FMT_YUV444:
+	case V4L2_PIX_FMT_YUV555:
+	case V4L2_PIX_FMT_YUV565:
+	case V4L2_PIX_FMT_YUV32:
+	case V4L2_PIX_FMT_YUV410:
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_PAL8:
+	case MSM_V4L2_PIX_FMT_META:
 		return 8;
 	case V4L2_PIX_FMT_SBGGR10:
 	case V4L2_PIX_FMT_SGBRG10:
@@ -799,6 +845,8 @@
 	case V4L2_PIX_FMT_QGBRG10:
 	case V4L2_PIX_FMT_QGRBG10:
 	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y10BPACK:
 		return 10;
 	case V4L2_PIX_FMT_SBGGR12:
 	case V4L2_PIX_FMT_SGBRG12:
@@ -808,21 +856,17 @@
 	case V4L2_PIX_FMT_QGBRG12:
 	case V4L2_PIX_FMT_QGRBG12:
 	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_Y12:
 		return 12;
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV14:
-	case V4L2_PIX_FMT_NV41:
-		return 8;
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_Y16:
 		return 16;
 		/*TD: Add more image format*/
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
-		break;
+		msm_isp_print_fourcc_error(__func__, output_format);
+		return -EINVAL;
 	}
-	return -EINVAL;
 }
 
 void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 8f080ce..407b81f 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -31,14 +31,19 @@
 int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
 		long clk_rate)
 {
-	struct msm_cam_clk_info jpeg_core_clk_info[] = {
-		{"core_clk", JPEG_CLK_RATE, 0}
-	};
+	int rc = 0;
+	struct clk *jpeg_clk;
 
-	jpeg_core_clk_info[0].clk_rate = clk_rate;
+	jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk");
+	if (IS_ERR(jpeg_clk)) {
+		JPEG_PR_ERR("%s get failed\n", "core_clk");
+		rc = PTR_ERR(jpeg_clk);
+		return rc;
+	}
 
-	return msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_core_clk_info,
-			pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_core_clk_info), 1);
+	rc = clk_set_rate(jpeg_clk, clk_rate);
+
+	return rc;
 }
 
 void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file  *file,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index c79b3a3..8a2c8e5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -1001,8 +1001,10 @@
 	video_set_drvdata(pvdev->vdev, pvdev);
 
 	msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
-	if (WARN_ON(!msm_session_q))
-		goto v4l2_fail;
+	if (WARN_ON(!msm_session_q)) {
+		rc = -ENOMEM;
+		goto session_fail;
+	}
 
 	msm_init_queue(msm_session_q);
 	spin_lock_init(&msm_eventq_lock);
@@ -1010,6 +1012,8 @@
 	INIT_LIST_HEAD(&ordered_sd_list);
 	goto probe_end;
 
+session_fail:
+	video_unregister_device(pvdev->vdev);
 v4l2_fail:
 	v4l2_device_unregister(pvdev->vdev->v4l2_dev);
 register_fail:
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 69f0a3d..532bebc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1845,6 +1845,11 @@
 	cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
 	cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
 		GFP_KERNEL);
+	if (!cpp_dev->work) {
+		pr_err("cpp_dev->work is NULL\n");
+		rc = -ENOMEM;
+		goto ERROR3;
+	}
 	INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
 	cpp_dev->cpp_open_cnt = 0;
 	cpp_dev->is_firmware_loaded = 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index dc29199..8d14363 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -691,43 +691,47 @@
 
 	if (queue->len > 0) {
 		frame_qcmd = msm_dequeue(queue, list_frame);
-		processed_frame = frame_qcmd->command;
-		do_gettimeofday(&(processed_frame->out_time));
-		kfree(frame_qcmd);
-		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
-		if (!event_qcmd) {
-			pr_err("%s: Insufficient memory\n", __func__);
-			return -ENOMEM;
-		}
-		atomic_set(&event_qcmd->on_heap, 1);
-		event_qcmd->command = processed_frame;
-		VPE_DBG("fid %d\n", processed_frame->frame_id);
-		msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+		if(frame_qcmd) {
+			processed_frame = frame_qcmd->command;
+			do_gettimeofday(&(processed_frame->out_time));
+			kfree(frame_qcmd);
+			event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+			if (!event_qcmd) {
+				pr_err("%s: Insufficient memory\n", __func__);
+				return -ENOMEM;
+			}
+			atomic_set(&event_qcmd->on_heap, 1);
+			event_qcmd->command = processed_frame;
+			VPE_DBG("fid %d\n", processed_frame->frame_id);
+			msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
 
-		if (!processed_frame->output_buffer_info.processed_divert) {
-			memset(&buff_mgr_info, 0 ,
-				sizeof(buff_mgr_info));
-			buff_mgr_info.session_id =
-				((processed_frame->identity >> 16) & 0xFFFF);
-			buff_mgr_info.stream_id =
-				(processed_frame->identity & 0xFFFF);
-			buff_mgr_info.frame_id = processed_frame->frame_id;
-			buff_mgr_info.timestamp = processed_frame->timestamp;
-			buff_mgr_info.index =
-				processed_frame->output_buffer_info.index;
-			rc = msm_vpe_buffer_ops(vpe_dev,
+			if (!processed_frame->output_buffer_info.processed_divert) {
+				memset(&buff_mgr_info, 0 ,
+					sizeof(buff_mgr_info));
+				buff_mgr_info.session_id =
+					((processed_frame->identity >> 16) & 0xFFFF);
+				buff_mgr_info.stream_id =
+					(processed_frame->identity & 0xFFFF);
+				buff_mgr_info.frame_id = processed_frame->frame_id;
+				buff_mgr_info.timestamp = processed_frame->timestamp;
+				buff_mgr_info.index =
+					processed_frame->output_buffer_info.index;
+				rc = msm_vpe_buffer_ops(vpe_dev,
 						VIDIOC_MSM_BUF_MNGR_BUF_DONE,
 						&buff_mgr_info);
-			if (rc < 0) {
-				pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
-					__func__);
-				rc = -EINVAL;
+				if (rc < 0) {
+					pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+						__func__);
+					rc = -EINVAL;
+				}
 			}
-		}
 
-		v4l2_evt.id = processed_frame->inst_id;
-		v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
-		v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+			v4l2_evt.id = processed_frame->inst_id;
+			v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+			v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+		}
+		else
+			rc = -EFAULT;
 	}
 	return rc;
 }
@@ -1368,6 +1372,8 @@
 		struct msm_vpe_frame_info_t *process_frame;
 		VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
 		event_qcmd = msm_dequeue(queue, list_eventdata);
+		if (NULL == event_qcmd)
+			break;
 		process_frame = event_qcmd->command;
 		VPE_DBG("fid %d\n", process_frame->frame_id);
 		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 45db19c..69c1faa 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -809,6 +809,7 @@
 	e_ctrl->is_supported = 0;
 	if (!of_node) {
 		pr_err("%s dev.of_node NULL\n", __func__);
+		kfree(e_ctrl);
 		return -EINVAL;
 	}
 
@@ -817,6 +818,7 @@
 	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
 	if (rc < 0) {
 		pr_err("failed rc %d\n", rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 	e_ctrl->subdev_id = pdev->id;
@@ -826,12 +828,14 @@
 	CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
 	if (rc < 0) {
 		pr_err("%s failed rc %d\n", __func__, rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 	rc = of_property_read_u32(of_node, "qcom,slave-addr",
 		&temp);
 	if (rc < 0) {
 		pr_err("%s failed rc %d\n", __func__, rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 
@@ -844,6 +848,7 @@
 		struct msm_camera_cci_client), GFP_KERNEL);
 	if (!e_ctrl->i2c_client.cci_client) {
 		pr_err("%s failed no memory\n", __func__);
+		kfree(e_ctrl);
 		return -ENOMEM;
 	}
 
@@ -936,6 +941,7 @@
 	kfree(e_ctrl->eboard_info);
 cciclient_free:
 	kfree(e_ctrl->i2c_client.cci_client);
+	kfree(e_ctrl);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 699142a..b88ac00 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -71,9 +71,9 @@
 	case MSM_CAMERA_LED_LOW:
 		if (fctrl->torch_trigger) {
 			max_curr_l = fctrl->torch_max_current;
-			if (cfg->led_current > 0 &&
-					cfg->led_current < max_curr_l) {
-				curr_l = cfg->led_current;
+			if (cfg->torch_current > 0 &&
+					cfg->torch_current < max_curr_l) {
+				curr_l = cfg->torch_current;
 			} else {
 				curr_l = fctrl->torch_op_current;
 				pr_err("LED current clamped to %d\n",
@@ -90,9 +90,9 @@
 		for (i = 0; i < fctrl->num_sources; i++)
 			if (fctrl->flash_trigger[i]) {
 				max_curr_l = fctrl->flash_max_current[i];
-				if (cfg->led_current > 0 &&
-						cfg->led_current < max_curr_l) {
-					curr_l = cfg->led_current;
+				if (cfg->flash_current[i] > 0 &&
+						cfg->flash_current[i] < max_curr_l) {
+					curr_l = cfg->flash_current[i];
 				} else {
 					curr_l = fctrl->flash_op_current[i];
 					pr_err("LED current clamped to %d\n",
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 19a378f..5694658 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -3964,6 +3964,58 @@
 }
 EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
 
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct mpq_video_feed_info *feed_data;
+	struct dvb_ringbuffer *buffer;
+	struct ion_handle *ion_handle;
+	int ret = 0;
+	int i;
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		if (dvb_dmx_is_sec_feed(feed) ||
+			dvb_dmx_is_pcr_feed(feed)) {
+			buffer = (struct dvb_ringbuffer *)
+				&mpq_feed->sdmx_buf;
+			ion_handle = mpq_feed->sdmx_buf_handle;
+		} else {
+			buffer = (struct dvb_ringbuffer *)
+				feed->feed.ts.buffer.ringbuff;
+			ion_handle = feed->feed.ts.buffer.priv_handle;
+		}
+
+		ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+			ion_handle, buffer->data,
+			buffer->size, ION_IOC_INV_CACHES);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: msm_ion_do_cache_op failed, ret = %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	/* Video buffers */
+	feed_data = &mpq_feed->video_info;
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		if (feed_data->buffer_desc.desc[i].base) {
+			/* Non-secured buffer */
+			ret = msm_ion_do_cache_op(
+				mpq_feed->mpq_demux->ion_client,
+				feed_data->buffer_desc.ion_handle[i],
+				feed_data->buffer_desc.desc[i].base,
+				feed_data->buffer_desc.desc[i].size,
+				ION_IOC_INV_CACHES);
+			if (ret)
+				MPQ_DVB_ERR_PRINT(
+					"%s: msm_ion_do_cache_op failed, ret = %d\n",
+					__func__, ret);
+		}
+	}
+
+	return ret;
+}
+
 static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
 	struct sdmx_filter_status *filter_sts,
 	struct mpq_feed *mpq_feed)
@@ -4757,6 +4809,9 @@
 			 mpq_feed->session_id))
 			continue;
 
+		/* Invalidate output buffer before processing the results */
+		mpq_sdmx_invalidate_buffer(mpq_feed);
+
 		if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
 			MPQ_DVB_ERR_PRINT(
 				"%s: meta-data buff for pid %d overflowed!\n",
@@ -4831,7 +4886,6 @@
 	for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
 		mpq_feed = &mpq_demux->feeds[i];
 		if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
-			&& (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
 			&& (!mpq_feed->secondary_feed)) {
 			sts = mpq_demux->sdmx_filters_state.status +
 				filter_index;
@@ -4950,6 +5004,10 @@
 	const char *buf,
 	size_t count)
 {
+	struct ion_handle *ion_handle =
+		mpq_demux->demux.dmx.dvr_input.priv_handle;
+	struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+		mpq_demux->demux.dmx.dvr_input.ringbuff;
 	struct sdmx_buff_descr buf_desc;
 	u32 read_offset;
 	int ret;
@@ -4968,6 +5026,19 @@
 	}
 	read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
 
+
+	/*
+	 * We must flush the buffer before SDMX starts reading from it
+	 * so that it gets a valid data in memory.
+	 */
+	ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+		ion_handle, rbuf->data,
+		rbuf->size, ION_IOC_CLEAN_CACHES);
+	if (ret)
+		MPQ_DVB_ERR_PRINT(
+			"%s: msm_ion_do_cache_op failed, ret = %d\n",
+			__func__, ret);
+
 	return mpq_sdmx_process(mpq_demux, &buf_desc, count,
 				read_offset, mpq_demux->demux.ts_packet_size);
 }
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 9a9b385..2e8837d 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -105,6 +105,7 @@
 	skb = alloc_skb(len, GFP_ATOMIC);
 	if (!skb) {
 		FMDERR("Memory not allocated for the socket");
+		kfree(worker);
 		return;
 	}
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a554749..3886c52 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3159,7 +3159,7 @@
 			struct v4l2_ext_controls *ctrl)
 {
 	int retval = 0;
-	int bytes_to_copy;
+	size_t bytes_to_copy;
 	struct hci_fm_tx_ps tx_ps;
 	struct hci_fm_tx_rt tx_rt;
 	struct hci_fm_def_data_wr_req default_data;
@@ -3168,18 +3168,20 @@
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	char *data = NULL;
 
-	if (radio == NULL) {
-		FMDERR(":radio is null");
-		return -EINVAL;
+	if ((ctrl == NULL) || (ctrl->controls == NULL)
+		|| (ctrl->count == 0)) {
+		retval = -EINVAL;
+		return retval;
 	}
+
 	switch ((ctrl->controls[0]).id) {
 	case V4L2_CID_RDS_TX_PS_NAME:
 		FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
 		/*Pass a sample PS string */
 
 		memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
-		bytes_to_copy = min((int)(ctrl->controls[0]).size,
-			MAX_PS_LENGTH);
+		bytes_to_copy = min(ctrl->controls[0].size,
+			(size_t)MAX_PS_LENGTH);
 		data = (ctrl->controls[0]).string;
 
 		if (copy_from_user(tx_ps.ps_data,
@@ -3196,7 +3198,7 @@
 		break;
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
 		bytes_to_copy =
-		    min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+		    min((ctrl->controls[0]).size, (size_t)MAX_RT_LENGTH);
 		data = (ctrl->controls[0]).string;
 
 		memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
@@ -4470,11 +4472,11 @@
 		if (kfifo_alloc_rc != 0) {
 			FMDERR("failed allocating buffers %d\n",
 				   kfifo_alloc_rc);
-			for (; i > -1; i--) {
+			for (; i > -1; i--)
 				kfifo_free(&radio->data_buf[i]);
-				kfree(radio);
-				return -ENOMEM;
-			}
+			video_device_release(radio->videodev);
+			kfree(radio);
+			return -ENOMEM;
 		}
 	}
 
@@ -4502,8 +4504,17 @@
 	} else {
 		priv_videodev = kzalloc(sizeof(struct video_device),
 			GFP_KERNEL);
-		memcpy(priv_videodev, radio->videodev,
-			sizeof(struct video_device));
+		if (priv_videodev != NULL) {
+			memcpy(priv_videodev, radio->videodev,
+				sizeof(struct video_device));
+		} else {
+			video_unregister_device(radio->videodev);
+			video_device_release(radio->videodev);
+			for (; i > -1; i--)
+				kfifo_free(&radio->data_buf[i]);
+			kfree(radio);
+			return -ENOMEM;
+		}
 	}
 	return 0;
 }
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 6b9f2b3..c44e2a5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -185,6 +185,10 @@
 	if (bahama_present == -ENODEV)
 		return -ENODEV;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
 	if (bahama_present)
 		radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
 	else
@@ -216,6 +220,11 @@
    * (otherwise, it may have already been there and will not be added a second
    * time).
    */
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
 	queue_delayed_work(radio->wqueue, &radio->work,
 				msecs_to_jiffies(TAVARUA_DELAY));
 	return IRQ_HANDLED;
@@ -243,6 +252,12 @@
 				unsigned char offset, int len)
 {
 	int retval = 0, i = 0;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -282,6 +297,12 @@
 			unsigned char offset, unsigned char value)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -322,6 +343,12 @@
 
 	int i;
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -358,6 +385,11 @@
 */
 static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
 {
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* read all 3 RDS blocks */
 	return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
 }
@@ -376,10 +408,17 @@
 */
 static void tavarua_rds_read(struct tavarua_device *radio)
 {
-	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+	struct kfifo *rds_buf;
 	unsigned char blocknum;
 	unsigned char tmp[3];
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
 	if (read_data_blocks(radio, RAW_RDS) < 0)
 		return;
 	 /* copy all four RDS blocks to internal buffer */
@@ -430,6 +469,12 @@
 static int request_read_xfr(struct tavarua_device *radio,
 				enum tavarua_xfr_ctrl_t mode){
 
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	tavarua_write_register(radio, XFRCTRL, mode);
 	msleep(TAVARUA_DELAY);
 	return 0;
@@ -457,8 +502,17 @@
 static int copy_from_xfr(struct tavarua_device *radio,
 		enum tavarua_buf_t buf_type, unsigned int n){
 
-	struct kfifo *data_fifo = &radio->data_buf[buf_type];
-	unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+	struct kfifo *data_fifo;
+	unsigned char *xfr_regs;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	data_fifo = &radio->data_buf[buf_type];
+	xfr_regs = &radio->registers[XFRCTRL+1];
+
 	kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
 	return 0;
 }
@@ -496,6 +550,12 @@
 			char *buf, int len)
 {
 	char buffer[len+1];
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	memcpy(buffer+1, buf, len);
 	/* buffer[0] corresponds to XFRCTRL register
 	   set the CTRL bit to 1 for write mode
@@ -520,6 +580,11 @@
 static int xfr_intf_own(struct tavarua_device *radio)
 {
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	mutex_lock(&radio->lock);
 	if (radio->xfr_in_progress) {
 		radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
@@ -552,6 +617,12 @@
 			enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = xfr_intf_own(radio);
 	if (retval < 0)
 		return retval;
@@ -590,6 +661,17 @@
 		enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = xfr_intf_own(radio);
 	if (retval < 0)
 		return retval;
@@ -627,6 +709,12 @@
 {
 	int i;
 	enum tavarua_xfr_t xfr;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	for (i = 0; i < TAVARUA_XFR_MAX; i++) {
 		if (radio->pending_xfrs[i]) {
 			radio->xfr_in_progress = 1;
@@ -681,8 +769,16 @@
 				enum tavarua_evt_t event)
 {
 
-	struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+	struct kfifo *data_b;
 	unsigned char evt = event;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+
 	FMDBG("updating event_q with event %x\n", event);
 	if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
 		wake_up_interruptible(&radio->event_queue);
@@ -707,12 +803,18 @@
 static void tavarua_start_xfr(struct tavarua_device *radio,
 		enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
 {
-		if (radio->xfr_in_progress)
-			radio->pending_xfrs[pending_id] = 1;
-		else {
-			radio->xfr_in_progress = 1;
-			request_read_xfr(radio, xfr_id);
-		}
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	if (radio->xfr_in_progress)
+		radio->pending_xfrs[pending_id] = 1;
+	else {
+		radio->xfr_in_progress = 1;
+		request_read_xfr(radio, xfr_id);
+	}
 }
 
 /*=============================================================================
@@ -739,6 +841,12 @@
 	int i;
 	int retval, adj_channel_tune_req = 0;
 	unsigned char xfr_status;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	if (!radio->handle_irq) {
 		FMDBG("IRQ happend, but I wont handle it\n");
 		return;
@@ -1143,15 +1251,34 @@
 */
 static void read_int_stat(struct work_struct *work)
 {
-	struct tavarua_device *radio = container_of(work,
-					struct tavarua_device, work.work);
+	struct tavarua_device *radio;
+
+	if (unlikely(work == NULL)) {
+		FMDERR("%s:work is null", __func__);
+		return;
+	}
+
+	radio = container_of(work, struct tavarua_device, work.work);
+
 	tavarua_handle_interrupts(radio);
 }
 
 static void fm_shutdown(struct work_struct *work)
 {
-	struct tavarua_device *radio = container_of(work,
-					struct tavarua_device, work.work);
+	struct tavarua_device *radio;
+
+	if (unlikely(work == NULL)) {
+		FMDERR("%s:work is null", __func__);
+		return;
+	}
+
+	radio = container_of(work, struct tavarua_device, work.work);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
 	if (radio->pdata->config_i2s_gpio != NULL)
 		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
@@ -1178,9 +1305,14 @@
 static int tavarua_request_irq(struct tavarua_device *radio)
 {
 	int retval;
-	int irq = radio->pdata->irq;
-	if (radio == NULL)
+	int irq;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
 		return -EINVAL;
+	}
+
+	irq = radio->pdata->irq;
 
   /* A workqueue created with create_workqueue() will have one worker thread
    * for each CPU on the system; create_singlethread_workqueue(), instead,
@@ -1237,8 +1369,12 @@
 static int tavarua_disable_irq(struct tavarua_device *radio)
 {
 	int irq;
-	if (!radio)
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
 		return -EINVAL;
+	}
+
 	irq = radio->pdata->irq;
 	disable_irq_wake(irq);
 	free_irq(irq, radio);
@@ -1255,6 +1391,11 @@
 	unsigned int rdsMask = 0;
 	unsigned char value = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	adie_type_bahma = is_bahama();
 
 	switch (region) {
@@ -1435,9 +1576,17 @@
 */
 static int tavarua_search(struct tavarua_device *radio, int on, int dir)
 {
-	enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+	enum search_t srch;
 
 	FMDBG("In tavarua_search\n");
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
 	if (on) {
 		radio->registers[SRCHRDS1] = 0x00;
 		radio->registers[SRCHRDS2] = 0x00;
@@ -1503,6 +1652,11 @@
 	enum tavarua_region_t region = req_region;
 	unsigned char adie_type_bahma;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	adie_type_bahma = is_bahama();
 
 	/* Set freq band */
@@ -1671,6 +1825,17 @@
 	unsigned short chan;
 	unsigned int band_bottom;
 	unsigned int spacing;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	band_bottom = radio->region_params.band_low;
 	spacing  = 0.100 * FREQ_MUL;
 	/* read channel */
@@ -1716,6 +1881,12 @@
 	unsigned char cmd[] = {0x00, 0x00};
 	unsigned int spacing;
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	band_bottom = radio->region_params.band_low;
 	spacing  = 0.100 * FREQ_MUL;
 	if ((freq % 1600) == 800) {
@@ -1760,8 +1931,19 @@
 				size_t count, loff_t *ppos)
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
-	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+	struct kfifo *rds_buf;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
+
+	rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
 	/* block if no new data available */
 	while (!kfifo_len(rds_buf)) {
 		if (file->f_flags & O_NONBLOCK)
@@ -1810,6 +1992,17 @@
 	int bytes_left;
 	int chunk_index = 0;
 	unsigned char tx_data[XFR_REG_NUM];
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(data == NULL)) {
+		FMDERR("%s:data is null", __func__);
+		return -EINVAL;
+	}
+
 	/* Disable TX of this type first */
 	switch (radio->tx_mode) {
 	case TAVARUA_TX_RT:
@@ -1897,6 +2090,11 @@
 	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
 	int bahama_present = -ENODEV;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	INIT_DELAYED_WORK(&radio->work, read_int_stat);
 	if (!atomic_dec_and_test(&radio->users)) {
 		pr_err("%s: Device already in use."
@@ -2518,6 +2716,16 @@
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(capability == NULL)) {
+		FMDERR("%s:capability is null", __func__);
+		return -EINVAL;
+	}
+
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	sprintf(capability->bus_info, "I2C");
@@ -2553,6 +2761,12 @@
 	unsigned char i;
 	int retval = -EINVAL;
 
+	if (unlikely(qc == NULL)) {
+		FMDERR("%s:qc is null", __func__);
+		return -EINVAL;
+	}
+
+
 	for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
 		if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
 			memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2574,6 +2788,11 @@
 	int index = 0, offset = 0, addr = 0x0, val = 0;
 	int retval = 0, temp = 0, cnt = 0, j = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
 	/* Read the SPUR Table Size */
@@ -2651,6 +2870,15 @@
 	unsigned char xfr_buf[XFR_REG_NUM + 1];
 	int retval = 0, temp = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
 	/* zero initialize the buffer */
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
@@ -2725,6 +2953,11 @@
 	int ct = 0;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/*
 	Poking the MPX_DCC_BYPASS register to freeze the
 	value of MPX_DCC from changing while we access it
@@ -2844,6 +3077,16 @@
 	signed char ioc;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		break;
@@ -3059,6 +3302,18 @@
 	int extra_name_byte = 0;
 	int name_bytes = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL) ||
+		unlikely(ctrl->controls == NULL) ||
+		unlikely(ctrl->count <= 0)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	switch ((ctrl->controls[0]).id)	{
 	case V4L2_CID_RDS_TX_PS_NAME: {
 		FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3191,6 +3446,16 @@
 	unsigned int freq = 0, mpx_dcc = 0;
 	unsigned long curr = 0, prev = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
 	switch (ctrl->id) {
@@ -3797,6 +4062,16 @@
 	char rmssi = 0;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s:tuner is null", __func__);
+		return -EINVAL;
+	}
+
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -3863,6 +4138,17 @@
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 	int audmode;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s:tuner is null", __func__);
+		return -EINVAL;
+	}
+
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -3910,6 +4196,17 @@
 		struct v4l2_frequency *freq)
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	freq->type = V4L2_TUNER_RADIO;
 	return tavarua_get_freq(radio, freq);
 
@@ -3945,6 +4242,16 @@
 
 	FMDBG("%s\n", __func__);
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	if (freq->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 
@@ -4108,6 +4415,17 @@
 {
 	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
 	int dir;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(seek == NULL)) {
+		FMDERR("%s:seek is null", __func__);
+		return -EINVAL;
+	}
+
 	if (seek->seek_upward)
 		dir = SRCH_DIR_UP;
 	else
@@ -4159,6 +4477,11 @@
 	int retval;
 	unsigned char int_ctrl[XFR_REG_NUM];
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (!radio->lp_mode)
 		return 0;
 
@@ -4222,6 +4545,12 @@
 {
 	unsigned char lpm_buf[XFR_REG_NUM];
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio->lp_mode)
 		return 0;
 	FMDBG("%s\n", __func__);
@@ -4270,6 +4599,12 @@
 
 	int retval;
 	FMDBG("%s <%d>\n", __func__, state);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* set geographic region */
 	radio->region_params.region = TAVARUA_REGION_US;
 
@@ -4305,6 +4640,12 @@
 	int retval;
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio) {
 		users = atomic_read(&radio->users);
 		if (!users) {
@@ -4336,6 +4677,12 @@
 	int retval;
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio) {
 		users = atomic_read(&radio->users);
 
@@ -4380,8 +4727,12 @@
 	struct tavarua_device *radio = private_data;
 	int rx_on = radio->registers[RDCTRL] & FM_RECV;
 	int retval = 0;
-	if (!radio)
-		return -ENOMEM;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* RX */
 	FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
 	if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
@@ -4469,6 +4820,12 @@
 	int retval = 0;
 	int i = 0, j = 0;
 	FMDBG("%s: probe called\n", __func__);
+
+	if (unlikely(pdev == NULL)) {
+		FMDERR("%s:pdev is null", __func__);
+		return -EINVAL;
+	}
+
 	/* private data allocation */
 	radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
 	if (!radio) {
@@ -4593,6 +4950,11 @@
 	int i;
 	struct tavarua_device *radio = platform_get_drvdata(pdev);
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* disable irq */
 	tavarua_disable_irq(radio);
 
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9dd06ee..127a231 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -310,6 +310,7 @@
 		"Scalable High",
 		"Scalable High Intra",
 		"Multiview High",
+		"Constrained High",
 		NULL,
 	};
 	static const char * const vui_sar_idc[] = {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 3d69473..19f26f2 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1706,6 +1706,8 @@
 	dma_free_coherent(NULL, config->desc.size, config->desc.base,
 		config->desc.phys_base);
 
+	sps_free_endpoint(channel->pipe);
+
 	tspp_destroy_buffers(channel_id, channel);
 	if (channel->dma_pool) {
 		dma_pool_destroy(channel->dma_pool);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 421774f..b36faff 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -467,6 +467,7 @@
 	}
 
 	kfree(card->wr_pack_stats.packing_events);
+	kfree(card->cached_ext_csd);
 
 	put_device(&card->dev);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 997e14b..b295bb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1189,9 +1189,9 @@
 		mmc_set_timing(card->host, MMC_TIMING_LEGACY);
 		mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
 
-		err = mmc_select_hs(card, &card->cached_ext_csd);
+		err = mmc_select_hs(card, card->cached_ext_csd);
 	} else {
-		err = mmc_select_hs400(card, &card->cached_ext_csd);
+		err = mmc_select_hs400(card, card->cached_ext_csd);
 	}
 
 	return err;
@@ -1439,7 +1439,7 @@
 		err = mmc_get_ext_csd(card, &ext_csd);
 		if (err)
 			goto free_card;
-		memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
+		card->cached_ext_csd = ext_csd;
 		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
@@ -1637,15 +1637,12 @@
 	if (!oldcard)
 		host->card = card;
 
-	mmc_free_ext_csd(ext_csd);
 	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
-	mmc_free_ext_csd(ext_csd);
-
 	return err;
 }
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 95f0a04..c335be1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6962,7 +6962,7 @@
 
 static const struct of_device_id msmsdcc_dt_match[] = {
 	{.compatible = "qcom,msm-sdcc"},
-
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
 
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index e391a06..4d3a560 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -3113,6 +3113,7 @@
 #endif
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{.compatible = "qcom,sdhci-msm"},
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 76eb15b..12c5704 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -50,6 +50,7 @@
 
 /* module params */
 #define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
 
 static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -355,7 +356,7 @@
 	int	fw_cal_available;
 	int	user_cal_read;
 	int	user_cal_available;
-	int	user_cal_rcvd;
+	u32	user_cal_rcvd;
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
@@ -2134,7 +2135,7 @@
 			*user_buffer, size_t count, loff_t *position)
 {
 	int rc = 0;
-	int size = 0;
+	size_t size = 0;
 
 	if (!penv || !penv->device_opened || penv->user_cal_available)
 		return -EFAULT;
@@ -2142,7 +2143,7 @@
 	if (penv->user_cal_rcvd == 0 && count >= 4
 			&& !penv->user_cal_data) {
 		rc = copy_from_user((void *)&size, user_buffer, 4);
-		if (size > MAX_CALIBRATED_DATA_SIZE) {
+		if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
 			pr_err(DEVICE " invalid size to write %d\n", size);
 			return -EFAULT;
 		}
@@ -2161,7 +2162,8 @@
 	} else if (penv->user_cal_rcvd == 0 && count < 4)
 		return -EFAULT;
 
-	if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+	if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+	     MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
 		pr_err(DEVICE " invalid size to write %d\n", count +
 				penv->user_cal_rcvd);
 		rc = -ENOMEM;
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
index c55ed09..696c84f 100644
--- a/drivers/platform/msm/qpnp-clkdiv.c
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -202,6 +202,7 @@
 	if (!res) {
 		dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
 					__func__);
+		return -EINVAL;
 	}
 
 	q_clkdiv->slave = spmi->sid;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8572616..6ea4ea6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1285,6 +1285,21 @@
 	return 0;
 }
 
+static int
+qpnp_chg_vddmax_get(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 vddmax = 0;
+
+	rc = qpnp_chg_read(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+	if (rc) {
+		pr_err("Failed to write vddmax: %d\n", rc);
+		return rc;
+	}
+
+	return QPNP_CHG_V_MIN_MV + (int)vddmax * QPNP_CHG_V_STEP_MV;
+}
+
 /* JEITA compliance logic */
 static void
 qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -2077,6 +2092,8 @@
 		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
 				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
 				&& charger_in
+				&& !chip->bat_is_cool
+				&& !chip->bat_is_warm
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
@@ -3118,10 +3135,17 @@
 			count = 0;
 		} else {
 			if (count == CONSECUTIVE_COUNT) {
-				pr_info("End of Charging\n");
+				if (!chip->bat_is_cool && !chip->bat_is_warm) {
+					pr_info("End of Charging\n");
+					chip->chg_done = true;
+				} else {
+					pr_info("stop charging: battery is %s, vddmax = %d reached\n",
+						chip->bat_is_cool
+							? "cool" : "warm",
+						qpnp_chg_vddmax_get(chip));
+				}
 				chip->delta_vddmax_mv = 0;
 				qpnp_chg_set_appropriate_vddmax(chip);
-				chip->chg_done = true;
 				qpnp_chg_charge_en(chip, 0);
 				/* sleep for a second before enabling */
 				msleep(2000);
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 01dce2d..0d17026 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,7 +7,7 @@
 obj-$(CONFIG_THERMAL_TSENS)	+= msm_tsens.o
 obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
 obj-$(CONFIG_THERMAL_PM8XXX)	+= pm8xxx-tm.o
-obj-$(CONFIG_THERMAL_MONITOR)	+= msm_thermal.o
+obj-$(CONFIG_THERMAL_MONITOR)	+= msm_thermal.o msm_thermal-dev.o
 obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
 obj-$(CONFIG_THERMAL_TSENS8974)	+= msm8974-tsens.o
 obj-$(CONFIG_THERMAL_QPNP)	+= qpnp-temp-alarm.o
diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c
new file mode 100644
index 0000000..c34dd27
--- /dev/null
+++ b/drivers/thermal/msm_thermal-dev.c
@@ -0,0 +1,224 @@
+/* Copyright (c) 2013, The Linux Foundation. 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/kernel.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/msm_thermal_ioctl.h>
+#include <linux/msm_thermal.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+
+struct msm_thermal_ioctl_dev {
+	struct semaphore sem;
+	struct cdev char_dev;
+};
+
+static int msm_thermal_major;
+static struct class *thermal_class;
+static struct msm_thermal_ioctl_dev *msm_thermal_dev;
+
+static int msm_thermal_ioctl_open(struct inode *node, struct file *filep)
+{
+	int ret = 0;
+	struct msm_thermal_ioctl_dev *dev;
+
+	dev = container_of(node->i_cdev, struct msm_thermal_ioctl_dev,
+		char_dev);
+	filep->private_data = dev;
+
+	return ret;
+}
+
+static int msm_thermal_ioctl_release(struct inode *node, struct file *filep)
+{
+	pr_debug("%s: IOCTL: release\n", KBUILD_MODNAME);
+	return 0;
+}
+
+static long validate_and_copy(unsigned int *cmd, unsigned long *arg,
+	struct msm_thermal_ioctl *query)
+{
+	long ret = 0, err_val = 0;
+
+	if ((_IOC_TYPE(*cmd) != MSM_THERMAL_MAGIC_NUM) ||
+		(_IOC_NR(*cmd) >= MSM_CMD_MAX_NR)) {
+		ret = -ENOTTY;
+		goto validate_exit;
+	}
+
+	if (_IOC_DIR(*cmd) & _IOC_READ) {
+		err_val = !access_ok(VERIFY_WRITE, (void __user *)*arg,
+				_IOC_SIZE(*cmd));
+	} else if (_IOC_DIR(*cmd) & _IOC_WRITE) {
+		err_val = !access_ok(VERIFY_READ, (void __user *)*arg,
+				_IOC_SIZE(*cmd));
+	}
+	if (err_val) {
+		ret = -EFAULT;
+		goto validate_exit;
+	}
+
+	if (copy_from_user(query, (void __user *)(*arg),
+		sizeof(struct msm_thermal_ioctl))) {
+		ret = -EACCES;
+		goto validate_exit;
+	}
+
+	if (query->size != sizeof(struct msm_thermal_ioctl)) {
+		pr_err("%s: Invalid input argument size\n", __func__);
+		ret = -EINVAL;
+		goto validate_exit;
+	}
+
+	switch (*cmd) {
+	case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+	case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+		if (query->cpu_freq.cpu_num >= num_possible_cpus()) {
+			pr_err("%s: Invalid CPU number: %u\n", __func__,
+				query->cpu_freq.cpu_num);
+			ret = -EINVAL;
+			goto validate_exit;
+		}
+		break;
+	default:
+		ret = -ENOTTY;
+		goto validate_exit;
+		break;
+	}
+
+validate_exit:
+	return ret;
+}
+
+static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	long ret = 0;
+	struct msm_thermal_ioctl query;
+
+	pr_debug("%s: IOCTL: processing cmd:%u\n", KBUILD_MODNAME, cmd);
+
+	ret = validate_and_copy(&cmd, &arg, &query);
+	if (ret)
+		goto process_exit;
+
+	switch (cmd) {
+	case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+		ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+			query.cpu_freq.freq_req, true);
+		break;
+	case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+		ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+			query.cpu_freq.freq_req, false);
+		break;
+	default:
+		ret = -ENOTTY;
+		goto process_exit;
+	}
+process_exit:
+	return ret;
+}
+
+static const struct file_operations msm_thermal_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_thermal_ioctl_open,
+	.unlocked_ioctl = msm_thermal_ioctl_process,
+	.release = msm_thermal_ioctl_release,
+};
+
+int msm_thermal_ioctl_init()
+{
+	int ret = 0;
+	dev_t thermal_dev;
+	struct device *therm_device;
+
+	ret = alloc_chrdev_region(&thermal_dev, 0, 1,
+		MSM_THERMAL_IOCTL_NAME);
+	if (ret < 0) {
+		pr_err("%s: Error in allocating char device region. Err:%d\n",
+			KBUILD_MODNAME, ret);
+		goto ioctl_init_exit;
+	}
+
+	msm_thermal_major = MAJOR(thermal_dev);
+
+	thermal_class = class_create(THIS_MODULE, "msm_thermal");
+	if (IS_ERR(thermal_class)) {
+		pr_err("%s: Error in creating class\n",
+			KBUILD_MODNAME);
+		ret = PTR_ERR(thermal_class);
+		goto ioctl_class_fail;
+	}
+
+	therm_device = device_create(thermal_class, NULL, thermal_dev, NULL,
+				MSM_THERMAL_IOCTL_NAME);
+	if (IS_ERR(therm_device)) {
+		pr_err("%s: Error in creating character device\n",
+			KBUILD_MODNAME);
+		ret = PTR_ERR(therm_device);
+		goto ioctl_dev_fail;
+	}
+	msm_thermal_dev = kmalloc(sizeof(struct msm_thermal_ioctl_dev),
+				GFP_KERNEL);
+	if (!msm_thermal_dev) {
+		pr_err("%s: Error allocating memory\n",
+			KBUILD_MODNAME);
+		ret = -ENOMEM;
+		goto ioctl_clean_all;
+	}
+
+	memset(msm_thermal_dev, 0, sizeof(struct msm_thermal_ioctl_dev));
+	sema_init(&msm_thermal_dev->sem, 1);
+	cdev_init(&msm_thermal_dev->char_dev, &msm_thermal_fops);
+	ret = cdev_add(&msm_thermal_dev->char_dev, thermal_dev, 1);
+	if (ret < 0) {
+		pr_err("%s: Error in adding character device\n",
+			KBUILD_MODNAME);
+		goto ioctl_clean_all;
+	}
+
+	return ret;
+
+ioctl_clean_all:
+	device_destroy(thermal_class, thermal_dev);
+ioctl_dev_fail:
+	class_destroy(thermal_class);
+ioctl_class_fail:
+	unregister_chrdev_region(thermal_dev, 1);
+ioctl_init_exit:
+	return ret;
+}
+
+void msm_thermal_ioctl_cleanup()
+{
+	dev_t thermal_dev = MKDEV(msm_thermal_major, 0);
+
+	if (!msm_thermal_dev) {
+		pr_err("%s: Thermal IOCTL cleanup already done\n",
+			KBUILD_MODNAME);
+		return;
+	}
+
+	device_destroy(thermal_class, thermal_dev);
+	class_destroy(thermal_class);
+	cdev_del(&msm_thermal_dev->char_dev);
+	unregister_chrdev_region(thermal_dev, 1);
+	kfree(msm_thermal_dev);
+	msm_thermal_dev = NULL;
+	thermal_class = NULL;
+}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index e9bb553..c366086 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -35,13 +35,13 @@
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
 #include <linux/regulator/consumer.h>
+#include <linux/msm_thermal_ioctl.h>
 
+#define MAX_CURRENT_UA 1000000
 #define MAX_RAILS 5
 #define MAX_THRESHOLD 2
 
 static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = UINT_MAX;
-static uint32_t limited_min_freq;
 static struct delayed_work check_temp_work;
 static bool core_control_enabled;
 static uint32_t cpus_offlined;
@@ -52,11 +52,14 @@
 static struct kobject *cc_kobj;
 static struct work_struct timer_work;
 static struct task_struct *hotplug_task;
+static struct task_struct *freq_mitigation_task;
 static struct completion hotplug_notify_complete;
+static struct completion freq_mitigation_complete;
 
 static int enabled;
 static int rails_cnt;
 static int psm_rails_cnt;
+static int ocr_rail_cnt;
 static int limit_idx;
 static int limit_idx_low;
 static int limit_idx_high;
@@ -71,18 +74,38 @@
 static bool psm_nodes_called;
 static bool psm_probed;
 static bool hotplug_enabled;
+static bool freq_mitigation_enabled;
+static bool ocr_enabled;
+static bool ocr_nodes_called;
+static bool ocr_probed;
 static int *tsens_id_map;
 static DEFINE_MUTEX(vdd_rstr_mutex);
 static DEFINE_MUTEX(psm_mutex);
+static DEFINE_MUTEX(ocr_mutex);
+static uint32_t min_freq_limit;
+
+enum thermal_threshold {
+	HOTPLUG_THRESHOLD_HIGH,
+	HOTPLUG_THRESHOLD_LOW,
+	FREQ_THRESHOLD_HIGH,
+	FREQ_THRESHOLD_LOW,
+	THRESHOLD_MAX_NR,
+};
 
 struct cpu_info {
 	uint32_t cpu;
-	bool offline;
-	bool user_offline;
-	bool thresh_cleared;
 	const char *sensor_type;
 	uint32_t sensor_id;
-	struct sensor_threshold thresh[MAX_THRESHOLD];
+	bool offline;
+	bool user_offline;
+	bool hotplug_thresh_clear;
+	struct sensor_threshold threshold[THRESHOLD_MAX_NR];
+	bool max_freq;
+	uint32_t user_max_freq;
+	uint32_t user_min_freq;
+	uint32_t limited_max_freq;
+	uint32_t limited_min_freq;
+	bool freq_thresh_clear;
 };
 
 struct rail {
@@ -104,10 +127,12 @@
 	uint8_t mode;
 	struct kobj_attribute mode_attr;
 	struct rpm_regulator *reg;
+	struct regulator *phase_reg;
 	struct attribute_group attr_gp;
 };
 
 static struct psm_rail *psm_rails;
+static struct psm_rail *ocr_rails;
 static struct rail *rails;
 static struct cpu_info cpus[NR_CPUS];
 
@@ -123,6 +148,12 @@
 	PMIC_PWM_MODE   = RPM_REGULATOR_MODE_HPM,
 };
 
+enum ocr_request {
+	OPTIMUM_CURRENT_MIN,
+	OPTIMUM_CURRENT_MAX,
+	OPTIMUM_CURRENT_NR,
+};
+
 #define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
 	ko_attr.attr.mode = 444; \
@@ -148,6 +179,14 @@
 #define VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr) \
 	(container_of(attr, struct rail, level_attr));
 
+#define OCR_RW_ATTRIB(_rail, ko_attr, j, _name) \
+	ko_attr.attr.name = __stringify(_name); \
+	ko_attr.attr.mode = 644; \
+	ko_attr.show = ocr_reg_##_name##_show; \
+	ko_attr.store = ocr_reg_##_name##_store; \
+	sysfs_attr_init(&ko_attr.attr); \
+	_rail.attr_gp.attrs[j] = &ko_attr.attr;
+
 #define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
 	ko_attr.attr.mode = 644; \
@@ -163,11 +202,20 @@
 		unsigned long event, void *data)
 {
 	struct cpufreq_policy *policy = data;
+	uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq;
+	uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq;
 
 	switch (event) {
 	case CPUFREQ_INCOMPATIBLE:
-		cpufreq_verify_within_limits(policy, limited_min_freq,
-				limited_max_freq);
+		pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n",
+		KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req);
+
+		cpufreq_verify_within_limits(policy, min_freq_req,
+			max_freq_req);
+
+		if (max_freq_req < min_freq_req)
+			pr_err("Invalid frequency request Max:%u Min:%u\n",
+				max_freq_req, min_freq_req);
 		break;
 	}
 	return NOTIFY_OK;
@@ -193,9 +241,17 @@
 	return ret;
 }
 
+static void update_cpu_freq(int cpu)
+{
+	if (cpu_online(cpu)) {
+		if (cpufreq_update_policy(cpu))
+			pr_err("Unable to update policy for cpu:%d\n", cpu);
+	}
+}
+
 static int update_cpu_min_freq_all(uint32_t min)
 {
-	int cpu = 0;
+	uint32_t cpu = 0;
 	int ret = 0;
 
 	if (!freq_table_get) {
@@ -208,15 +264,17 @@
 	/* If min is larger than allowed max */
 	min = min(min, table[limit_idx_high].frequency);
 
-	limited_min_freq = min;
-
-	get_online_cpus();
-	for_each_online_cpu(cpu) {
-		if (cpufreq_update_policy(cpu))
-			pr_info("%s: Unable to update policy for cpu:%d\n",
-				KBUILD_MODNAME, cpu);
+	if (freq_mitigation_task) {
+		min_freq_limit = min;
+		complete(&freq_mitigation_complete);
+	} else {
+		get_online_cpus();
+		for_each_possible_cpu(cpu) {
+			cpus[cpu].limited_min_freq = min;
+			update_cpu_freq(cpu);
+		}
+		put_online_cpus();
 	}
-	put_online_cpus();
 
 	return ret;
 }
@@ -446,6 +504,92 @@
 	return count;
 }
 
+static int request_optimum_current(struct psm_rail *rail, enum ocr_request req)
+{
+	int ret = 0;
+
+	if ((!rail) || (req >= OPTIMUM_CURRENT_NR) ||
+		(req < 0)) {
+		pr_err("%s:%s Invalid input\n", KBUILD_MODNAME, __func__);
+		ret = -EINVAL;
+		goto request_ocr_exit;
+	}
+
+	ret = regulator_set_optimum_mode(rail->phase_reg,
+		(req == OPTIMUM_CURRENT_MAX) ? MAX_CURRENT_UA : 0);
+	if (ret < 0) {
+		pr_err("%s: Optimum current request failed\n", KBUILD_MODNAME);
+		goto request_ocr_exit;
+	}
+	ret = 0; /*regulator_set_optimum_mode returns the mode on success*/
+	pr_debug("%s: Requested optimum current mode: %d\n",
+		KBUILD_MODNAME, req);
+
+request_ocr_exit:
+	return ret;
+}
+
+static int ocr_set_mode_all(enum ocr_request req)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < ocr_rail_cnt; i++) {
+		if (ocr_rails[i].mode == req)
+			continue;
+		ret = request_optimum_current(&ocr_rails[i], req);
+		if (ret)
+			goto ocr_set_mode_exit;
+		ocr_rails[i].mode = req;
+	}
+
+ocr_set_mode_exit:
+	return ret;
+}
+
+static int ocr_reg_mode_show(struct kobject *kobj,
+	struct kobj_attribute *attr, char *buf)
+{
+	struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+	return snprintf(buf, PAGE_SIZE, "%d\n", reg->mode);
+}
+
+static ssize_t ocr_reg_mode_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	int val = 0;
+	struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+
+	if (!ocr_enabled)
+		return count;
+
+	mutex_lock(&ocr_mutex);
+	ret = kstrtoint(buf, 10, &val);
+	if (ret) {
+		pr_err("%s: Invalid input %s for mode\n",
+			KBUILD_MODNAME, buf);
+		goto done_ocr_store;
+	}
+
+	if ((val != OPTIMUM_CURRENT_MAX) &&
+		(val != OPTIMUM_CURRENT_MIN)) {
+		pr_err("%s: Invalid value %d for mode\n",
+			KBUILD_MODNAME, val);
+		goto done_ocr_store;
+	}
+
+	if (val != reg->mode) {
+		ret = request_optimum_current(reg, val);
+		if (ret)
+			goto done_ocr_store;
+		reg->mode = val;
+	}
+
+done_ocr_store:
+	mutex_unlock(&ocr_mutex);
+	return count;
+}
+
 static int psm_reg_mode_show(
 	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
@@ -607,27 +751,6 @@
 	return ret;
 }
 
-static int update_cpu_max_freq(int cpu, uint32_t max_freq)
-{
-	int ret = 0;
-
-	if (max_freq != UINT_MAX)
-		pr_info("%s: Limiting cpu%d max frequency to %d\n",
-				KBUILD_MODNAME, cpu, max_freq);
-	else
-		pr_info("%s: Max frequency reset for cpu%d\n",
-				KBUILD_MODNAME, cpu);
-	get_online_cpus();
-	for_each_online_cpu(cpu) {
-		if (cpufreq_update_policy(cpu))
-			pr_info("%s: Unable to update policy for cpu:%d\n",
-				KBUILD_MODNAME, cpu);
-	}
-	put_online_cpus();
-
-	return ret;
-}
-
 static int set_and_activate_threshold(uint32_t sensor_id,
 	struct sensor_threshold *threshold)
 {
@@ -788,10 +911,11 @@
 		mutex_lock(&core_control_mutex);
 		for_each_possible_cpu(cpu) {
 			if (hotplug_enabled &&
-				cpus[cpu].thresh_cleared) {
+				cpus[cpu].hotplug_thresh_clear) {
 				set_threshold(cpus[cpu].sensor_id,
-					cpus[cpu].thresh);
-				cpus[cpu].thresh_cleared = false;
+				&cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]);
+
+				cpus[cpu].hotplug_thresh_clear = false;
 			}
 			if (cpus[cpu].offline || cpus[cpu].user_offline)
 				mask |= BIT(cpu);
@@ -816,6 +940,63 @@
 }
 #endif
 
+static int do_ocr(void)
+{
+	struct tsens_device tsens_dev;
+	long temp = 0;
+	int ret = 0;
+	int i = 0, j = 0;
+	int auto_cnt = 0;
+
+	if (!ocr_enabled)
+		return ret;
+
+	mutex_lock(&ocr_mutex);
+	for (i = 0; i < max_tsens_num; i++) {
+		tsens_dev.sensor_num = tsens_id_map[i];
+		ret = tsens_get_temp(&tsens_dev, &temp);
+		if (ret) {
+			pr_debug("%s: Unable to read TSENS sensor %d\n",
+					__func__, tsens_dev.sensor_num);
+			auto_cnt++;
+			continue;
+		}
+
+		if (temp > msm_thermal_info.ocr_temp_degC) {
+			if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+				for (j = 0; j < ocr_rail_cnt; j++)
+					ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+			ret = ocr_set_mode_all(OPTIMUM_CURRENT_MAX);
+			if (ret)
+				pr_err("Error setting max optimum current\n");
+			goto do_ocr_exit;
+		} else if (temp <= (msm_thermal_info.ocr_temp_degC -
+			msm_thermal_info.ocr_temp_hyst_degC))
+			auto_cnt++;
+	}
+
+	if (auto_cnt == max_tsens_num ||
+		ocr_rails[0].init != OPTIMUM_CURRENT_NR) {
+		/* 'init' not equal to OPTIMUM_CURRENT_NR means this is the
+		** first polling iteration after device probe. During first
+		** iteration, if temperature is less than the set point, clear
+		** the max current request made and reset the 'init'.
+		*/
+		if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+			for (j = 0; j < ocr_rail_cnt; j++)
+				ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+		ret = ocr_set_mode_all(OPTIMUM_CURRENT_MIN);
+		if (ret) {
+			pr_err("Error setting min optimum current\n");
+			goto do_ocr_exit;
+		}
+	}
+
+do_ocr_exit:
+	mutex_unlock(&ocr_mutex);
+	return ret;
+}
+
 static int do_vdd_restriction(void)
 {
 	struct tsens_device tsens_dev;
@@ -915,14 +1096,14 @@
 
 static void __ref do_freq_control(long temp)
 {
-	int cpu = 0;
-	uint32_t max_freq = limited_max_freq;
+	uint32_t cpu = 0;
+	uint32_t max_freq = cpus[cpu].limited_max_freq;
 
 	if (temp >= msm_thermal_info.limit_temp_degC) {
 		if (limit_idx == limit_idx_low)
 			return;
 
-		limit_idx -= msm_thermal_info.freq_step;
+		limit_idx -= msm_thermal_info.bootup_freq_step;
 		if (limit_idx < limit_idx_low)
 			limit_idx = limit_idx_low;
 		max_freq = table[limit_idx].frequency;
@@ -931,7 +1112,7 @@
 		if (limit_idx == limit_idx_high)
 			return;
 
-		limit_idx += msm_thermal_info.freq_step;
+		limit_idx += msm_thermal_info.bootup_freq_step;
 		if (limit_idx >= limit_idx_high) {
 			limit_idx = limit_idx_high;
 			max_freq = UINT_MAX;
@@ -939,16 +1120,18 @@
 			max_freq = table[limit_idx].frequency;
 	}
 
-	if (max_freq == limited_max_freq)
+	if (max_freq == cpus[cpu].limited_max_freq)
 		return;
 
-	limited_max_freq = max_freq;
 	/* Update new limits */
+	get_online_cpus();
 	for_each_possible_cpu(cpu) {
-		if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+		if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu)))
 			continue;
-		update_cpu_max_freq(cpu, max_freq);
+		cpus[cpu].limited_max_freq = max_freq;
+		update_cpu_freq(cpu);
 	}
+	put_online_cpus();
 }
 
 static void __ref check_temp(struct work_struct *work)
@@ -977,6 +1160,7 @@
 	do_core_control(temp);
 	do_vdd_restriction();
 	do_psm();
+	do_ocr();
 	do_freq_control(temp);
 
 reschedule:
@@ -988,7 +1172,7 @@
 static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
 		unsigned long action, void *hcpu)
 {
-	unsigned int cpu = (unsigned long)hcpu;
+	uint32_t cpu = (uint32_t)hcpu;
 
 	if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
 		if (core_control_enabled &&
@@ -1064,7 +1248,7 @@
 		break;
 	}
 	if (hotplug_task) {
-		cpu_node->thresh_cleared = true;
+		cpu_node->hotplug_thresh_clear = true;
 		complete(&hotplug_notify_complete);
 	} else {
 		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
@@ -1076,7 +1260,7 @@
 {
 	struct tsens_device tsens_dev;
 	long temp = 0;
-	int cpu = 0;
+	uint32_t cpu = 0;
 
 	if (!hotplug_enabled)
 		return 0;
@@ -1113,7 +1297,8 @@
 
 static void hotplug_init(void)
 {
-	int cpu = 0;
+	uint32_t cpu = 0;
+	struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
 
 	if (hotplug_task)
 		return;
@@ -1122,23 +1307,22 @@
 		goto init_kthread;
 
 	for_each_possible_cpu(cpu) {
-		cpus[cpu].cpu = (uint32_t)cpu;
-		cpus[cpu].thresh_cleared = false;
 		cpus[cpu].sensor_id =
 			sensor_get_id((char *)cpus[cpu].sensor_type);
 		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
 			continue;
-		cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
-		cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
-		cpus[cpu].thresh[0].notify = hotplug_notify;
-		cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
 
-		cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+		hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH];
+		low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW];
+		hi_thresh->temp = msm_thermal_info.hotplug_temp_degC;
+		hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		low_thresh->temp = msm_thermal_info.hotplug_temp_degC -
 				msm_thermal_info.hotplug_temp_hysteresis_degC;
-		cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
-		cpus[cpu].thresh[1].notify = hotplug_notify;
-		cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
-		set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
+		low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		hi_thresh->notify = low_thresh->notify = hotplug_notify;
+		hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+
+		set_threshold(cpus[cpu].sensor_id, hi_thresh);
 	}
 init_kthread:
 	init_completion(&hotplug_notify_complete);
@@ -1156,6 +1340,167 @@
 		kthread_stop(hotplug_task);
 }
 
+static __ref int do_freq_mitigation(void *data)
+{
+	int ret = 0;
+	uint32_t cpu = 0, max_freq_req = 0, min_freq_req = 0;
+
+	while (!kthread_should_stop()) {
+		wait_for_completion(&freq_mitigation_complete);
+		INIT_COMPLETION(freq_mitigation_complete);
+
+		get_online_cpus();
+		for_each_possible_cpu(cpu) {
+			max_freq_req = (cpus[cpu].max_freq) ?
+					msm_thermal_info.freq_limit :
+					UINT_MAX;
+			max_freq_req = min(max_freq_req,
+					cpus[cpu].user_max_freq);
+
+			min_freq_req = max(min_freq_limit,
+					cpus[cpu].user_min_freq);
+
+			if ((max_freq_req == cpus[cpu].limited_max_freq)
+				&& (min_freq_req ==
+				cpus[cpu].limited_min_freq))
+				goto reset_threshold;
+
+			cpus[cpu].limited_max_freq = max_freq_req;
+			cpus[cpu].limited_min_freq = min_freq_req;
+			update_cpu_freq(cpu);
+reset_threshold:
+			if (freq_mitigation_enabled &&
+				cpus[cpu].freq_thresh_clear) {
+				set_threshold(cpus[cpu].sensor_id,
+				&cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]);
+
+				cpus[cpu].freq_thresh_clear = false;
+			}
+		}
+		put_online_cpus();
+	}
+	return ret;
+}
+
+static int freq_mitigation_notify(enum thermal_trip_type type,
+	int temp, void *data)
+{
+	struct cpu_info *cpu_node = (struct cpu_info *) data;
+
+	pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME,
+		cpu_node->sensor_type, temp);
+
+	if (!(msm_thermal_info.freq_mitig_control_mask &
+		BIT(cpu_node->cpu)))
+		return 0;
+
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		if (!cpu_node->max_freq) {
+			pr_info("%s: Mitigating cpu %d frequency to %d\n",
+				KBUILD_MODNAME, cpu_node->cpu,
+				msm_thermal_info.freq_limit);
+
+			cpu_node->max_freq = true;
+		}
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		if (cpu_node->max_freq) {
+			pr_info("%s: Removing frequency mitigation for cpu%d\n",
+				KBUILD_MODNAME, cpu_node->cpu);
+
+			cpu_node->max_freq = false;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (freq_mitigation_task) {
+		cpu_node->freq_thresh_clear = true;
+		complete(&freq_mitigation_complete);
+	} else {
+		pr_err("%s: Frequency mitigation task is not initialized\n",
+			KBUILD_MODNAME);
+	}
+
+	return 0;
+}
+
+static void freq_mitigation_init(void)
+{
+	uint32_t cpu = 0;
+	struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
+
+	if (freq_mitigation_task)
+		return;
+	if (!freq_mitigation_enabled)
+		goto init_freq_thread;
+
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu)))
+			continue;
+		hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH];
+		low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW];
+
+		hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc;
+		hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc -
+			msm_thermal_info.freq_mitig_temp_hysteresis_degc;
+		low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		hi_thresh->notify = low_thresh->notify =
+			freq_mitigation_notify;
+		hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+
+		set_threshold(cpus[cpu].sensor_id, hi_thresh);
+	}
+init_freq_thread:
+	init_completion(&freq_mitigation_complete);
+	freq_mitigation_task = kthread_run(do_freq_mitigation, NULL,
+		"msm_thermal:freq_mitig");
+
+	if (IS_ERR(freq_mitigation_task)) {
+		pr_err("%s: Failed to create frequency mitigation thread\n",
+				KBUILD_MODNAME);
+		return;
+	}
+}
+
+int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq, bool is_max)
+{
+	int ret = 0;
+
+	if (cpu >= num_possible_cpus()) {
+		pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+		ret = -EINVAL;
+		goto set_freq_exit;
+	}
+
+	if (is_max) {
+		if (cpus[cpu].user_max_freq == freq)
+			goto set_freq_exit;
+
+		cpus[cpu].user_max_freq = freq;
+	} else {
+		if (cpus[cpu].user_min_freq == freq)
+			goto set_freq_exit;
+
+		cpus[cpu].user_min_freq = freq;
+	}
+
+	if (freq_mitigation_task) {
+		complete(&freq_mitigation_complete);
+	} else {
+		pr_err("%s: Frequency mitigation task is not initialized\n",
+			KBUILD_MODNAME);
+		ret = -ESRCH;
+		goto set_freq_exit;
+	}
+
+set_freq_exit:
+	return ret;
+}
+
 /*
  * We will reset the cpu frequencies limits here. The core online/offline
  * status will be carried over to the process stopping the msm_thermal, as
@@ -1163,21 +1508,20 @@
  */
 static void __ref disable_msm_thermal(void)
 {
-	int cpu = 0;
+	uint32_t cpu = 0;
 
 	/* make sure check_temp is no longer running */
 	cancel_delayed_work(&check_temp_work);
 	flush_scheduled_work();
 
-	if (limited_max_freq == UINT_MAX)
-		return;
-
-	limited_max_freq = UINT_MAX;
 	get_online_cpus();
-	for_each_online_cpu(cpu) {
-		if (cpufreq_update_policy(cpu))
-			pr_info("%s: Unable to update policy for cpu:%d\n",
-				KBUILD_MODNAME, cpu);
+	for_each_possible_cpu(cpu) {
+		if (cpus[cpu].limited_max_freq == UINT_MAX &&
+			cpus[cpu].limited_min_freq == 0)
+			continue;
+		cpus[cpu].limited_max_freq = UINT_MAX;
+		cpus[cpu].limited_min_freq = 0;
+		update_cpu_freq(cpu);
 	}
 	put_online_cpus();
 }
@@ -1190,6 +1534,7 @@
 	if (!enabled) {
 		disable_msm_thermal();
 		hotplug_init();
+		freq_mitigation_init();
 	} else
 		pr_info("%s: no action for enabled = %d\n",
 			KBUILD_MODNAME, enabled);
@@ -1257,7 +1602,7 @@
 {
 	int ret = 0;
 	uint32_t val = 0;
-	int cpu;
+	uint32_t cpu;
 
 	mutex_lock(&core_control_mutex);
 	ret = kstrtouint(buf, 10, &val);
@@ -1422,6 +1767,7 @@
 int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
+	uint32_t cpu;
 
 	BUG_ON(!pdata);
 	tsens_get_max_sensor_num(&max_tsens_num);
@@ -1433,13 +1779,15 @@
 		return -EINVAL;
 
 	enabled = 1;
-
+	for_each_possible_cpu(cpu) {
+		cpus[cpu].limited_max_freq = UINT_MAX;
+		cpus[cpu].limited_min_freq = 0;
+	}
 	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
 			CPUFREQ_POLICY_NOTIFIER);
 	if (ret)
 		pr_err("%s: cannot register cpufreq notifier\n",
 			KBUILD_MODNAME);
-
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
@@ -1449,6 +1797,42 @@
 	return ret;
 }
 
+static int ocr_reg_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	int i, j;
+
+	for (i = 0; i < ocr_rail_cnt; i++) {
+		/* Check if vdd_restriction has already initialized any
+		 * regualtor handle. If so use the same handle.*/
+		for (j = 0; j < rails_cnt; j++) {
+			if (!strcmp(ocr_rails[i].name, rails[j].name)) {
+				if (rails[j].reg == NULL)
+					break;
+				ocr_rails[i].phase_reg = rails[j].reg;
+				goto reg_init;
+			}
+
+		}
+		ocr_rails[i].phase_reg = devm_regulator_get(&pdev->dev,
+					ocr_rails[i].name);
+		if (IS_ERR_OR_NULL(ocr_rails[i].phase_reg)) {
+			ret = PTR_ERR(ocr_rails[i].phase_reg);
+			if (ret != -EPROBE_DEFER) {
+				pr_err("%s, could not get regulator: %s\n",
+					__func__, ocr_rails[i].name);
+				ocr_rails[i].phase_reg = NULL;
+				ocr_rails[i].mode = 0;
+				ocr_rails[i].init = 0;
+			}
+			return ret;
+		}
+reg_init:
+		ocr_rails[i].mode = OPTIMUM_CURRENT_MIN;
+	}
+	return ret;
+}
+
 static int vdd_restriction_reg_init(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -1618,6 +2002,80 @@
 	return rc;
 }
 
+static int msm_thermal_add_ocr_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *ocr_kobj = NULL;
+	struct kobject *ocr_reg_kobj[MAX_RAILS] = {0};
+	int rc = 0;
+	int i = 0;
+
+	if (!ocr_probed) {
+		ocr_nodes_called = true;
+		return rc;
+	}
+
+	if (ocr_probed && ocr_rail_cnt == 0)
+		return rc;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		rc = -ENOENT;
+		goto ocr_node_exit;
+	}
+
+	ocr_kobj = kobject_create_and_add("opt_curr_req", module_kobj);
+	if (!ocr_kobj) {
+		pr_err("%s: cannot create ocr kobject\n", KBUILD_MODNAME);
+		rc = -ENOMEM;
+		goto ocr_node_exit;
+	}
+
+	for (i = 0; i < ocr_rail_cnt; i++) {
+		ocr_reg_kobj[i] = kobject_create_and_add(ocr_rails[i].name,
+					ocr_kobj);
+		if (!ocr_reg_kobj[i]) {
+			pr_err("%s: cannot create for kobject for %s\n",
+					KBUILD_MODNAME, ocr_rails[i].name);
+			rc = -ENOMEM;
+			goto ocr_node_exit;
+		}
+		ocr_rails[i].attr_gp.attrs = kzalloc( \
+				sizeof(struct attribute *) * 2, GFP_KERNEL);
+		if (!ocr_rails[i].attr_gp.attrs) {
+			rc = -ENOMEM;
+			goto ocr_node_exit;
+		}
+
+		OCR_RW_ATTRIB(ocr_rails[i], ocr_rails[i].mode_attr, 0, mode);
+		ocr_rails[i].attr_gp.attrs[1] = NULL;
+
+		rc = sysfs_create_group(ocr_reg_kobj[i], &ocr_rails[i].attr_gp);
+		if (rc) {
+			pr_err("%s: cannot create attribute group for %s\n",
+				KBUILD_MODNAME, ocr_rails[i].name);
+			goto ocr_node_exit;
+		}
+	}
+
+ocr_node_exit:
+	if (rc) {
+		for (i = 0; i < ocr_rail_cnt; i++) {
+			if (ocr_reg_kobj[i])
+				kobject_del(ocr_reg_kobj[i]);
+			if (ocr_rails[i].attr_gp.attrs) {
+				kfree(ocr_rails[i].attr_gp.attrs);
+				ocr_rails[i].attr_gp.attrs = NULL;
+			}
+		}
+		if (ocr_kobj)
+			kobject_del(ocr_kobj);
+	}
+	return rc;
+}
+
 static int msm_thermal_add_psm_nodes(void)
 {
 	struct kobject *module_kobj = NULL;
@@ -1790,6 +2248,83 @@
 	return ret;
 }
 
+static int probe_ocr(struct device_node *node, struct msm_thermal_data *data,
+		struct platform_device *pdev)
+{
+	int ret = 0;
+	int j = 0;
+	char *key = NULL;
+
+	if (ocr_probed) {
+		pr_info("%s: Nodes already probed\n",
+			__func__);
+		goto read_ocr_exit;
+	}
+	ocr_rails = NULL;
+
+	key = "qti,pmic-opt-curr-temp";
+	ret = of_property_read_u32(node, key, &data->ocr_temp_degC);
+	if (ret)
+		goto read_ocr_fail;
+
+	key = "qti,pmic-opt-curr-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data->ocr_temp_hyst_degC);
+	if (ret)
+		goto read_ocr_fail;
+
+	key = "qti,pmic-opt-curr-regs";
+	ocr_rail_cnt = of_property_count_strings(node, key);
+	ocr_rails = kzalloc(sizeof(struct psm_rail) * ocr_rail_cnt,
+			GFP_KERNEL);
+	if (!ocr_rails) {
+		pr_err("%s: Fail to allocate memory for ocr rails\n", __func__);
+		ocr_rail_cnt = 0;
+		return -ENOMEM;
+	}
+
+	for (j = 0; j < ocr_rail_cnt; j++) {
+		ret = of_property_read_string_index(node, key, j,
+				&ocr_rails[j].name);
+		if (ret)
+			goto read_ocr_fail;
+		ocr_rails[j].phase_reg = NULL;
+		ocr_rails[j].init = OPTIMUM_CURRENT_MAX;
+	}
+
+	if (ocr_rail_cnt) {
+		ret = ocr_reg_init(pdev);
+		if (ret) {
+			pr_info("%s:Failed to get regulators. KTM continues.\n",
+					__func__);
+			goto read_ocr_fail;
+		}
+		ocr_enabled = true;
+		ocr_nodes_called = false;
+		/*
+		 * Vote for max optimum current by default until we have made
+		 * our first temp reading
+		 */
+		if (ocr_set_mode_all(OPTIMUM_CURRENT_MAX))
+			pr_err("Set max optimum current failed\n");
+	}
+
+read_ocr_fail:
+	ocr_probed = true;
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			__func__, node->full_name, key);
+		if (ocr_rails)
+			kfree(ocr_rails);
+		ocr_rails = NULL;
+		ocr_rail_cnt = 0;
+	}
+	if (ret == -EPROBE_DEFER)
+		ocr_probed = false;
+read_ocr_exit:
+	return ret;
+}
+
 static int probe_psm(struct device_node *node, struct msm_thermal_data *data,
 		struct platform_device *pdev)
 {
@@ -1854,9 +2389,9 @@
 		struct platform_device *pdev)
 {
 	char *key = NULL;
-	int cpu_cnt = 0;
+	uint32_t cpu_cnt = 0;
 	int ret = 0;
-	int cpu = 0;
+	uint32_t cpu = 0;
 
 	if (num_possible_cpus() > 1) {
 		core_control_enabled = 1;
@@ -1901,6 +2436,7 @@
 		cpus[cpu].cpu = cpu;
 		cpus[cpu].offline = 0;
 		cpus[cpu].user_offline = 0;
+		cpus[cpu].hotplug_thresh_clear = false;
 		ret = of_property_read_string_index(node, key, cpu,
 				&cpus[cpu].sensor_type);
 		if (ret)
@@ -1928,6 +2464,55 @@
 	return ret;
 }
 
+static int probe_freq_mitigation(struct device_node *node,
+		struct msm_thermal_data *data,
+		struct platform_device *pdev)
+{
+	char *key = NULL;
+	int ret = 0;
+	uint32_t cpu;
+
+	key = "qcom,freq-mitigation-temp";
+	ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
+	if (ret)
+		goto PROBE_FREQ_EXIT;
+
+	key = "qcom,freq-mitigation-temp-hysteresis";
+	ret = of_property_read_u32(node, key,
+		&data->freq_mitig_temp_hysteresis_degc);
+	if (ret)
+		goto PROBE_FREQ_EXIT;
+
+	key = "qcom,freq-mitigation-value";
+	ret = of_property_read_u32(node, key, &data->freq_limit);
+	if (ret)
+		goto PROBE_FREQ_EXIT;
+
+	key = "qcom,freq-mitigation-control-mask";
+	ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask);
+	if (ret)
+		goto PROBE_FREQ_EXIT;
+
+	freq_mitigation_enabled = 1;
+	for_each_possible_cpu(cpu) {
+		cpus[cpu].max_freq = false;
+		cpus[cpu].user_max_freq = UINT_MAX;
+		cpus[cpu].user_min_freq = 0;
+		cpus[cpu].limited_max_freq = UINT_MAX;
+		cpus[cpu].limited_min_freq = 0;
+		cpus[cpu].freq_thresh_clear = false;
+	}
+
+PROBE_FREQ_EXIT:
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			__func__, node->full_name, key);
+		freq_mitigation_enabled = 0;
+	}
+	return ret;
+}
+
 static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -1958,18 +2543,23 @@
 		goto fail;
 
 	key = "qcom,freq-step";
-	ret = of_property_read_u32(node, key, &data.freq_step);
+	ret = of_property_read_u32(node, key, &data.bootup_freq_step);
 	if (ret)
 		goto fail;
 
 	key = "qcom,freq-control-mask";
-	ret = of_property_read_u32(node, key, &data.freq_control_mask);
+	ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask);
 
 	ret = probe_cc(node, &data, pdev);
+
+	ret = probe_freq_mitigation(node, &data, pdev);
 	/*
 	 * Probe optional properties below. Call probe_psm before
 	 * probe_vdd_rstr because rpm_regulator_get has to be called
 	 * before devm_regulator_get
+	 * probe_ocr should be called after probe_vdd_rstr to reuse the
+	 * regualtor handle. calling devm_regulator_get more than once
+	 * will fail.
 	 */
 	ret = probe_psm(node, &data, pdev);
 	if (ret == -EPROBE_DEFER)
@@ -1977,6 +2567,9 @@
 	ret = probe_vdd_rstr(node, &data, pdev);
 	if (ret == -EPROBE_DEFER)
 		goto fail;
+	ret = probe_ocr(node, &data, pdev);
+	if (ret == -EPROBE_DEFER)
+		goto fail;
 
 	/*
 	 * In case sysfs add nodes get called before probe function.
@@ -1990,6 +2583,11 @@
 		msm_thermal_add_vdd_rstr_nodes();
 		vdd_rstr_nodes_called = false;
 	}
+	if (ocr_nodes_called) {
+		msm_thermal_add_ocr_nodes();
+		ocr_nodes_called = false;
+	}
+	msm_thermal_ioctl_init();
 	ret = msm_thermal_init(&data);
 
 	return ret;
@@ -2001,6 +2599,11 @@
 	return ret;
 }
 
+static int msm_thermal_dev_exit(struct platform_device *inp_dev)
+{
+	msm_thermal_ioctl_cleanup();
+	return 0;
+}
 
 static struct of_device_id msm_thermal_match_table[] = {
 	{.compatible = "qcom,msm-thermal"},
@@ -2014,6 +2617,7 @@
 		.owner = THIS_MODULE,
 		.of_match_table = msm_thermal_match_table,
 	},
+	.remove = msm_thermal_dev_exit,
 };
 
 int __init msm_thermal_device_init(void)
@@ -2027,6 +2631,7 @@
 		msm_thermal_add_cc_nodes();
 	msm_thermal_add_psm_nodes();
 	msm_thermal_add_vdd_rstr_nodes();
+	msm_thermal_add_ocr_nodes();
 	alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
 			thermal_rtc_callback);
 	INIT_WORK(&timer_work, timer_work_fn);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index dd04f49..7ae0a54 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1063,7 +1063,7 @@
 
 	memset(kbuf, 0, 10);
 
-	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+	if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
 		return -EFAULT;
 
 	if (sscanf(kbuf, "%x", &data) != 1)
@@ -1088,7 +1088,7 @@
 
 	memset(kbuf, 0, 10);
 
-	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+	if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
 		return -EFAULT;
 
 	if (sscanf(kbuf, "%x", &temp) != 1)
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index b49e08e..01edf92 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -28,3 +28,10 @@
 	  seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller
 	  fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status
 	  to HAL layer to reset the controller.
+
+config FB_MSM_MDSS_MDP3
+	depends on FB_MSM_MDSS
+	bool "MDP3 display controller"
+	---help---
+	The MDP3 provides support for an older version display controller
+	included in latest display sub-system, known as MDSS.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 0fc6245..fd03b63 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,6 @@
 mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
 mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
-obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o
 
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
 mdss-mdp-objs += mdss_mdp_pp.o
@@ -17,7 +17,7 @@
 endif
 
 dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
-obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += dsi-v2.o
 
 mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o
 mdss-dsi-objs += mdss_dsi_panel.o
@@ -42,4 +42,8 @@
 
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
 
+ifeq ($(CONFIG_FB_MSM_MDSS_MDP3),y)
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += dsi_status_v2.o
+else
 obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
+endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index aa41cb2..4173e3f 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -78,6 +78,9 @@
 
 	if (status) {
 		MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
+
+		/* Writing of an extra 0 needed to clear error bits */
+		MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
@@ -220,6 +223,12 @@
 
 	spin_unlock(&ctrl->mdp_lock);
 
+	if (isr & DSI_INTR_BTA_DONE)
+		complete(&ctrl->bta_comp);
+
+	if (isr & DSI_INTR_CMD_MDP_DONE)
+		complete(&ctrl->mdp_comp);
+
 	return IRQ_HANDLED;
 }
 
@@ -261,6 +270,49 @@
 	}
 }
 
+static int msm_dsi_wait4mdp_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int rc;
+	unsigned long flag;
+
+	spin_lock_irqsave(&ctrl->mdp_lock, flag);
+	INIT_COMPLETION(ctrl->mdp_comp);
+	msm_dsi_set_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+	spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+	rc = wait_for_completion_timeout(&ctrl->mdp_comp,
+			msecs_to_jiffies(VSYNC_PERIOD * 4));
+
+	if (rc == 0) {
+		pr_err("DSI wait 4 mdp done time out\n");
+		rc = -ETIME;
+	} else if (!IS_ERR_VALUE(rc)) {
+		rc = 0;
+	}
+
+	msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+
+	return rc;
+}
+
+void msm_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int rc;
+	u32 dsi_status;
+	unsigned char *ctrl_base = dsi_host_private->dsi_base;
+
+	if (ctrl->panel_mode == DSI_VIDEO_MODE)
+		return;
+
+	dsi_status = MIPI_INP(ctrl_base + DSI_STATUS);
+	if (dsi_status & 0x04) {
+		pr_debug("dsi command engine is busy\n");
+		rc = msm_dsi_wait4mdp_done(ctrl);
+		if (rc)
+			pr_err("Timed out waiting for mdp done");
+	}
+}
+
 static int msm_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int rc;
@@ -883,17 +935,18 @@
 	if (req->cb)
 		req->cb(len);
 }
-void msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
 	int dsi_on;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->mutex);
 	dsi_on = dsi_host_private->dsi_on;
 	mutex_unlock(&ctrl->mutex);
 	if (!dsi_on) {
 		pr_err("try to send DSI commands while dsi is off\n");
-		return;
+		return ret;
 	}
 
 	mutex_lock(&ctrl->cmd_mutex);
@@ -901,7 +954,7 @@
 
 	if (!req) {
 		mutex_unlock(&ctrl->cmd_mutex);
-		return;
+		return ret;
 	}
 
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
@@ -916,6 +969,7 @@
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
 
 	mutex_unlock(&ctrl->cmd_mutex);
+	return 0;
 }
 
 static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
@@ -1166,6 +1220,38 @@
 	return 0;
 }
 
+int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int ret = 0;
+
+	if (ctrl_pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return 0;
+	}
+
+	mutex_lock(&ctrl_pdata->cmd_mutex);
+	msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1);
+	msm_dsi_cmd_mdp_busy(ctrl_pdata);
+	msm_dsi_set_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+	INIT_COMPLETION(ctrl_pdata->bta_comp);
+
+	/* BTA trigger */
+	MIPI_OUTP(dsi_host_private->dsi_base + DSI_CMD_MODE_BTA_SW_TRIGGER,
+									0x01);
+	wmb();
+	ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+									HZ/10);
+	msm_dsi_clear_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+	msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0);
+	mutex_unlock(&ctrl_pdata->cmd_mutex);
+
+	if (ret <= 0)
+		pr_err("%s: DSI BTA error: %i\n", __func__, __LINE__);
+
+	pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+	return ret;
+}
+
 static void msm_dsi_debug_enable_clock(int on)
 {
 	if (dsi_host_private->debug_enable_clk)
@@ -1329,6 +1415,7 @@
 {
 	init_completion(&ctrl->dma_comp);
 	init_completion(&ctrl->mdp_comp);
+	init_completion(&ctrl->bta_comp);
 	init_completion(&ctrl->video_comp);
 	spin_lock_init(&ctrl->irq_lock);
 	spin_lock_init(&ctrl->mdp_lock);
@@ -1339,6 +1426,7 @@
 	dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
 	ctrl->cmdlist_commit = msm_dsi_cmdlist_commit;
 	ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
+	ctrl->check_status = msm_dsi_bta_status_check;
 }
 
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index cec9774..b297452 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -17,6 +17,8 @@
 
 #define DSI_INTR_ERROR_MASK			BIT(25)
 #define DSI_INTR_ERROR				BIT(24)
+#define DSI_INTR_BTA_DONE_MASK			BIT(21)
+#define DSI_INTR_BTA_DONE			BIT(20)
 #define DSI_INTR_VIDEO_DONE_MASK		BIT(17)
 #define DSI_INTR_VIDEO_DONE			BIT(16)
 #define DSI_INTR_CMD_MDP_DONE_MASK		BIT(9)
@@ -24,6 +26,8 @@
 #define DSI_INTR_CMD_DMA_DONE_MASK		BIT(1)
 #define DSI_INTR_CMD_DMA_DONE			BIT(0)
 
+#define DSI_BTA_TERM				BIT(1)
+
 #define DSI_CTRL				0x0000
 #define DSI_STATUS				0x0004
 #define DSI_FIFO_STATUS			0x0008
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
new file mode 100644
index 0000000..d62ddf3
--- /dev/null
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 2013, The Linux Foundation. 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/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdp3_ctrl.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+/**
+ * dsi_status_data - Stores all the data necessary for this module
+ * @fb_notif: Used to egister for the fb events
+ * @live_status: Delayed worker structure, used to associate the
+ * delayed worker function
+ * @mfd: Used to store the msm_fb_data_type received when the notifier
+ * call back happens
+ * @root: Stores the dir created by debuugfs
+ * @debugfs_reset_panel: The debugfs variable used to inject errors
+ */
+
+struct dsi_status_data {
+	struct notifier_block fb_notifier;
+	struct delayed_work check_status;
+	struct msm_fb_data_type *mfd;
+	uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+void check_dsi_ctrl_status(struct work_struct *work)
+{
+	struct dsi_status_data *pdsi_status = NULL;
+	struct mdss_panel_data *pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdp3_session_data *mdp3_session = NULL;
+	int ret = 0;
+
+	pdsi_status = container_of(to_delayed_work(work),
+		struct dsi_status_data, check_status);
+	if (!pdsi_status) {
+		pr_err("%s: DSI status data not available\n", __func__);
+		return;
+	}
+
+	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("%s: Panel data not available\n", __func__);
+		return;
+	}
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+							panel_data);
+	if (!ctrl_pdata || !ctrl_pdata->check_status) {
+		pr_err("%s: DSI ctrl or status_check callback not avilable\n",
+								__func__);
+		return;
+	}
+	mdp3_session = pdsi_status->mfd->mdp.private1;
+	mutex_lock(&mdp3_session->lock);
+
+	ret = ctrl_pdata->check_status(ctrl_pdata);
+
+	mutex_unlock(&mdp3_session->lock);
+
+	if ((pdsi_status->mfd->panel_power_on)) {
+		if (ret > 0) {
+			schedule_delayed_work(&pdsi_status->check_status,
+				msecs_to_jiffies(pdsi_status->check_interval));
+		} else {
+			char *envp[2] = {"PANEL_ALIVE=0", NULL};
+			pdata->panel_info.panel_dead = true;
+			ret = kobject_uevent_env(
+				&pdsi_status->mfd->fbi->dev->kobj,
+							KOBJ_CHANGE, envp);
+			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+							__func__, envp[0]);
+		}
+	}
+}
+
+/**
+ * fb_notifier_callback() - Call back function for the fb_register_client()
+ * notifying events
+ * @self  : notifier block
+ * @event : The event that was triggered
+ * @data  : Of type struct fb_event
+ *
+ * - This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * - Based on the event the delayed work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled
+ */
+static int fb_event_callback(struct notifier_block *self,
+				unsigned long event, void *data)
+{
+	struct fb_event *evdata = (struct fb_event *)data;
+	struct dsi_status_data *pdata = container_of(self,
+				struct dsi_status_data, fb_notifier);
+	pdata->mfd = (struct msm_fb_data_type *)evdata->info->par;
+
+	if (event == FB_EVENT_BLANK && evdata) {
+		int *blank = evdata->data;
+		switch (*blank) {
+		case FB_BLANK_UNBLANK:
+			schedule_delayed_work(&pdata->check_status,
+			msecs_to_jiffies(STATUS_CHECK_INTERVAL));
+			break;
+		case FB_BLANK_POWERDOWN:
+			cancel_delayed_work(&pdata->check_status);
+			break;
+		}
+	}
+	return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+	int rc;
+
+	pstatus_data = kzalloc(sizeof(struct dsi_status_data),	GFP_KERNEL);
+	if (!pstatus_data) {
+		pr_err("%s: can't alloc mem\n", __func__);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	memset(pstatus_data, 0, sizeof(struct dsi_status_data));
+
+	pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+	rc = fb_register_client(&pstatus_data->fb_notifier);
+	if (rc < 0) {
+		pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+								__func__, rc);
+		kfree(pstatus_data);
+		return -EPERM;
+	}
+
+	pstatus_data->check_interval = interval;
+	pr_info("%s: DSI status check interval:%d\n", __func__, interval);
+
+	INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+	pr_debug("%s: DSI ctrl status thread initialized\n", __func__);
+
+	return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+	fb_unregister_client(&pstatus_data->fb_notifier);
+	cancel_delayed_work_sync(&pstatus_data->check_status);
+	kfree(pstatus_data);
+	pr_debug("%s: DSI ctrl status thread removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+	"Duration in milliseconds to send BTA command for checking"
+	"DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6219737..e6d4ff2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -613,9 +613,6 @@
 	panel = mdp3_session->panel;
 	mutex_lock(&mdp3_session->lock);
 
-	if (panel && panel->set_backlight)
-		panel->set_backlight(panel, 0);
-
 	if (!mdp3_session->status) {
 		pr_debug("fb%d is off already", mfd->index);
 		goto off_error;
@@ -838,6 +835,14 @@
 {
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct fb_info *fbi = mfd->fbi;
+	int stride;
+
+	fix = &fbi->fix;
+	var = &fbi->var;
+	stride = req->src.width * var->bits_per_pixel/8;
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -846,6 +851,9 @@
 
 	mdp3_session->overlay = *req;
 	if (req->id == MSMFB_NEW_REQUEST) {
+		if (fix->line_length != stride)
+			mdp3_session->dma->config_stride(
+						mdp3_session->dma, stride);
 		mdp3_session->overlay.id = 1;
 		req->id = 1;
 	}
@@ -859,10 +867,15 @@
 {
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct fb_info *fbi = mfd->fbi;
+	struct fb_fix_screeninfo *fix;
 
+	fix = &fbi->fix;
 	mutex_lock(&mdp3_session->lock);
 
 	if (mdp3_session->overlay.id == ndx && ndx == 1) {
+		mdp3_session->dma->config_stride(mdp3_session->dma,
+							fix->line_length);
 		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 		mdp3_bufq_deinit(&mdp3_session->bufq_in);
 	} else {
@@ -1708,14 +1721,14 @@
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
+	if (mdp3_get_cont_spash_en())
+		mdp3_session->clk_on = 1;
+
 	if (splash_mismatch) {
 		pr_err("splash memory mismatch, stop splash\n");
 		mdp3_ctrl_off(mfd);
 	}
 
-	if (mdp3_get_cont_spash_en())
-		mdp3_session->clk_on = 1;
-
 	mdp3_session->vsync_before_commit = true;
 init_done:
 	if (IS_ERR_VALUE(rc))
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3a2c94b..2ebcb8a 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -268,6 +268,23 @@
 	return 0;
 }
 
+static void mdp3_dma_stride_config(struct mdp3_dma *dma, int stride)
+{
+	struct mdp3_dma_source *source_config;
+	u32 dma_stride_offset;
+
+	if (dma->dma_sel == MDP3_DMA_P)
+		dma_stride_offset = MDP3_REG_DMA_P_IBUF_Y_STRIDE;
+	else
+		dma_stride_offset = MDP3_REG_DMA_S_IBUF_Y_STRIDE;
+
+	source_config = &dma->source_config;
+	source_config->stride = stride;
+	pr_debug("%s: Update the fb stride for DMA to %d", __func__,
+						(u32)source_config->stride);
+	MDP3_REG_WRITE(dma_stride_offset, source_config->stride);
+}
+
 static int mdp3_dmap_config(struct mdp3_dma *dma,
 			struct mdp3_dma_source *source_config,
 			struct mdp3_dma_output_config *output_config)
@@ -855,6 +872,7 @@
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
+		dma->config_stride = mdp3_dma_stride_config;
 		break;
 	case MDP3_DMA_S:
 		dma->dma_config = mdp3_dmas_config;
@@ -869,6 +887,7 @@
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
+		dma->config_stride = mdp3_dma_stride_config;
 		break;
 	case MDP3_DMA_E:
 	default:
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6983e55..9d439ad 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -287,6 +287,8 @@
 
 	int (*histo_op)(struct mdp3_dma *dma, u32 op);
 
+	void (*config_stride)(struct mdp3_dma *dma, int stride);
+
 	void (*vsync_enable)(struct mdp3_dma *dma,
 			struct mdp3_vsync_notification *vsync_client);
 };
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index a64a6b4..d778af8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -412,12 +412,47 @@
 	mdp3_ppp_kickoff();
 }
 
-static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+static int solid_fill_workaround(struct mdp_blit_req *req,
+						struct ppp_blit_op *blit_op)
+{
+	/* Make width 2 when there is a solid fill of width 1, and make
+	sure width does not become zero while trying to avoid odd width */
+	if (blit_op->dst.roi.width == 1) {
+		if (req->dst_rect.x + 2 > req->dst.width) {
+			pr_err("%s: Unable to handle solid fill of width 1",
+								__func__);
+			return -EINVAL;
+		}
+		blit_op->dst.roi.width = 2;
+	}
+	if (blit_op->src.roi.width == 1) {
+		if (req->src_rect.x + 2 > req->src.width) {
+			pr_err("%s: Unable to handle solid fill of width 1",
+								__func__);
+			return -EINVAL;
+		}
+		blit_op->src.roi.width = 2;
+	}
+
+	/* Avoid odd width, as it could hang ppp during solid fill */
+	blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
+	blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
+
+	/* Avoid RGBA format, as it could hang ppp during solid fill */
+	if (blit_op->src.color_fmt == MDP_RGBA_8888)
+		blit_op->src.color_fmt = MDP_RGBX_8888;
+	if (blit_op->dst.color_fmt == MDP_RGBA_8888)
+		blit_op->dst.color_fmt = MDP_RGBX_8888;
+	return 0;
+}
+
+static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
 	struct mdp_blit_req *req, struct mdp3_img_data *src_data,
 	struct mdp3_img_data *dst_data)
 {
 	unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
 	uint32_t dst_width, dst_height;
+	int ret = 0;
 
 	srcp0_start = (unsigned long) src_data->addr;
 	srcp0_len = (unsigned long) src_data->len;
@@ -510,24 +545,19 @@
 		blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
 
 	if (req->flags & MDP_SOLID_FILL) {
-		blit_op->solid_fill = true;
+		ret = solid_fill_workaround(req, blit_op);
+		if (ret)
+			return ret;
 
-		/* Avoid odd width, as it could hang ppp during solid fill */
-		blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
-		blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
-
-		/* Avoid RGBA format, as it could hang ppp during solid fill */
-		if (blit_op->src.color_fmt == MDP_RGBA_8888)
-			blit_op->src.color_fmt = MDP_RGBX_8888;
-		if (blit_op->dst.color_fmt == MDP_RGBA_8888)
-			blit_op->dst.color_fmt = MDP_RGBX_8888;
 		blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
 				(req->const_color.r & 0xFF) << 8 |
 				(req->const_color.b & 0xFF)  << 16 |
 				(req->const_color.alpha & 0xFF) << 24;
+		blit_op->solid_fill = true;
 	} else {
 		blit_op->solid_fill = false;
 	}
+	return ret;
 }
 
 static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -626,6 +656,7 @@
 	struct mdp3_img_data *dst_data)
 {
 	struct ppp_blit_op blit_op;
+	int ret = 0;
 
 	memset(&blit_op, 0, sizeof(blit_op));
 
@@ -639,7 +670,11 @@
 		return -EINVAL;
 	}
 
-	mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+	ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+	if (ret) {
+		pr_err("%s: Failed to process the blit request", __func__);
+		return ret;
+	}
 
 	if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
 	     (req->src.format == MDP_ARGB_8888) ||
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index d743c42..855ec6c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,7 +233,7 @@
 	int (*off) (struct mdss_panel_data *pdata);
 	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
 	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
-	void (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	int reg_size;
@@ -336,7 +336,7 @@
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 void mdss_dsi_cmdlist_kickoff(int intf);
 int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
index 9a3e638..8fc1115c0 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.c
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -655,7 +655,7 @@
 {
 	struct dcs_cmd_req *req;
 	struct dcs_cmd_list *clist;
-	int ret = 0;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	clist = &ctrl->cmdlist;
@@ -674,7 +674,6 @@
 	}
 	mutex_unlock(&ctrl->cmd_mutex);
 
-	ret++;
 	pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
 		clist->tot, clist->put, clist->get);
 
@@ -682,7 +681,7 @@
 		if (!ctrl->cmdlist_commit)
 			pr_err("cmdlist_commit not implemented!\n");
 		else
-			ctrl->cmdlist_commit(ctrl, 0);
+			ret = ctrl->cmdlist_commit(ctrl, 0);
 	}
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 37ccd4f..65e6214 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1155,38 +1155,55 @@
 				__func__, current->pid);
 }
 
-void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
 				struct dcs_cmd_req *req)
 {
-	int ret;
+	int ret, ret_val = -EINVAL;
 
 	ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
 
+	if (!IS_ERR_VALUE(ret))
+		ret_val = 0;
+
 	if (req->cb)
 		req->cb(ret);
+
+	return ret_val;
 }
 
-void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
 				struct dcs_cmd_req *req)
 {
 	struct dsi_buf *rp;
-	int len = 0;
+	int len = 0, ret = -EINVAL;
 
 	if (req->rbuf) {
 		rp = &ctrl->rx_buf;
 		len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
 		memcpy(req->rbuf, rp->data, rp->len);
+		/*
+		 * For dual DSI cases, early return of controller - 0
+		 * is valid. Hence, for those cases the return value
+		 * is zero even though we don't send any commands.
+		 *
+		 */
+		if ((ctrl->shared_pdata.broadcast_enable &&
+			ctrl->ndx == DSI_CTRL_0) || (len != 0))
+			ret = 0;
 	} else {
 		pr_err("%s: No rx buffer provided\n", __func__);
 	}
 
 	if (req->cb)
 		req->cb(len);
+
+	return ret;
 }
 
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
@@ -1211,9 +1228,9 @@
 	mdss_dsi_clk_ctrl(ctrl, 1);
 
 	if (req->flags & CMD_REQ_RX)
-		mdss_dsi_cmdlist_rx(ctrl, req);
+		ret = mdss_dsi_cmdlist_rx(ctrl, req);
 	else
-		mdss_dsi_cmdlist_tx(ctrl, req);
+		ret = mdss_dsi_cmdlist_tx(ctrl, req);
 
 	mdss_dsi_clk_ctrl(ctrl, 0);
 	mdss_bus_bandwidth_ctrl(0);
@@ -1224,6 +1241,7 @@
 		mdss_dsi_cmd_mdp_start(ctrl);
 
 	mutex_unlock(&ctrl->cmd_mutex);
+	return ret;
 }
 
 static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
@@ -1313,6 +1331,8 @@
 
 	if (status) {
 		MIPI_OUTP(base + 0x0068, status);
+		/* Writing of an extra 0 needed to clear error bits */
+		MIPI_OUTP(base + 0x0068, 0);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c15c02b..94b2cbd 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2187,6 +2187,7 @@
 	struct platform_device *fb_pdev, *mdss_pdev;
 	struct device_node *node;
 	int rc = 0;
+	bool master_panel = true;
 
 	if (!pdev || !pdev->dev.of_node) {
 		pr_err("Invalid device node\n");
@@ -2214,6 +2215,8 @@
 	fb_pdev = of_find_device_by_node(node);
 	if (fb_pdev) {
 		rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+		if (rc == 0)
+			master_panel = false;
 	} else {
 		pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
 		fb_pdev = of_platform_device_create(node, NULL,
@@ -2221,7 +2224,7 @@
 		fb_pdev->dev.platform_data = pdata;
 	}
 
-	if (mdp_instance->panel_register_done)
+	if (master_panel && mdp_instance->panel_register_done)
 		mdp_instance->panel_register_done(pdata);
 
 mdss_notfound:
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 769f9b2..fad6b0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -289,6 +289,7 @@
 struct mdss_ad_info {
 	u8 num;
 	u8 calc_hw_num;
+	u32 ops;
 	u32 sts;
 	u32 reg_sts;
 	u32 state;
@@ -516,7 +517,7 @@
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
 int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
 int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index bad4d06..f73b583 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1062,26 +1062,34 @@
 	return rc;
 }
 
-static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	struct mdss_mdp_mixer *mixer;
 	u32 outsize, temp;
 	int ret = 0;
 	int i, nmixers;
 
-	if (ctl->start_fnc)
-		ret = ctl->start_fnc(ctl);
-	else
-		pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
-				ctl->panel_data->panel_info.type);
-
-	if (ret) {
-		pr_err("unable to start intf\n");
-		return ret;
-	}
-
 	pr_debug("ctl_num=%d\n", ctl->num);
 
+	/*
+	 * Need start_fnc in 2 cases:
+	 * (1) handoff
+	 * (2) continuous splash finished.
+	 */
+	if (handoff || !ctl->panel_data->panel_info.cont_splash_enabled) {
+		if (ctl->start_fnc)
+			ret = ctl->start_fnc(ctl);
+		else
+			pr_warn("no start function for ctl=%d type=%d\n",
+					ctl->num,
+					ctl->panel_data->panel_info.type);
+
+		if (ret) {
+			pr_err("unable to start intf\n");
+			return ret;
+		}
+	}
+
 	if (!ctl->panel_data->panel_info.cont_splash_enabled) {
 		nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
 			MDSS_MDP_WB_MAX_LAYERMIXER;
@@ -1108,7 +1116,7 @@
 	return ret;
 }
 
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	struct mdss_mdp_ctl *sctl;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -1123,12 +1131,17 @@
 	if (ret)
 		return ret;
 
-
 	sctl = mdss_mdp_get_split_ctl(ctl);
 
 	mutex_lock(&ctl->lock);
 
-	ctl->power_on = true;
+	/*
+	 * keep power_on false during handoff to avoid unexpected
+	 * operations to overlay.
+	 */
+	if (!handoff)
+		ctl->power_on = true;
+
 	ctl->bus_ab_quota = 0;
 	ctl->bus_ib_quota = 0;
 	ctl->clk_rate = 0;
@@ -1141,10 +1154,10 @@
 		goto error;
 	}
 
-	ret = mdss_mdp_ctl_start_sub(ctl);
+	ret = mdss_mdp_ctl_start_sub(ctl, handoff);
 	if (ret == 0) {
 		if (sctl) { /* split display is available */
-			ret = mdss_mdp_ctl_start_sub(sctl);
+			ret = mdss_mdp_ctl_start_sub(sctl, handoff);
 			if (!ret)
 				mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
 		} else if (ctl->mixer_right) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 14b486a..4c89064 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -859,7 +859,7 @@
 		mdss_hw_init(mdss_res);
 	}
 
-	rc = mdss_mdp_ctl_start(ctl);
+	rc = mdss_mdp_ctl_start(ctl, false);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
 
@@ -1580,8 +1580,8 @@
 		return -ENODEV;
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -EOPNOTSUPP;
-
-	if (!ctl->power_on) {
+	if (!ctl->panel_data->panel_info.cont_splash_enabled
+			&& !ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
 		return -EPERM;
@@ -1698,7 +1698,9 @@
 	u64 vsync_ticks;
 	int ret;
 
-	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+	if (!mdp5_data->ctl ||
+		(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
+			&& !mdp5_data->ctl->power_on))
 		return -EAGAIN;
 
 	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -2535,9 +2537,15 @@
 		mdp5_data->ctl = ctl;
 	}
 
-	rc = mdss_mdp_ctl_setup(ctl);
-	if (rc)
+	/*
+	 * vsync interrupt needs on during continuous splash, this is
+	 * to initialize necessary ctl members here.
+	 */
+	rc = mdss_mdp_ctl_start(ctl, true);
+	if (rc) {
+		pr_err("Failed to initialize ctl\n");
 		goto error;
+	}
 
 	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
 	pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0dc61d0..d0d2157 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -205,6 +205,10 @@
 
 #define PP_AD_BAD_HW_NUM 255
 
+#define MDSS_SIDE_NONE	0
+#define MDSS_SIDE_LEFT	1
+#define MDSS_SIDE_RIGHT	2
+
 #define PP_AD_STATE_INIT	0x2
 #define PP_AD_STATE_CFG		0x4
 #define PP_AD_STATE_DATA	0x8
@@ -293,15 +297,15 @@
 	struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
 	u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
-	/* physical info */
 	struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
+	/* physical info */
 	struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
 };
 
 static DEFINE_MUTEX(mdss_pp_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-static void pp_hist_read(char __iomem *v_addr,
+static u32 pp_hist_read(char __iomem *v_addr,
 				struct pp_hist_col_info *hist_info);
 static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
 static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
@@ -340,8 +344,9 @@
 static void pp_dither_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_dither_cfg_data *dither_cfg);
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
-				int mdp_rev);
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+					struct pp_sts_type *pp_sts, int mdp_rev,
+					u32 *opmode);
 static void pp_sharp_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config);
@@ -375,11 +380,15 @@
 			struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
 static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
 						struct mdss_ad_info *ad);
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode);
 static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
 						struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
 static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
 static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
+static inline bool pp_sts_is_enabled(u32 sts, int side);
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
 
 static u32 last_sts, last_state;
 
@@ -511,6 +520,7 @@
 		pp_sts->gamut_sts &= ~PP_STS_ENABLE;
 	else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
 		pp_sts->gamut_sts |= PP_STS_ENABLE;
+	pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
 }
 
 static void pp_pa_config(unsigned long flags, char __iomem *addr,
@@ -679,6 +689,7 @@
 	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
 		pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
 
+	pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
 }
 
 static void pp_pcc_config(unsigned long flags, char __iomem *addr,
@@ -693,6 +704,7 @@
 			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
 		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
 			pp_sts->pcc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
 	}
 }
 
@@ -720,6 +732,7 @@
 			pp_sts->igc_sts &= ~PP_STS_ENABLE;
 		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
 			pp_sts->igc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
 	}
 }
 
@@ -1324,12 +1337,20 @@
 		pp_sts->dither_sts &= ~PP_STS_ENABLE;
 	else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
 		pp_sts->dither_sts |= PP_STS_ENABLE;
+	pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
 }
 
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
-			int mdp_rev)
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+					struct pp_sts_type *pp_sts, int mdp_rev,
+					u32 *opmode)
 {
-	if (pp_sts->pa_sts & PP_STS_ENABLE)
+	int side;
+	side = pp_num_to_side(ctl, num);
+
+	if (side < 0)
+		return;
+
+	if (pp_sts_is_enabled(pp_sts->pa_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
 	if (mdp_rev >= MDSS_MDP_HW_REV_103) {
 		if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
@@ -1357,10 +1378,10 @@
 		if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
 			*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
 	}
-	if (pp_sts->pcc_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
 
-	if (pp_sts->igc_sts & PP_STS_ENABLE) {
+	if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
 		*opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
 			      (pp_sts->igc_tbl_idx << 1);
 	}
@@ -1368,14 +1389,14 @@
 		*opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
 				  MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
 	}
-	if (pp_sts->dither_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->dither_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
-	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+	if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
 		*opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
 		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
 			*opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
 	}
-	if (pp_sts->pgc_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
 }
 
@@ -1481,6 +1502,7 @@
 			pp_sts->pgc_sts &= ~PP_STS_ENABLE;
 		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
 			pp_sts->pgc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
 	}
 
 	if (ad_hw) {
@@ -1492,12 +1514,12 @@
 			pp_ad_init_write(ad_hw, ad, ctl);
 		if (ad_flags & PP_AD_STS_DIRTY_CFG)
 			pp_ad_cfg_write(ad_hw, ad);
-		pp_ad_bypass_config(ad, &ad_bypass);
+		pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
 		writel_relaxed(ad_bypass, ad_hw->base);
 		mutex_unlock(&ad->lock);
 	}
 
-	pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev);
+	pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
 flush_exit:
 	writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
 	ctl->flush_bits |= BIT(13 + dspp_num);
@@ -1836,6 +1858,12 @@
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) ==
+							MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2119,6 +2147,11 @@
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2238,6 +2271,11 @@
 	if (config->len != IGC_LUT_ENTRIES)
 		return -EINVAL;
 
+	if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2437,6 +2475,11 @@
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 
 	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2608,6 +2651,11 @@
 	if (config->flags & MDP_PP_OPS_READ)
 		return -ENOTSUPP;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 	mdss_pp_res->dither_disp_cfg[disp_num] = *config;
@@ -2657,6 +2705,11 @@
 	if (pp_gm_has_invalid_lut_size(config))
 		return -EINVAL;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2773,19 +2826,27 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
-static void pp_hist_read(char __iomem *v_addr,
+
+static u32 pp_hist_read(char __iomem *v_addr,
 				struct pp_hist_col_info *hist_info)
 {
 	int i, i_start;
+	u32 sum = 0;
 	u32 data;
 	data = readl_relaxed(v_addr);
 	i_start = data >> 24;
 	hist_info->data[i_start] = data & 0xFFFFFF;
-	for (i = i_start + 1; i < HIST_V_SIZE; i++)
+	sum += hist_info->data[i_start];
+	for (i = i_start + 1; i < HIST_V_SIZE; i++) {
 		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
-	for (i = 0; i < i_start - 1; i++)
+		sum += hist_info->data[i];
+	}
+	for (i = 0; i < i_start; i++) {
 		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+		sum += hist_info->data[i];
+	}
 	hist_info->hist_cnt_read++;
+	return sum;
 }
 
 /* Assumes that relevant clocks are enabled */
@@ -3168,10 +3229,10 @@
 
 static int pp_hist_collect(struct mdp_histogram_data *hist,
 				struct pp_hist_col_info *hist_info,
-				char __iomem *ctl_base)
+				char __iomem *ctl_base, u32 expect_sum)
 {
 	int wait_ret, ret = 0;
-	u32 timeout;
+	u32 timeout, sum;
 	char __iomem *v_base;
 	unsigned long flag;
 	struct mdss_pipe_pp_res *res;
@@ -3238,10 +3299,13 @@
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		v_base = ctl_base + 0x1C;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		pp_hist_read(v_base, hist_info);
+		sum = pp_hist_read(v_base, hist_info);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		spin_lock_irqsave(&hist_info->hist_lock, flag);
-		hist_info->read_request = false;
+		if (!expect_sum || sum == expect_sum)
+			hist_info->read_request = false;
+		else
+			ret = -ENODATA;
 		hist_info->col_state = HIST_IDLE;
 	}
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -3261,6 +3325,7 @@
 	u32 *hist_data_addr;
 	u32 pipe_cnt = 0;
 	u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+	u32 exp_sum = 0;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
@@ -3290,7 +3355,10 @@
 			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
 			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
 				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-			ret = pp_hist_collect(hist, hist_info, ctl_base);
+			exp_sum = (mdata->mixer_intf[dspp_num].width *
+					mdata->mixer_intf[dspp_num].height);
+			ret = pp_hist_collect(hist, hist_info, ctl_base,
+								exp_sum);
 			if (ret)
 				goto hist_collect_exit;
 		}
@@ -3359,7 +3427,8 @@
 			hist_info = &pipe->pp_res.hist;
 			ctl_base = pipe->base +
 				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
-			ret = pp_hist_collect(hist, hist_info, ctl_base);
+			ret = pp_hist_collect(hist, hist_info, ctl_base,
+								exp_sum);
 			mdss_mdp_pipe_unmap(pipe);
 			if (ret)
 				goto hist_collect_exit;
@@ -3490,6 +3559,53 @@
 	return out;
 }
 
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
+{
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 mixer_num;
+
+	if (!ctl || !ctl->mfd)
+		return -EINVAL;
+	mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+	if (mixer_num < 2)
+		return MDSS_SIDE_NONE;
+	else if (mixer_id[1] == num)
+		return MDSS_SIDE_RIGHT;
+	else if (mixer_id[0] == num)
+		return MDSS_SIDE_LEFT;
+	else
+		pr_err("invalid, not on any side");
+	return -EINVAL;
+}
+
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits)
+{
+	u32 tmp = *sts;
+	tmp &= ~MDSS_PP_SPLIT_MASK;
+	tmp |= bits & MDSS_PP_SPLIT_MASK;
+	*sts = tmp;
+}
+
+static inline bool pp_sts_is_enabled(u32 sts, int side)
+{
+	bool ret = false;
+	/*
+	 * If there are no sides, or if there are no split mode bits set, the
+	 * side can't be disabled via split mode.
+	 *
+	 * Otherwise, if the side being checked opposes the split mode
+	 * configuration, the side is disabled.
+	 */
+	if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK))
+		ret = true;
+	else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT))
+		ret = true;
+	else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT))
+		ret = true;
+
+	return ret && (sts & PP_STS_ENABLE);
+}
+
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
 {
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -3586,7 +3702,7 @@
 	struct mdss_mdp_ctl *ctl;
 	struct msm_fb_data_type *bl_mfd;
 	int lin_ret = -1, inv_ret = -1, ret = 0;
-	u32 ratio_temp, shift = 0;
+	u32 ratio_temp, shift = 0, last_ops;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
@@ -3599,6 +3715,11 @@
 		bl_mfd = mfd;
 	}
 
+	if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&ad->lock);
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
 		memcpy(&ad->init, &init_cfg->params.init,
@@ -3638,6 +3759,22 @@
 		ad->sts |= PP_AD_STS_DIRTY_CFG;
 	}
 
+	last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
+	ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
+	/*
+	 *  if there is a change in the split mode config, the init values
+	 *  need to be re-written to hardware (if they have already been
+	 *  written or if there is data pending to be written). Check for
+	 *  pending data (DIRTY_INIT) is not checked here since it will not
+	 *  affect the outcome of this conditional (i.e. if init hasn't
+	 *  already been written (*_STATE_INIT is set), this conditional will
+	 *  only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
+	 *  already been set).
+	 */
+	if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
+		ad->sts |= PP_AD_STS_DIRTY_INIT;
+
+
 	if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
 		ad->sts &= ~PP_STS_ENABLE;
 		mutex_unlock(&ad->lock);
@@ -3792,8 +3929,9 @@
 	u32 temp;
 	u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
 	u32 num;
+	int side;
 	char __iomem *base;
-	bool is_calc, is_dual_pipe;
+	bool is_calc, is_dual_pipe, split_mode;
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
 	u32 mixer_num;
 	mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
@@ -3804,6 +3942,7 @@
 
 	base = ad_hw->base;
 	is_calc = ad->calc_hw_num == ad_hw->num;
+	split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
 
 	writel_relaxed(ad->init.i_control[0] & 0x1F,
 				base + MDSS_MDP_REG_AD_CON_CTRL_0);
@@ -3829,7 +3968,10 @@
 	writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
 	writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
 
-	temp = ad->init.frame_w << 16;
+	if (split_mode)
+		temp = mdata->mixer_intf[ad_hw->num].width << 16;
+	else
+		temp = ad->init.frame_w << 16;
 	temp |= ad->init.frame_h & 0xFFFF;
 	writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
 
@@ -3841,17 +3983,26 @@
 	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
 
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
-		if (is_dual_pipe) {
+		if (is_dual_pipe && !split_mode) {
 			num = ad_hw->num;
+			side = pp_num_to_side(ctl, num);
 			tile_ctrl = 0x5;
-			if (is_calc) {
+			if ((ad->calc_hw_num + 1) == num)
+				tile_ctrl |= 0x10;
+
+			if (side <= MDSS_SIDE_NONE) {
+				WARN(1, "error finding sides, %d", side);
+				frame_start = 0;
+				procs_start = frame_start;
+				frame_end = 0;
+				procs_end = frame_end;
+			} else if (side == MDSS_SIDE_LEFT) {
 				frame_start = 0;
 				procs_start = 0;
 				frame_end = mdata->mixer_intf[num].width +
 							MDSS_AD_MERGED_WIDTH;
 				procs_end = mdata->mixer_intf[num].width;
 			} else {
-				tile_ctrl |= 0x10;
 				procs_start = ad->init.frame_w -
 					(mdata->mixer_intf[num].width);
 				procs_end = ad->init.frame_w;
@@ -3866,8 +4017,13 @@
 			frame_end = 0xFFFF;
 			procs_start = 0x0;
 			procs_end = 0xFFFF;
-			tile_ctrl = 0x1;
+			if (split_mode)
+				tile_ctrl = 0x0;
+			else
+				tile_ctrl = 0x1;
 		}
+
+
 		writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
 		writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
 		writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
@@ -3931,12 +4087,17 @@
 }
 
 #define MDSS_PP_AD_BYPASS_DEF 0x101
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode)
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
 {
-	if (ad->reg_sts & PP_STS_ENABLE)
+	int side = pp_num_to_side(ctl, num);
+
+	if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
+								side)) {
 		*opmode = 0;
-	else
+	} else {
 		*opmode = MDSS_PP_AD_BYPASS_DEF;
+	}
 }
 
 static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
@@ -3951,6 +4112,8 @@
 
 	/* default to left mixer */
 	ad->calc_hw_num = mixer_id[0];
+	if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
+		ad->calc_hw_num = mixer_id[1];
 	return 0;
 }
 
@@ -4258,6 +4421,7 @@
 		mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
 		mdata->ad_off[i].num = i;
 		mdata->ad_cfgs[i].num = i;
+		mdata->ad_cfgs[i].ops = 0;
 		mdata->ad_cfgs[i].reg_sts = 0;
 		mdata->ad_cfgs[i].calc_itr = 0;
 		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index d9b1ef7..329b58e 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -454,3 +454,4 @@
 header-y += msm_audio_amrwbplus.h
 header-y += avtimer.h
 header-y += msm_ipa.h
+header-y += msm_thermal_ioctl.h
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f36298b..7131da3 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -22,6 +22,8 @@
 #include <linux/types.h>
 
 struct ion_handle;
+typedef struct ion_handle *ion_user_handle_t;
+
 /**
  * enum ion_heap_types - list of all possible types of heaps
  * @ION_HEAP_TYPE_SYSTEM:	 memory allocated via vmalloc
@@ -350,7 +352,7 @@
 	size_t align;
 	unsigned int heap_mask;
 	unsigned int flags;
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 };
 
 /**
@@ -364,7 +366,7 @@
  * provides the file descriptor and the kernel returns the handle.
  */
 struct ion_fd_data {
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 	int fd;
 };
 
@@ -373,7 +375,7 @@
  * @handle:	a handle
  */
 struct ion_handle_data {
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 };
 
 /**
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 1bcfd28..43aebb5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -392,7 +392,7 @@
 	unsigned int		idle_timeout;
 	struct notifier_block        reboot_notify;
 	bool issue_long_pon;
-	u8 cached_ext_csd;
+	u8 *cached_ext_csd;
 };
 
 /*
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 724e573..4903939 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -802,6 +802,10 @@
 	DCM_BLANK,
 };
 
+#define MDSS_PP_SPLIT_LEFT_ONLY		0x10000000
+#define MDSS_PP_SPLIT_RIGHT_ONLY	0x20000000
+#define MDSS_PP_SPLIT_MASK		0x30000000
+
 #define MDSS_MAX_BL_BRIGHTNESS 255
 #define AD_BL_LIN_LEN 256
 
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2ca9900..25b5363 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -19,22 +19,30 @@
 	uint32_t poll_ms;
 	int32_t limit_temp_degC;
 	int32_t temp_hysteresis_degC;
-	uint32_t freq_step;
-	uint32_t freq_control_mask;
+	uint32_t bootup_freq_step;
+	uint32_t bootup_freq_control_mask;
 	int32_t core_limit_temp_degC;
 	int32_t core_temp_hysteresis_degC;
 	int32_t hotplug_temp_degC;
 	int32_t hotplug_temp_hysteresis_degC;
 	uint32_t core_control_mask;
+	uint32_t freq_mitig_temp_degc;
+	uint32_t freq_mitig_temp_hysteresis_degc;
+	uint32_t freq_mitig_control_mask;
+	uint32_t freq_limit;
 	int32_t vdd_rstr_temp_degC;
 	int32_t vdd_rstr_temp_hyst_degC;
 	int32_t psm_temp_degC;
 	int32_t psm_temp_hyst_degC;
+	int32_t ocr_temp_degC;
+	int32_t ocr_temp_hyst_degC;
 };
 
 #ifdef CONFIG_THERMAL_MONITOR
 extern int msm_thermal_init(struct msm_thermal_data *pdata);
 extern int msm_thermal_device_init(void);
+extern int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+	bool is_max);
 #else
 static inline int msm_thermal_init(struct msm_thermal_data *pdata)
 {
@@ -44,6 +52,11 @@
 {
 	return -ENOSYS;
 }
+static inline int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+	bool is_max)
+{
+	return -ENOSYS;
+}
 #endif
 
 #endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/msm_thermal_ioctl.h b/include/linux/msm_thermal_ioctl.h
new file mode 100644
index 0000000..7b36493
--- /dev/null
+++ b/include/linux/msm_thermal_ioctl.h
@@ -0,0 +1,41 @@
+#ifndef _MSM_THERMAL_IOCTL_H
+#define _MSM_THERMAL_IOCTL_H
+
+#include <linux/ioctl.h>
+
+#define MSM_THERMAL_IOCTL_NAME "msm_thermal_query"
+
+struct __attribute__((__packed__)) cpu_freq_arg {
+	uint32_t cpu_num;
+	uint32_t freq_req;
+};
+
+struct __attribute__((__packed__)) msm_thermal_ioctl {
+	uint32_t size;
+	union {
+		struct cpu_freq_arg cpu_freq;
+	};
+};
+
+enum {
+	/*Set CPU Frequency*/
+	MSM_SET_CPU_MAX_FREQ = 0x00,
+	MSM_SET_CPU_MIN_FREQ = 0x01,
+
+	MSM_CMD_MAX_NR,
+};
+
+#define MSM_THERMAL_MAGIC_NUM 0xCA /*Unique magic number*/
+
+#define MSM_THERMAL_SET_CPU_MAX_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+		MSM_SET_CPU_MAX_FREQ, struct msm_thermal_ioctl)
+
+#define MSM_THERMAL_SET_CPU_MIN_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+		MSM_SET_CPU_MIN_FREQ, struct msm_thermal_ioctl)
+
+#ifdef __KERNEL__
+extern int msm_thermal_ioctl_init(void);
+extern void msm_thermal_ioctl_cleanup(void);
+#endif
+
+#endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 560accb..bfafe00 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1904,6 +1904,9 @@
 	V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index c48586e..a01dd9a 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -571,7 +571,8 @@
 
 struct msm_camera_led_cfg_t {
 	enum msm_camera_led_config_t cfgtype;
-	uint32_t led_current;
+	uint32_t torch_current;
+	uint32_t flash_current[2];
 };
 
 #define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 75fe3a2..2c969cd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -7172,5 +7172,7 @@
 #define US_POINT_EPOS_FORMAT_V2 0x0001272D
 #define US_RAW_FORMAT_V2        0x0001272C
 #define US_PROX_FORMAT_V2       0x0001272E
+#define US_RAW_SYNC_FORMAT      0x0001272F
+#define US_GES_SYNC_FORMAT      0x00012730
 
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9a459b8..b00cfc9 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -67,6 +67,8 @@
 /* Enable Sample_Rate/Channel_Mode notification event from Decoder */
 #define SR_CM_NOTIFY_ENABLE	0x0004
 
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE  0x0004 /* tunnel read write mode */
 #define SYNC_IO_MODE	0x0001
 #define ASYNC_IO_MODE	0x0002
 #define COMPRESSED_IO	0x0040
@@ -218,6 +220,9 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
+int q6asm_open_loopback_v2(struct audio_client *ac,
+			   uint16_t bits_per_sample);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e174693..fa8a793 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,36 +184,6 @@
 	return ret;
 }
 
-#ifdef ENABLE_VMALLOC_SAVING
-int is_vmalloc_addr(const void *x)
-{
-	struct rb_node *n;
-	struct vmap_area *va;
-	int ret = 0;
-
-	spin_lock(&vmap_area_lock);
-
-	for (n = rb_first(vmap_area_root); n; rb_next(n)) {
-		va = rb_entry(n, struct vmap_area, rb_node);
-		if (x >= va->va_start && x < va->va_end) {
-			ret = 1;
-			break;
-		}
-	}
-
-	spin_unlock(&vmap_area_lock);
-	return ret;
-}
-#else
-int is_vmalloc_addr(const void *x)
-{
-	unsigned long addr = (unsigned long)x;
-
-	return addr >= VMALLOC_START && addr < VMALLOC_END;
-}
-#endif
-EXPORT_SYMBOL(is_vmalloc_addr);
-
 int is_vmalloc_or_module_addr(const void *x)
 {
 	/*
@@ -302,6 +272,47 @@
 
 static unsigned long vmap_area_pcpu_hole;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+int is_vmalloc_addr(const void *x)
+{
+	struct vmap_area *va;
+	int ret = 0;
+
+	spin_lock(&vmap_area_lock);
+	list_for_each_entry(va, &vmap_area_list, list) {
+		if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
+			continue;
+
+		if (!(va->flags & VM_VM_AREA))
+			continue;
+
+		if (va->vm == NULL)
+			continue;
+
+		if (va->vm->flags & VM_LOWMEM)
+			continue;
+
+		if ((unsigned long)x >= va->va_start &&
+		    (unsigned long)x < va->va_end) {
+			ret = 1;
+			break;
+		}
+	}
+	spin_unlock(&vmap_area_lock);
+	return ret;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+	unsigned long addr = (unsigned long)x;
+
+	return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
+
+
 static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
 	struct rb_node *n = vmap_area_root.rb_node;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9962c88..6c78c0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
 		head = p; id++;
 	}
 
-	sprintf(hdev->name, "hci%d", id);
+	snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
 	hdev->id = id;
 	list_add(&hdev->list, head);
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2628937..b2b0e99 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3443,10 +3443,7 @@
 			tcp_done(sk);
 			bh_unlock_sock(sk);
 			local_bh_enable();
-			if (!sock_flag(sk, SOCK_DEAD)) {
-				sock_orphan(sk);
-				sock_put(sk);
-			}
+			sock_put(sk);
 
 			goto restart;
 		}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..9a11f9f 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -55,6 +55,7 @@
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
 
 int token_profit[0x10000];
 
@@ -65,7 +66,10 @@
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+			"[--symbol-prefix=<prefix char>] "
+			"[--page-offset=<CONFIG_PAGE_OFFSET>] "
+			"< in.map > out.S\n");
 	exit(1);
 }
 
@@ -194,6 +198,9 @@
 	int i;
 	int offset = 1;
 
+	if (s->addr < kernel_start_addr)
+		return 0;
+
 	/* skip prefix char */
 	if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
 		offset++;
@@ -646,6 +653,9 @@
 				if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
 					p++;
 				symbol_prefix_char = *p;
+			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+				const char *p = &argv[i][14];
+				kernel_start_addr = strtoull(p, NULL, 16);
 			} else
 				usage();
 		}
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 55fec32..1962ff0 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1396,7 +1396,10 @@
 	switch (decimator) {
 	case 1:
 	case 2:
-			adc_dmic_sel = 0x0;
+			if ((dec_mux == 3) || (dec_mux == 4))
+				adc_dmic_sel = 0x1;
+			else
+				adc_dmic_sel = 0x0;
 		break;
 	default:
 		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 28d4c84..14218d8 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -213,7 +213,6 @@
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
-	s16 v_brh, v_b1_hu;
 	struct snd_soc_codec *codec = mbhc->codec;
 	int mbhc_state = mbhc->mbhc_state;
 
@@ -254,17 +253,6 @@
 		/* set to max */
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-
-		v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-			      (v_brh >> 8) & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-			      v_brh & 0xFF);
-		v_b1_hu = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-			      v_b1_hu & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-			      (v_b1_hu >> 8) & 0xFF);
 	}
 
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
@@ -325,22 +313,32 @@
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 				      (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
 				      0xFF);
-			/* Threshods for button press */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-				      d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				      (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
-				      0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-				      d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-				      (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
-				      0xFF);
-			/* Threshods for button release */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-				      d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				      (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
+
+			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+				/* Threshods for button press */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+					d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+					(d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+					d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+					(d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+				/* Threshods for button release */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+					d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+					(d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+			}
 			pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
 				 __func__);
 		}
@@ -376,22 +374,31 @@
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 					(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
 					0xFF);
-			/* Revert threshods for button press */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-				      d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				      (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
-				      0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-				      d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-				      (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
-				      0xFF);
-			/* Revert threshods for button release */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-				      d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				      (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
+			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+				/* Revert threshods for button press */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+					d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+					(d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+					d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+					(d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+				/* Revert threshods for button release */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+					d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+					(d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+			}
 			pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
 					__func__);
 		}
@@ -489,19 +496,25 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 		      (v_ins_hu >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-		      (v_b1_hu >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-		      (v_b1_h >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-		      (v_brh >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
-		      mbhc->mbhc_data.v_brl & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
-		      (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+
+	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				(v_b1_hu >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+				(v_b1_h >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				(v_brh >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
+				mbhc->mbhc_data.v_brl & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
+				(mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+	}
 }
 
 static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
@@ -3148,15 +3161,22 @@
 	mv = ceilmv + btn_det->v_btn_press_delta_cic;
 	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
 
-	/* update LSB first so mbhc hardware block doesn't see too low value */
-	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-		      (v_b1_hu >> 8) & 0xFF);
-	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-		      (v_brh >> 8) & 0xFF);
+	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+		/*
+		 * update LSB first so mbhc hardware block
+		 * doesn't see too low value.
+		 */
+		v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				(v_b1_hu >> 8) & 0xFF);
+		v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				(v_brh >> 8) & 0xFF);
+	}
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 39cb470..6f94d99 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -422,6 +422,30 @@
 	},
 	{
 		.playback = {
+			.stream_name = "INT_HFP_BT Hostless Playback",
+			.aif_name = "INTHFP_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     16000,
+		},
+		.capture = {
+			.stream_name = "INT_HFP_BT Hostless Capture",
+			.aif_name = "INTHFP_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "INT_HFP_BT_HOSTLESS",
+	},
+	{
+		.playback = {
 			.stream_name = "AFE-PROXY Playback",
 			.aif_name = "PCM_RX",
 			.rates = (SNDRV_PCM_RATE_8000 |
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index ceea3d2..b4ae0a4 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1420,6 +1420,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_LSM1,
 	},
+	{
+		.name = "MSM8226 Compr8",
+		.stream_name = "COMPR8",
+		.cpu_dai_name	= "MultiMedia8",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		 /* this dainlink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c120e0c..69a6671 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2203,6 +2203,37 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{
+		.name = "INT_HFP_BT Hostless",
+		.stream_name = "INT_HFP_BT Hostless",
+		.cpu_dai_name   = "INT_HFP_BT_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "MSM8974 HFP TX",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name = "MultiMedia6",
+		.platform_name  = "msm-pcm-loopback",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
+	{
 		.name = LPASS_BE_SLIMBUS_4_TX,
 		.stream_name = "Slimbus4 Capture",
 		.cpu_dai_name = "msm-dai-q6-dev.16393",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 408ec03..c1ba26a 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -163,6 +163,8 @@
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
 };
 static int msm8x10_ext_spk_power_amp_init(void)
 {
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index ea16f47..f0f5db6 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -3,7 +3,8 @@
 			msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
 			msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
-			msm-lsm-client.o msm-audio-effects-q6-v2.o
+			msm-lsm-client.o msm-audio-effects-q6-v2.o \
+			msm-pcm-loopback-v2.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
 				 msm-dai-stub-v2.o
 obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58c3cdf..4e04bef 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -405,9 +405,9 @@
 
 done:
 	mutex_unlock(&acdb_data.acdb_mutex);
-ret:
 	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
 		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+ret:
 	return result;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..57fc268
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+				LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+	int session_id;
+	struct audio_client *audio_client;
+	int volume;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+	.formats                = 0xffffffff,
+	.channels_min           = 1,
+	.channels_max           = UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max       = 128*1024,
+	.period_bytes_min       = 1024,
+	.period_bytes_max       = 1024*2,
+	.periods_min            = 2,
+	.periods_max            = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_pcm_loopback *pcm = priv_data;
+
+	BUG_ON(!pcm);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_DEVSWITCH:
+		q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+		q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+		q6asm_run(pcm->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+					   uint32_t *payload, void *priv)
+{
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+			break;
+		default:
+			break;
+		}
+	}
+		break;
+	default:
+		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+	int rc = -EINVAL;
+
+	pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+	if (prtd && prtd->audio_client) {
+		rc = q6asm_set_volume(prtd->audio_client, volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		prtd->volume = volume;
+	}
+	return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct msm_pcm_loopback *pcm;
+	int ret = 0;
+	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_evt event;
+
+	pcm = dev_get_drvdata(rtd->platform->dev);
+	mutex_lock(&pcm->lock);
+
+	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+	pcm->volume = 0x2000;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_substream = substream;
+
+	pcm->instance++;
+	dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+			pcm->instance, substream->stream);
+	if (pcm->instance == 2) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+				pcm->capture_substream->private_data;
+		if (pcm->audio_client != NULL)
+			stop_pcm(pcm);
+
+		pcm->audio_client = q6asm_audio_client_alloc(
+				(app_cb)msm_pcm_loopback_event_handler, pcm);
+		if (!pcm->audio_client) {
+			dev_err(rtd->platform->dev,
+				"%s: Could not allocate memory\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		pcm->session_id = pcm->audio_client->session;
+		pcm->audio_client->perf_mode = false;
+		ret = q6asm_open_loopback_v2(pcm->audio_client,
+					     bits_per_sample);
+		if (ret < 0) {
+			dev_err(rtd->platform->dev,
+				"%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(pcm->audio_client);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) pcm;
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream,
+			event);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			pcm->playback_substream = substream;
+			ret = pcm_loopback_set_volume(pcm, pcm->volume);
+			if (ret < 0)
+				dev_err(rtd->platform->dev,
+					"Error %d setting volume", ret);
+		}
+	}
+	dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+			__func__ , pcm->instance, substream->pcm->id);
+	runtime->private_data = pcm;
+
+	mutex_unlock(&pcm->lock);
+
+	return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx =
+		pcm->playback_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_tx =
+		pcm->capture_substream->private_data;
+
+	if (pcm->audio_client == NULL)
+		return;
+	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(pcm->audio_client);
+	pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_start = 0;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_start = 0;
+
+	pcm->instance--;
+	if (!pcm->playback_start || !pcm->capture_start) {
+		dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+		stop_pcm(pcm);
+	}
+
+	mutex_unlock(&pcm->lock);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!pcm->playback_start)
+			pcm->playback_start = 1;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!pcm->capture_start)
+			pcm->capture_start = 1;
+	}
+	mutex_unlock(&pcm->lock);
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev_dbg(rtd->platform->dev,
+			"%s: playback_start:%d,capture_start:%d\n", __func__,
+			pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		dev_dbg(rtd->platform->dev,
+			"%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+			__func__, pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+		params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params      = msm_pcm_hw_params,
+	.hw_free        = msm_pcm_hw_free,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_pcm_volume *vol = kcontrol->private_data;
+	struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+	struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+	int volume = ucontrol->value.integer.value[0];
+
+	rc = pcm_loopback_set_volume(prtd, volume);
+	return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+	struct snd_pcm_volume *volume_info;
+	struct snd_kcontrol *kctl;
+	int ret = 0;
+
+	dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+	ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				      NULL, 1,
+				      rtd->dai_link->be_id,
+				      &volume_info);
+	if (ret < 0)
+		return ret;
+	kctl = volume_info->kctl;
+	kctl->put = msm_pcm_volume_ctl_put;
+	kctl->tlv.p = loopback_rx_vol_gain;
+	return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ret = msm_pcm_add_controls(rtd);
+	if (ret)
+		dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops            = &msm_pcm_ops,
+	.pcm_new        = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	dev_set_name(&pdev->dev, "%s", "msm-pcm-loopback");
+	dev_dbg(&pdev->dev, "%s: dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+	if (!pcm) {
+		dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+			__func__);
+		return -ENOMEM;
+	} else {
+		mutex_init(&pcm->lock);
+		dev_set_drvdata(&pdev->dev, pcm);
+	}
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	pcm = dev_get_drvdata(&pdev->dev);
+	mutex_destroy(&pcm->lock);
+	kfree(pcm);
+
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+	{.compatible = "qti,msm-pcm-loopback"},
+	{}
+};
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-loopback",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pcm_loopback_dt_match,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index dc41948..f25f746 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -109,6 +109,25 @@
 	.mask = 0,
 };
 
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_audio *prtd = priv_data;
+
+	BUG_ON(!prtd);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_BUF_RECFG:
+		q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+		q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+		q6asm_run(prtd->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
 static void event_handler(uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv)
 {
@@ -151,18 +170,31 @@
 		pr_debug("token = 0x%08x\n", token);
 		in_frame_info[token][0] = payload[4];
 		in_frame_info[token][1] = payload[5];
-		prtd->pcm_irq_pos += in_frame_info[token][0];
-		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
-		if (atomic_read(&prtd->start))
-			snd_pcm_period_elapsed(substream);
-		if (atomic_read(&prtd->in_count) <= prtd->periods)
-			atomic_inc(&prtd->in_count);
-		wake_up(&the_locks.read_wait);
-		if (prtd->mmap_flag
-			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+		/* assume data size = 0 during flushing */
+		if (in_frame_info[token][0]) {
+			prtd->pcm_irq_pos += in_frame_info[token][0];
+			pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+			if (atomic_read(&prtd->start))
+				snd_pcm_period_elapsed(substream);
+			if (atomic_read(&prtd->in_count) <= prtd->periods)
+				atomic_inc(&prtd->in_count);
+			wake_up(&the_locks.read_wait);
+			if (prtd->mmap_flag &&
+			    q6asm_is_cpu_buf_avail_nolock(OUT,
 				prtd->audio_client,
 				&size, &idx))
-			q6asm_read_nolock(prtd->audio_client);
+				q6asm_read_nolock(prtd->audio_client);
+		} else {
+			pr_debug("%s: reclaim flushed buf in_count %x\n",
+				__func__, atomic_read(&prtd->in_count));
+			atomic_inc(&prtd->in_count);
+			if (atomic_read(&prtd->in_count) == prtd->periods) {
+				pr_info("%s: reclaimed all bufs\n", __func__);
+				if (atomic_read(&prtd->start))
+					snd_pcm_period_elapsed(substream);
+				wake_up(&the_locks.read_wait);
+			}
+		}
 		break;
 	}
 	case APR_BASIC_RSP_RESULT: {
@@ -681,6 +713,7 @@
 	int dir, ret;
 	struct msm_plat_data *pdata;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_evt event;
 
 	pdata = (struct msm_plat_data *)
 				dev_get_drvdata(soc_prtd->platform->dev);
@@ -737,9 +770,12 @@
 		pr_debug("%s: session ID %d\n",
 				__func__, prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
-		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) prtd;
+		msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
 				prtd->audio_client->perf_mode,
-				prtd->session_id, substream->stream);
+				prtd->session_id, substream->stream,
+				event);
 	}
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 537719f..711291da 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,12 @@
 	unsigned int  format;
 };
 
+struct msm_pcm_routing_fdai_data {
+	u16 be_srate; /* track prior backend sample rate for flushing purpose */
+	int strm_id; /* ASM stream ID */
+	struct msm_pcm_routing_evt event_info;
+};
+
 #define INVALID_SESSION -1
 #define SESSION_TYPE_RX 0
 #define SESSION_TYPE_TX 1
@@ -250,25 +256,35 @@
 
 
 /* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+	fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
 	/* MULTIMEDIA1 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA2 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA3 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA4 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION,  {NULL, NULL} } },
 	/* MULTIMEDIA5 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA6 */
-	{INVALID_SESSION, INVALID_SESSION},
-	/* MULTIMEDIA7 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
+	/* MULTIMEDIA7*/
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA8 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA9 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 };
 
 /* Track performance mode of all front-end multimedia sessions.
@@ -334,7 +350,7 @@
 
 	mutex_lock(&routing_lock);
 
-	fe_dai_map[fedai_id][session_type] = dspst_id;
+	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
 		if (!is_be_dai_extproc(i) &&
 		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -376,7 +392,7 @@
 	mutex_lock(&routing_lock);
 
 	payload.num_copps = 0; /* only RX needs to use payload */
-	fe_dai_map[fedai_id][session_type] = dspst_id;
+	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
 	fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
 
 	/* re-enable EQ if active */
@@ -435,6 +451,19 @@
 	mutex_unlock(&routing_lock);
 }
 
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+				       int dspst_id, int stream_type,
+				       struct msm_pcm_routing_evt event_info)
+{
+	msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+				       stream_type);
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+		fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+	else
+		fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+}
+
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
 {
 	int i, port_type, session_type, path_type, topology;
@@ -470,8 +499,8 @@
 		}
 	}
 
-	fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+	fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+	fe_dai_map[fedai_id][session_type].be_srate = 0;
 	mutex_unlock(&routing_lock);
 }
 
@@ -497,6 +526,7 @@
 	int session_type, path_type, port_id, topology;
 	u32 channels;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_fdai_data *fdai;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
@@ -523,10 +553,23 @@
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
 		set_bit(val, &msm_bedais[reg].fe_sessions);
-		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+		fdai = &fe_dai_map[val][session_type];
+		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
 
 			channels = msm_bedais[reg].channel;
+			if (session_type == SESSION_TYPE_TX &&
+			    fdai->be_srate &&
+			    (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+				pr_debug("%s: flush strm %d diff BE rates\n",
+					__func__, fdai->strm_id);
+
+				if (fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_BUF_RECFG,
+						fdai->event_info.priv_data);
+				fdai->be_srate = 0; /* might not need it */
+			}
 			if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
 
@@ -549,8 +592,14 @@
 				msm_bedais[reg].sample_rate, channels,
 				topology, false, bits_per_sample);
 
+			if (session_type == SESSION_TYPE_RX &&
+			    fdai->event_info.event_func)
+				fdai->event_info.event_func(
+					MSM_PCM_RT_EVT_DEVSWITCH,
+					fdai->event_info.priv_data);
+
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[val][session_type]);
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
@@ -566,7 +615,8 @@
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
-		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+		fdai = &fe_dai_map[val][session_type];
+		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
 			adm_close(msm_bedais[reg].port_id,
 				  fe_dai_perf_mode[val][session_type]);
@@ -574,7 +624,7 @@
 			    (fe_dai_perf_mode[val][session_type] == false))
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[val][session_type]);
 		}
 	}
@@ -1203,12 +1253,12 @@
 static void msm_send_eq_values(int eq_idx)
 {
 	int result;
-	struct audio_client *ac =
-		q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+	struct audio_client *ac = q6asm_get_audio_client(
+				  fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
 
 	if (ac == NULL) {
 		pr_err("%s: Could not get audio client for session: %d\n",
-		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
 		goto done;
 	}
 
@@ -2034,6 +2084,15 @@
 };
 
 
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -3040,6 +3099,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -3068,6 +3128,10 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
@@ -3218,6 +3282,8 @@
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3474,6 +3540,7 @@
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3484,6 +3551,7 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3516,6 +3584,7 @@
 	{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3527,6 +3596,7 @@
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3716,6 +3786,8 @@
 
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+	{"INTHFP_UL_HL", NULL, "INT_BT_SCO_TX"},
+	{"INT_BT_SCO_RX", NULL, "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
 	{"MI2S_RX", NULL, "MI2S_DL_HL"},
@@ -3881,7 +3953,9 @@
 	mutex_lock(&routing_lock);
 	topology = get_topology(path_type);
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
-		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+		if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+			fe_dai_map[i][session_type].be_srate =
+				bedai->sample_rate;
 			adm_close(bedai->port_id,
 				  fe_dai_perf_mode[i][session_type]);
 			srs_port_id = -1;
@@ -3908,6 +3982,7 @@
 	u32 channels;
 	bool playback, capture;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_fdai_data *fdai;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3939,8 +4014,21 @@
 	capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
 
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
-		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+		fdai = &fe_dai_map[i][session_type];
+		if (fdai->strm_id != INVALID_SESSION) {
+			if (session_type == SESSION_TYPE_TX &&
+			    fdai->be_srate &&
+			    (fdai->be_srate != bedai->sample_rate)) {
+				pr_debug("%s: flush strm %d diff BE rates\n",
+					__func__,
+					fdai->strm_id);
 
+				if (fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_BUF_RECFG,
+						fdai->event_info.priv_data);
+				fdai->be_srate = 0; /* might not need it */
+			}
 			channels = bedai->channel;
 			if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
@@ -3967,7 +4055,7 @@
 			}
 
 			msm_pcm_routing_build_matrix(i,
-				fe_dai_map[i][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[i][session_type]);
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 10be150..4f7c4e3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -133,6 +133,12 @@
 	MSM_BACKEND_DAI_MAX,
 };
 
+enum msm_pcm_routing_event {
+	MSM_PCM_RT_EVT_BUF_RECFG,
+	MSM_PCM_RT_EVT_DEVSWITCH,
+	MSM_PCM_RT_EVT_MAX,
+};
+
 /* dai_id: front-end ID,
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
@@ -142,6 +148,15 @@
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type);
 
+struct msm_pcm_routing_evt {
+	void (*event_func)(enum msm_pcm_routing_event, void *);
+	void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+				       int dspst_id, int stream_type,
+				       struct msm_pcm_routing_evt event_info);
+
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
 
 int msm_routing_check_backend_enabled(int fedai_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 95114e0..631e9bd 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1256,6 +1256,7 @@
 		case ASM_STREAM_CMD_OPEN_READ_V3:
 		case ASM_STREAM_CMD_OPEN_WRITE_V3:
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_CMD_ADD_TOPOLOGIES:
@@ -1744,6 +1745,7 @@
 			rc);
 		goto fail_cmd;
 	}
+	ac->io_mode |= TUN_READ_IO_MODE;
 	return 0;
 fail_cmd:
 	return -EINVAL;
@@ -1837,6 +1839,7 @@
 			rc);
 		goto fail_cmd;
 	}
+	ac->io_mode |= TUN_WRITE_IO_MODE;
 	return 0;
 fail_cmd:
 	return -EINVAL;
@@ -1977,6 +1980,49 @@
 	return -EINVAL;
 }
 
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_loopback_v2 open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+	open.mode_flags = 0;
+	open.src_endpointype = 0;
+	open.sink_endpointype = 0;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+	open.bits_per_sample = bits_per_sample;
+	open.reserved = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s open failed op[0x%x]rc[%d]\n", __func__,
+				open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s timeout. waited for open_loopback rc[%d]\n",
+				__func__, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts)
 {
@@ -4217,9 +4263,11 @@
 {
 	int cnt = 0;
 	int loopcnt = 0;
+	int used;
 	struct audio_port_data *port = NULL;
 
 	if (ac->io_mode & SYNC_IO_MODE) {
+		used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
 		mutex_lock(&ac->cmd_lock);
 		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
 			port = &ac->port[loopcnt];
@@ -4229,7 +4277,7 @@
 			while (cnt >= 0) {
 				if (!port->buf)
 					continue;
-				port->buf[cnt].used = 1;
+				port->buf[cnt].used = used;
 				cnt--;
 			}
 		}