Merge "netlink: use kfree_rcu() in netlink_release()"
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 25219cd..ce797d3 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -19,7 +19,8 @@
 	"arm,coresight-stm" for coresight stm trace device,
 	"arm,coresight-etm" for coresight etm trace devices,
 	"qcom,coresight-csr" for coresight csr device,
-	"arm,coresight-cti" for coresight cti devices
+	"arm,coresight-cti" for coresight cti devices,
+	"qcom,coresight-hwevent" for coresight hardware event devices
 - reg : physical base address and length of the register set(s) of the component
 - reg-names : names corresponding to each reg property value. The reg-names that
 	need to be used with corresponding compatible string for a coresight device
@@ -61,6 +62,12 @@
 		compatible : should be "arm,coresight-cti"
 		reg-names  : should be:
 			"cti<num>-base" - physical base address of cti registers
+	- for coresight hardware event devices:
+		compatible : should be "qcom,coresight-hwevent"
+		reg-names  : should be:
+			"<ss-mux>" - physical base address of hardware event mux
+				control registers where <ss-mux> is subsystem mux it
+				represents
 - coresight-id : unique integer identifier for the component
 - coresight-name : unique descriptive name of the component
 - coresight-nr-inports : number of input ports on the component
@@ -105,6 +112,7 @@
 - qcom,setb-gpios-drv : active drive strength for set B gpios
 - qcom,setb-gpios-pull : active pull configuration for set B gpios
 - qcom,setb-gpios-dir : active direction for set B gpios
+- qcom,hwevent-clks : list of clocks required by hardware event driver
 
 Examples:
 
@@ -213,3 +221,17 @@
 		coresight-name = "coresight-cti1";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fdf30018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfdf30018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
index da99e19..76cacd8 100644
--- a/Documentation/devicetree/bindings/input/gen_vkeys.txt
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -11,7 +11,7 @@
  - qcom,panel-maxx	: Maximum x-coordinate of touch panel
  - qcom,panel-maxy	: Maximum y-coordinate of touch panel
  - qcom,key-codes	: Array of key codes for virtual keys
-
+ - qcom,y-offset	: Offset of y-location for virtual keys
 Example:
 	gen-vkeys {
 		compatible = "qcom,gen-vkeys";
@@ -21,4 +21,5 @@
 		qcom,panel-maxx = <760>;
 		qcom,panel-maxy = <1424>;
 		qcom,key-codes = <158 139 102 217>;
+		qcom,y-offset = <35>;
 	};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index cc1ffc2..af5cbc6 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -11,17 +11,20 @@
 - qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
 - qcom,iommu-pmu-ncounters: Number of PMU counters per group.
 - qcom,iommu-pmu-event-classes: List of event classes supported.
+- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
+  access to the IOMMU configuration registers
+
 - List of sub nodes, one for each of the translation context banks supported.
-  Each sub node has the following required properties:
+    Required properties for each sub-node:
 
-  - reg : offset and length of the register set for the context bank.
-  - interrupts : should contain the context bank interrupt.
-  - qcom,iommu-ctx-mids : List of machine identifiers associated with this
-    translation context.
-  - label : Name of the context bank
+    - reg : offset and length of the register set for the context bank.
+    - interrupts : should contain the context bank interrupt.
+    - qcom,iommu-ctx-mids : List of machine identifiers associated with this
+      translation context.
+    - label : Name of the context bank
 
-Optional properties:
-  - none
+    Optional properties for each sub-node:
+    - none
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 96d95da..c409ea6 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -45,6 +45,7 @@
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
+- qcom,torch-enable: set flash led to torch mode
 
 RGB Led is a tri-colored led, Red, Blue & Green.
 
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index c3d929c..4a312a8 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -12,7 +12,6 @@
 - reg-names:	      Names of the bases for the above registers. "qdsp6_base",
 		      "halt_base", "rmb_base", and "restart_reg" are expected.
 - interrupts:         The modem watchdog interrupt
-- vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - vdd_cx-supply:      Reference to the regulator that supplies the vdd_cx domain.
 - vdd_mx-supply:      Reference to the regulator that supplies the memory rail.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
@@ -23,6 +22,10 @@
 - qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
 
 Optional properties:
+- vdd_mss-supply:     Reference to the regulator that supplies the processor.
+		      This may be a shared regulator that is already voted
+		      on in the PIL proxy voting code (and also managed by the
+		      modem on its own), hence we mark it as as optional.
 - vdd_pll-supply:     Reference to the regulator that supplies the PLL's rail.
 - qcom,vdd_pll:       Voltage to be set for the PLL's rail.
 - reg-names:          "cxrail_bhs_reg" - control register for modem power
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 777933a..9abf54e 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -76,6 +76,8 @@
 				dynamically.
 				Supplies in this list are off by default.
 
+ - qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
+
 Example:
 
 taiko_codec {
@@ -138,6 +140,7 @@
 	qcom,cdc-slim-ifd = "taiko-slim-ifd";
 	qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
 	qcom,cdc-dmic-sample-rate = <4800000>;
+	qcom,cdc-micbias2-headset-only;
 };
 
 Wcd9xxx audio CODEC in I2C mode
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index ba1ccd7..2543c40 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -165,6 +165,42 @@
 	android_usb {
 		compatible = "qcom,android-usb";
 	};
+
+	qcom,ocmem@fdd00000 {
+		compatible = "qcom,msm-ocmem";
+		reg = <0xfdd00000 0x2000>,
+		      <0xfdd02000 0x2000>,
+		      <0xfe039000 0x400>,
+		      <0xfec00000 0x200000>;
+		reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
+		interrupts = <0 76 0 0 77 0>;
+		interrupt-names = "ocmem_irq", "dm_irq";
+		qcom,ocmem-num-regions = <0x4>;
+		qcom,ocmem-num-macros = <0x20>;
+		qcom,resource-type = <0x706d636f>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0xfec00000 0x200000>;
+
+		partition@0 {
+			reg = <0x0 0x180000>;
+			qcom,ocmem-part-name = "graphics";
+			qcom,ocmem-part-min = <0x80000>;
+		};
+
+		partition@80000 {
+			reg = <0x180000 0x80000>;
+			qcom,ocmem-part-name = "lp_audio";
+			qcom,ocmem-part-min = <0x80000>;
+		};
+
+		partition@100000 {
+			reg = <0x180000 0x80000>;
+			qcom,ocmem-part-name = "video";
+			qcom,ocmem-part-min = <0x55000>;
+		};
+
+	};
 };
 
 /include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 1cc3c59..b0257d0 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -207,6 +207,7 @@
 		reg = <0xfd880000 0x10000>;
 		interrupts = <0 38 0>;
 		qcom,glb-offset = <0xF000>;
+		qcom,needs-alt-core-clk;
 		label = "gfx_iommu";
 		qcom,iommu-pmu-ngroups = <1>;
 		qcom,iommu-pmu-ncounters = <4>;
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 689bf0f..fad9d86 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -196,6 +196,21 @@
 				qcom,fast-avg-setup = <0>;
 			};
 		};
+
+		pm8019_adc_tm: vadc@3400 {
+			compatible = "qcom,qpnp-adc-tm";
+			reg = <0x3400 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts =	<0x0 0x34 0x0>,
+					<0x0 0x34 0x3>,
+				     <0x0 0x34 0x4>;
+			interrupt-names =	"eoc-int-en-set",
+						"high-thr-en-set",
+						"low-thr-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1800>;
+		};
 	};
 
 	qcom,pm8019@1 {
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 391c564..bce9806 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,29 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0>,
+				     <0x0 0x8 0x1>,
+				     <0x0 0x8 0x4>;
+			interrupt-names = "kpdpwr", "resin", "resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,pull-up = <1>;
+				linux,code = <114>;
+			};
+		};
+
 		pm8110_chg: qcom,charger {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-charger";
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 8a1ac1d..3240efb 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -153,10 +153,10 @@
 			qcom,mode = "wfi";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
 			qcom,mode = "standalone_pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_retention";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <3>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,latency-us = <16300>;
 			qcom,ss-power = <63>;
 			qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <3>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,latency-us = <24000>;
 			qcom,ss-power = <10>;
 			qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
-			qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
-			qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
-			qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+			qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+			qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
 			qcom,latency-us = <26000>;
 			qcom,ss-power = <2>;
 			qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 6c06336..3cd9cb5 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -800,7 +800,6 @@
 			    "restart_reg", "cxrail_bhs_reg";
 
 		interrupts = <0 24 1>;
-		vdd_mss-supply = <&pm8226_s1>;
 		vdd_cx-supply = <&pm8226_s1_corner>;
 		vdd_mx-supply = <&pm8226_l3>;
 		vdd_pll-supply = <&pm8226_l8>;
@@ -980,22 +979,27 @@
 };
 
 &gdsc_venus {
+	qcom,clock-names = "core_clk";
 	status = "ok";
 };
 
 &gdsc_mdss {
+	qcom,clock-names = "core_clk", "lut_clk";
 	status = "ok";
 };
 
 &gdsc_jpeg {
+	qcom,clock-names = "core_clk";
 	status = "ok";
 };
 
 &gdsc_vfe {
+	qcom,clock-names = "core_clk", "csi_clk", "cpp_clk";
 	status = "ok";
 };
 
 &gdsc_oxili_cx {
+	qcom,clock-names = "core_clk";
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 28e9dc5..1bf7c2b 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -156,7 +156,7 @@
 			qcom,led_mpp_3 {
 				label = "mpp";
 				linux,name = "wled-backlight";
-				linux-default-trigger = "none";
+				linux,default-trigger = "bkl-trigger";
 				qcom,default-state = "on";
 				qcom,max-current = <40>;
 				qcom,id = <6>;
@@ -207,6 +207,17 @@
 			qcom,vib-vtg-level-mV = <3100>;
 		};
 	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "atmel_mxt_ts";
+		qcom,disp-maxx = <480>;
+		qcom,disp-maxy = <800>;
+		qcom,panel-maxx = <508>;
+		qcom,panel-maxy = <880>;
+		qcom,key-codes = <158 102 139>;
+		qcom,y-offset = <35>;
+	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 83e7b48..3fbc820 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -156,7 +156,7 @@
 			qcom,led_mpp_3 {
 				label = "mpp";
 				linux,name = "wled-backlight";
-				linux-default-trigger = "none";
+				linux,default-trigger = "bkl-trigger";
 				qcom,default-state = "on";
 				qcom,max-current = <40>;
 				qcom,id = <6>;
@@ -207,6 +207,17 @@
 			qcom,vib-vtg-level-mV = <3100>;
 		};
 	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "atmel_mxt_ts";
+		qcom,disp-maxx = <480>;
+		qcom,disp-maxy = <800>;
+		qcom,panel-maxx = <508>;
+		qcom,panel-maxy = <880>;
+		qcom,key-codes = <158 102 139>;
+		qcom,y-offset = <35>;
+	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index 34382c5..938b2aa 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -114,7 +114,7 @@
 			qcom,type = <0x61706d73>;	/* "smpa" */
 			qcom,id = <0x01>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
+			qcom,init-value = <3>;		/* SVS SOC */
 		};
 
 		qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
 			qcom,type = <0x616F646C>;	/* "ldoa" */
 			qcom,id = <0x03>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* Active */
+			qcom,init-value = <3>;		/* SVS SOC */
 		};
 
 		qcom,lpm-resources@2 {
@@ -153,10 +153,10 @@
 			qcom,mode = "wfi";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
 			qcom,mode = "standalone_pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_retention";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <3>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,irqs-detectable;
 			qcom,gpio-detectable;
 			qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* NORMAL */
+			qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,latency-us = <16300>;
 			qcom,ss-power = <63>;
 			qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <2>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <3>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <2>;  /* SVS SOC */
+			qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <3>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,latency-us = <24000>;
 			qcom,ss-power = <10>;
 			qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
 			qcom,mode = "pc";
 			qcom,xo = "xo_off";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
-			qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
-			qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
-			qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+			qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+			qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
 			qcom,latency-us = <26000>;
 			qcom,ss-power = <2>;
 			qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 9e79df1..3df428a 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -44,6 +44,9 @@
 		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
 		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
+		vdd-mx-supply = <&pm8110_l3_ao>;
+		qcom,vdd-mx-vmax = <1350000>;
+		qcom,vdd-mx-vmin-method = <1>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 4b861ed..cf05fe4 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -676,7 +676,6 @@
 			    "restart_reg", "cxrail_bhs_reg";
 
 		interrupts = <0 24 1>;
-		vdd_mss-supply = <&pm8110_s1>;
 		vdd_cx-supply = <&pm8110_s1_corner>;
 		vdd_mx-supply = <&pm8110_l3>;
 		vdd_pll-supply = <&pm8110_l10>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 72b6223..5fa7c08 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -195,6 +195,7 @@
 		qcom,model = "msm8974-taiko-cdp-snd-card";
 		qcom,hdmi-audio-rx;
 		qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
+		qcom,cdc-micbias2-headset-only;
 	};
 
 	usb2_otg_sw: regulator-tpd4s214 {
@@ -499,7 +500,7 @@
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
 		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
+		qcom,out-strength = <1>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index cccedd8..1610f1f 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -364,4 +364,18 @@
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fdf30018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfdf30018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 06b13b8..ad5f175 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -230,6 +230,7 @@
 
 		qcom,hdmi-audio-rx;
 		qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
+		qcom,cdc-micbias2-headset-only;
 	};
 };
 
@@ -505,7 +506,7 @@
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
 		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
+		qcom,out-strength = <1>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index befd206..b39cc21 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -93,6 +93,20 @@
 				linux,name = "led:flash_1";
 				qcom,current = <625>;
 			};
+
+			pm8941_torch: qcom,flash_torch {
+				qcom,max-current = <200>;
+				qcom,default-state = "off";
+				qcom,headroom = <0>;
+				qcom,startup-dly = <1>;
+				linux,default-trigger =
+					"torch_trigger";
+				label = "flash";
+				qcom,id = <2>;
+				linux,name = "led:flash_torch";
+				qcom,current = <200>;
+				qcom,torch-enable;
+			};
 		};
 
 		qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 3f4e035..e63b53b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -511,7 +511,7 @@
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
 		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
+		qcom,out-strength = <1>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 37286af..4d28a1d 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -187,6 +187,7 @@
 
 	sound {
 		qcom,model = "msm8974-taiko-mtp-snd-card";
+		qcom,cdc-micbias2-headset-only;
 	};
 };
 
@@ -489,7 +490,7 @@
 		qcom,output-type = <0>;
 		qcom,pull = <5>;
 		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
+		qcom,out-strength = <1>;
 		qcom,src-sel = <2>;
 		qcom,master-en = <1>;
 	};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f614d61..5abfab8 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -967,3 +967,32 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&pm8019_adc_tm {
+	/* Channel Node */
+	chan@33 {
+		label = "pa_therm0";
+		reg = <0x33>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x48>;
+		qcom,thermal-node;
+	};
+
+	chan@34 {
+		label = "pa_therm1";
+		reg = <0x34>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+};
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 5660dec..e45024e 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -62,6 +62,7 @@
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 09b038c..bff59db 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -69,6 +69,7 @@
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index dc84558..8ebe7d4 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -443,15 +443,6 @@
 CONFIG_IOMMU_PGTABLES_L2=y
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
-CONFIG_CORESIGHT_EVENT=m
 CONFIG_BIF=y
 CONFIG_BIF_QPNP=y
 CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 1e0134a..662d555 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -225,6 +225,7 @@
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -278,14 +279,6 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_IPA=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT3_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index f7c3bff..7e92748 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -225,6 +225,7 @@
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index a6f772d..5793326 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -80,8 +80,8 @@
 	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 3 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
 	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
 	{ 0 }
 };
 
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 27bfcac..6212a4d 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3138,10 +3138,10 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
-	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33c000.jtagmm"),
-	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33d000.jtagmm"),
-	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33e000.jtagmm"),
-	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33f000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.jtagmm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
@@ -3279,6 +3279,15 @@
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
 
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", camss_vfe_vfe0_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("csi_clk", camss_csi_vfe0_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5e60bd5..aa9368d 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3061,6 +3061,7 @@
 	CLK_DUMMY("core_clk",   NULL, "fd870000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd880000.qcom,iommu", OFF),
 	CLK_DUMMY("core_clk",   NULL, "fd880000.qcom,iommu", OFF),
+	CLK_DUMMY("alt_core_clk",   NULL, "fd880000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd000000.qcom,iommu", OFF),
 	CLK_DUMMY("core_clk",   NULL, "fd000000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd010000.qcom,iommu", OFF),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 4fb348d..75919149 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5207,6 +5207,7 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fdf30018.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -5236,6 +5237,9 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fdf30018.hwevent"),
+
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fdf30018.hwevent"),
 
 	CLK_LOOKUP("l2_m_clk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_m_clk",	krait0_m_clk, ""),
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index c68c783..894379e 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -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
@@ -31,6 +31,11 @@
 	MSM_IPC_ROUTER_WRITE_DONE,
 };
 
+struct comm_mode_info {
+	int mode;
+	void *xprt_info;
+};
+
 struct msm_ipc_port {
 	struct list_head list;
 
@@ -39,6 +44,7 @@
 	uint32_t type;
 	unsigned flags;
 	spinlock_t port_lock;
+	struct comm_mode_info mode_info;
 
 	struct list_head incomplete;
 	struct mutex incomplete_lock;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c31c969..a328b2b 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1245,6 +1245,67 @@
 	return 0;
 }
 
+static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
+					uint32_t node_id, uint32_t port_id)
+{
+	union rr_control_msg msg;
+	struct msm_ipc_router_xprt_info *tmp_xprt_info;
+	int mode;
+	void *xprt_info;
+	int rc = 0;
+
+	if (!mode_info) {
+		pr_err("%s: NULL mode_info\n", __func__);
+		return -EINVAL;
+	}
+	mode = mode_info->mode;
+	xprt_info = mode_info->xprt_info;
+
+	msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+	msg.cli.node_id = node_id;
+	msg.cli.port_id = port_id;
+
+	if ((mode == SINGLE_LINK_MODE) && xprt_info) {
+		mutex_lock(&xprt_info_list_lock);
+		list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
+			if (tmp_xprt_info != xprt_info)
+				continue;
+			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+			break;
+		}
+		mutex_unlock(&xprt_info_list_lock);
+	} else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
+		broadcast_ctl_msg_locally(&msg);
+	} else if (mode == MULTI_LINK_MODE) {
+		broadcast_ctl_msg(&msg);
+		broadcast_ctl_msg_locally(&msg);
+	} else if (mode != NULL_MODE) {
+		pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
+			__func__, mode, xprt_info, node_id, port_id);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static void update_comm_mode_info(struct comm_mode_info *mode_info,
+				  struct msm_ipc_router_xprt_info *xprt_info)
+{
+	if (!mode_info) {
+		pr_err("%s: NULL mode_info\n", __func__);
+		return;
+	}
+
+	if (mode_info->mode == NULL_MODE) {
+		mode_info->xprt_info = xprt_info;
+		mode_info->mode = SINGLE_LINK_MODE;
+	} else if (mode_info->mode == SINGLE_LINK_MODE &&
+		   mode_info->xprt_info != xprt_info) {
+		mode_info->mode = MULTI_LINK_MODE;
+	}
+
+	return;
+}
+
 static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
 {
 	struct msm_ipc_router_remote_port *rport_ptr;
@@ -1915,6 +1976,7 @@
 	broadcast_ctl_msg(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
+	port_ptr->mode_info.mode = MULTI_LINK_MODE;
 	port_ptr->port_name.service = server->name.service;
 	port_ptr->port_name.instance = server->name.instance;
 	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -2026,6 +2088,7 @@
 	ret_len = pkt->length;
 	wake_up(&port_ptr->port_rx_wait_q);
 	mutex_unlock(&port_ptr->port_rx_q_lock);
+	update_comm_mode_info(&src->mode_info, NULL);
 	mutex_unlock(&local_ports_lock);
 
 	return ret_len;
@@ -2118,6 +2181,7 @@
 		pr_err("%s: Write on XPRT failed\n", __func__);
 		return ret;
 	}
+	update_comm_mode_info(&src->mode_info, xprt_info);
 
 	RAW_HDR("[w rr_h] "
 		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
@@ -2407,13 +2471,11 @@
 		 * Server port could have been a client port earlier.
 		 * Send REMOVE_CLIENT message in either case.
 		 */
-		msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
-		msg.cli.node_id = port_ptr->this_port.node_id;
-		msg.cli.port_id = port_ptr->this_port.port_id;
 		RR("x REMOVE_CLIENT id=%d:%08x\n",
-		   msg.cli.node_id, msg.cli.port_id);
-		broadcast_ctl_msg(&msg);
-		broadcast_ctl_msg_locally(&msg);
+		   port_ptr->this_port.node_id, port_ptr->this_port.port_id);
+		msm_ipc_router_send_remove_client(&port_ptr->mode_info,
+			port_ptr->this_port.node_id,
+			port_ptr->this_port.port_id);
 	} else if (port_ptr->type == CONTROL_PORT) {
 		mutex_lock(&control_ports_lock);
 		list_del(&port_ptr->list);
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index cafcdd2..32832dd 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -62,6 +62,12 @@
 	IRSC_PORT,
 };
 
+enum {
+	NULL_MODE,
+	SINGLE_LINK_MODE,
+	MULTI_LINK_MODE,
+};
+
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index e993282..d657b05 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -104,13 +104,15 @@
 
 static int pil_mss_power_up(struct q6v5_data *drv)
 {
-	int ret;
+	int ret = 0;
 	struct device *dev = drv->desc.dev;
 	u32 regval;
 
-	ret = regulator_enable(drv->vreg);
-	if (ret)
-		dev_err(dev, "Failed to enable modem regulator.\n");
+	if (drv->vreg) {
+		ret = regulator_enable(drv->vreg);
+		if (ret)
+			dev_err(dev, "Failed to enable modem regulator.\n");
+	}
 
 	if (drv->cxrail_bhs) {
 		regval = readl_relaxed(drv->cxrail_bhs);
@@ -134,7 +136,10 @@
 		writel_relaxed(regval, drv->cxrail_bhs);
 	}
 
-	return regulator_disable(drv->vreg);
+	if (drv->vreg)
+		return regulator_disable(drv->vreg);
+
+	return 0;
 }
 
 static int pil_mss_enable_clks(struct q6v5_data *drv)
@@ -724,6 +729,7 @@
 	struct q6v5_data *q6;
 	struct pil_desc *q6_desc, *mba_desc;
 	struct resource *res;
+	struct property *prop;
 	int ret;
 
 	int clk_ready = of_get_named_gpio(pdev->dev.of_node,
@@ -761,31 +767,36 @@
 	if (!q6->restart_reg)
 		return -ENOMEM;
 
-	q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
-	if (IS_ERR(q6->vreg))
-		return PTR_ERR(q6->vreg);
+	q6->vreg = NULL;
+
+	prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
+	if (prop) {
+		q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+		if (IS_ERR(q6->vreg))
+			return PTR_ERR(q6->vreg);
+
+		ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV,
+						MAX_VDD_MSS_UV);
+		if (ret)
+			dev_err(&pdev->dev, "Failed to set vreg voltage.\n");
+
+		ret = regulator_set_optimum_mode(q6->vreg, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Failed to set vreg mode.\n");
+			return ret;
+		}
+	}
 
 	q6->vreg_mx = devm_regulator_get(&pdev->dev, "vdd_mx");
 	if (IS_ERR(q6->vreg_mx))
 		return PTR_ERR(q6->vreg_mx);
 
-	ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV, MAX_VDD_MSS_UV);
-	if (ret)
-		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
-
-	ret = regulator_set_optimum_mode(q6->vreg, 100000);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
-		return ret;
-	}
-
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 		"cxrail_bhs_reg");
 	if (res)
 		q6->cxrail_bhs = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 
-
 	q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
 	if (IS_ERR(q6->ahb_clk))
 		return PTR_ERR(q6->ahb_clk);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 12a3ceb..d316496 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -279,6 +279,8 @@
 	/* 8974 IDs */
 	[126] = MSM_CPU_8974,
 	[184] = MSM_CPU_8974,
+	[185] = MSM_CPU_8974,
+	[186] = MSM_CPU_8974,
 
 	/* 8625 IDs */
 	[127] = MSM_CPU_8625,
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5e00570..7ec83dd 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -105,6 +105,16 @@
 	  If unsure, say 'N' here to avoid potential power and performance
 	  penalty.
 
+config CORESIGHT_HWEVENT
+	bool "CoreSight Hardware Event driver"
+	depends on CORESIGHT_STM
+	select CORESIGHT_CSR
+	help
+	  This driver provides support for monitoring and tracing CoreSight
+	  Hardware Event across STM interface. It configures Coresight
+	  Hardware Event mux control registers to select hardware events
+	  based on user input.
+
 config CORESIGHT_ETM
 	bool "CoreSight Embedded Trace Macrocell driver"
 	help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0595064..0e2e2d9 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -11,5 +11,6 @@
 obj-$(CONFIG_CORESIGHT_FUNNEL) += coresight-funnel.o
 obj-$(CONFIG_CORESIGHT_REPLICATOR) += coresight-replicator.o
 obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
+obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
 obj-$(CONFIG_CORESIGHT_ETM) += coresight-etm.o coresight-etm-cp14.o
 obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 1c2ab25..8195184 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -73,6 +73,7 @@
 
 struct csr_drvdata {
 	void __iomem		*base;
+	phys_addr_t		pbase;
 	struct device		*dev;
 	struct coresight_device	*csdev;
 	uint32_t		blksize;
@@ -134,6 +135,30 @@
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
 
+int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+	int ret = 0;
+
+	CSR_UNLOCK(drvdata);
+
+	if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
+		csr_writel(drvdata, val, CSR_STMEXTHWCTRL0);
+	else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL1))
+		csr_writel(drvdata, val, CSR_STMEXTHWCTRL1);
+	else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL2))
+		csr_writel(drvdata, val, CSR_STMEXTHWCTRL2);
+	else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL3))
+		csr_writel(drvdata, val, CSR_STMEXTHWCTRL3);
+	else
+		ret = -EINVAL;
+
+	CSR_LOCK(drvdata);
+
+	return ret;
+}
+EXPORT_SYMBOL(coresight_csr_hwctrl_set);
+
 static int __devinit csr_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -161,6 +186,7 @@
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
 	if (!res)
 		return -ENODEV;
+	drvdata->pbase = res->start;
 
 	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
 	if (!drvdata->base)
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
new file mode 100644
index 0000000..777484d
--- /dev/null
+++ b/drivers/coresight/coresight-hwevent.c
@@ -0,0 +1,341 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/of.h>
+
+#include "coresight-priv.h"
+
+struct hwevent_mux {
+	phys_addr_t				start;
+	phys_addr_t				end;
+};
+
+struct hwevent_drvdata {
+	struct device				*dev;
+	struct coresight_device			*csdev;
+	struct clk				*clk;
+	struct mutex				mutex;
+	int					nr_hclk;
+	struct clk				**hclk;
+	int					nr_hmux;
+	struct hwevent_mux			*hmux;
+	bool					enable;
+};
+
+static int hwevent_enable(struct hwevent_drvdata *drvdata)
+{
+	int ret, i;
+
+	mutex_lock(&drvdata->mutex);
+
+	if (drvdata->enable)
+		goto out;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		goto err0;
+	for (i = 0; i < drvdata->nr_hclk; i++) {
+		ret = clk_prepare_enable(drvdata->hclk[i]);
+		if (ret)
+			goto err1;
+	}
+	drvdata->enable = true;
+	dev_info(drvdata->dev, "Hardware Event driver enabled\n");
+out:
+	mutex_unlock(&drvdata->mutex);
+	return 0;
+err1:
+	clk_disable_unprepare(drvdata->clk);
+	for (i--; i >= 0; i--)
+		clk_disable_unprepare(drvdata->hclk[i]);
+err0:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static void hwevent_disable(struct hwevent_drvdata *drvdata)
+{
+	int i;
+
+	mutex_lock(&drvdata->mutex);
+
+	if (!drvdata->enable)
+		goto out;
+
+	drvdata->enable = false;
+	clk_disable_unprepare(drvdata->clk);
+	for (i = 0; i < drvdata->nr_hclk; i++)
+		clk_disable_unprepare(drvdata->hclk[i]);
+	dev_info(drvdata->dev, "Hardware Event driver disabled\n");
+out:
+	mutex_unlock(&drvdata->mutex);
+}
+
+static ssize_t hwevent_show_enable(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->enable;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t hwevent_store_enable(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	int ret = 0;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = hwevent_enable(drvdata);
+	else
+		hwevent_disable(drvdata);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, hwevent_show_enable,
+		   hwevent_store_enable);
+
+static ssize_t hwevent_store_setreg(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	void *hwereg;
+	phys_addr_t addr;
+	uint32_t val;
+	int ret, i;
+
+	if (sscanf(buf, "%x %x", &addr, &val) != 2)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->mutex);
+
+	if (!drvdata->enable) {
+		dev_err(dev, "Hardware Event driver not enabled\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < drvdata->nr_hmux; i++) {
+		if ((addr >= drvdata->hmux[i].start) &&
+		    (addr < drvdata->hmux[i].end)) {
+			hwereg = devm_ioremap(dev,
+					      drvdata->hmux[i].start,
+					      drvdata->hmux[i].end -
+					      drvdata->hmux[i].start);
+			if (!hwereg) {
+				dev_err(dev, "unable to map address 0x%x\n",
+					addr);
+				ret = -ENOMEM;
+				goto err;
+			}
+			writel_relaxed(val, hwereg + addr -
+				       drvdata->hmux[i].start);
+			/* Ensure writes to hwevent control registers
+			   are completed before unmapping the address
+			*/
+			mb();
+			devm_iounmap(dev, hwereg);
+			break;
+		}
+	}
+
+	if (i == drvdata->nr_hmux) {
+		ret = coresight_csr_hwctrl_set(addr, val);
+		if (ret) {
+			dev_err(dev, "invalid mux control register address\n");
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+
+	mutex_unlock(&drvdata->mutex);
+	return size;
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+static DEVICE_ATTR(setreg, S_IWUSR, NULL, hwevent_store_setreg);
+
+static struct attribute *hwevent_attrs[] = {
+	&dev_attr_enable.attr,
+	&dev_attr_setreg.attr,
+	NULL,
+};
+
+static struct attribute_group hwevent_attr_grp = {
+	.attrs = hwevent_attrs,
+};
+
+static const struct attribute_group *hwevent_attr_grps[] = {
+	&hwevent_attr_grp,
+	NULL,
+};
+
+static int __devinit hwevent_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct hwevent_drvdata *drvdata;
+	struct coresight_desc *desc;
+	struct coresight_platform_data *pdata;
+	struct resource *res;
+	int ret, i;
+	const char *hmux_name, *hclk_name;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	if (pdev->dev.of_node)
+		drvdata->nr_hmux = of_property_count_strings(pdev->dev.of_node,
+							     "reg-names");
+
+	if (drvdata->nr_hmux > 0) {
+		drvdata->hmux = devm_kzalloc(dev, drvdata->nr_hmux *
+					     sizeof(*drvdata->hmux),
+					     GFP_KERNEL);
+		if (!drvdata->hmux)
+			return -ENOMEM;
+		for (i = 0; i < drvdata->nr_hmux; i++) {
+			ret = of_property_read_string_index(pdev->dev.of_node,
+							    "reg-names", i,
+							    &hmux_name);
+			if (ret)
+				return ret;
+			res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							   hmux_name);
+			if (!res)
+				return -ENODEV;
+			drvdata->hmux[i].start = res->start;
+			drvdata->hmux[i].end = res->end;
+		}
+	} else if (drvdata->nr_hmux < 0) {
+		return drvdata->nr_hmux;
+	} else {
+		/* return error if reg-names in dt node is empty string */
+		return -ENODEV;
+	}
+
+	mutex_init(&drvdata->mutex);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	if (pdev->dev.of_node)
+		drvdata->nr_hclk = of_property_count_strings(pdev->dev.of_node,
+							     "qcom,hwevent-clks");
+	if (drvdata->nr_hclk > 0) {
+		drvdata->hclk = devm_kzalloc(dev, drvdata->nr_hclk *
+					     sizeof(*drvdata->hclk),
+					     GFP_KERNEL);
+		if (!drvdata->hclk)
+			return -ENOMEM;
+		for (i = 0; i < drvdata->nr_hclk; i++) {
+			ret = of_property_read_string_index(pdev->dev.of_node,
+							    "qcom,hwevent-clks",
+							    i, &hclk_name);
+			if (ret)
+				return ret;
+			drvdata->hclk[i] = devm_clk_get(dev, hclk_name);
+			if (IS_ERR(drvdata->hclk[i]))
+				return PTR_ERR(drvdata->hclk[i]);
+		}
+	}
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->type = CORESIGHT_DEV_TYPE_NONE;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = hwevent_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "Hardware Event driver initialized\n");
+	return 0;
+}
+
+static int __devexit hwevent_remove(struct platform_device *pdev)
+{
+	struct hwevent_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id hwevent_match[] = {
+	{.compatible = "qcom,coresight-hwevent"},
+	{}
+};
+
+static struct platform_driver hwevent_driver = {
+	.probe		= hwevent_probe,
+	.remove		= __devexit_p(hwevent_remove),
+	.driver		= {
+		.name	= "coresight-hwevent",
+		.owner	= THIS_MODULE,
+		.of_match_table	= hwevent_match,
+	},
+};
+
+static int __init hwevent_init(void)
+{
+	return platform_driver_register(&hwevent_driver);
+}
+module_init(hwevent_init);
+
+static void __exit hwevent_exit(void)
+{
+	platform_driver_unregister(&hwevent_driver);
+}
+module_exit(hwevent_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Hardware Event driver");
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 258ff09..f208185 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -40,10 +40,13 @@
 extern void msm_qdss_csr_enable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_flush(void);
+extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
 #else
 static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_flush(void) {}
+static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+					   uint32_t val) { return -ENOSYS; }
 #endif
 #ifdef CONFIG_CORESIGHT_ETM
 extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 2210dc8..1be2702 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -379,7 +379,7 @@
 #define CRYPTO_FIRST				17
 #define CRYPTO_LAST				16
 
-#define CRYPTO_AUTH_POS				15 /* bit 15 .. 14*/
+#define CRYPTO_AUTH_POS				14 /* bit 15 .. 14*/
 #define CRYPTO_AUTH_POS_MASK			(0x3 << CRYPTO_AUTH_POS)
 #define CRYPTO_AUTH_POS_BEFORE			0
 #define CRYPTO_AUTH_POS_AFTER			1
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index e6c345b..d95c12b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1719,6 +1719,7 @@
 {
 	int status = -EINVAL;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int state = device->state;
 
 	kgsl_cffdump_open(device);
 
@@ -1780,8 +1781,11 @@
 	kgsl_mmu_stop(&device->mmu);
 
 error_clk_off:
-	if (KGSL_STATE_DUMP_AND_FT != device->state)
+	if (KGSL_STATE_DUMP_AND_FT != device->state) {
 		kgsl_pwrctrl_disable(device);
+		/* set the state back to original state */
+		kgsl_pwrctrl_set_state(device, state);
+	}
 
 	return status;
 }
@@ -2773,9 +2777,6 @@
 	unsigned long wait;
 	unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 
-	if (!(rb->flags & KGSL_FLAGS_STARTED))
-		return 0;
-
 	/*
 	 * The first time into the loop, wait for 100 msecs and kick wptr again
 	 * to ensure that the hardware has updated correctly.  After that, kick
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7cd9943..2b674ab 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -308,16 +308,28 @@
 
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
 {
+	bool had_gpuaddr = false;
+
 	if (entry == NULL)
 		return;
 
+	/*
+	 * Unmap the entry first so that there isn't a period of
+	 * time where kgsl doesn't know about the address range
+	 * but it is still present in the pagetable. Unmapping will
+	 * clear the gpuaddr field, so remember if we had a mapping,
+	 * and an rbtree entry for later.
+	 */
+	had_gpuaddr = entry->memdesc.gpuaddr != 0;
+	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
+
 	spin_lock(&entry->priv->mem_lock);
 
 	if (entry->id != 0)
 		idr_remove(&entry->priv->mem_idr, entry->id);
 	entry->id = 0;
 
-	if (entry->memdesc.gpuaddr != 0)
+	if (had_gpuaddr)
 		rb_erase(&entry->node, &entry->priv->mem_rb);
 
 	spin_unlock(&entry->priv->mem_lock);
@@ -325,7 +337,6 @@
 	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
 	entry->priv = NULL;
 
-	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
 
 	kgsl_mem_entry_put(entry);
 }
@@ -1346,6 +1357,12 @@
 				"invalid gpuaddr %08x\n", gpuaddr);
 		return -EINVAL;
 	}
+	if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+	entry->memdesc.priv |= KGSL_MEMDESC_FREE_PENDING;
+
 	trace_kgsl_mem_timestamp_queue(device, entry, context_id,
 				       kgsl_readtimestamp(device, context,
 						  KGSL_TIMESTAMP_RETIRED),
@@ -1445,6 +1462,11 @@
 		return -EINVAL;
 	}
 
+	if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+
 	trace_kgsl_mem_free(entry);
 
 	kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1470,6 +1492,12 @@
 		KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id);
 		return -EINVAL;
 	}
+
+	if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+
 	trace_kgsl_mem_free(entry);
 
 	kgsl_memfree_hist_set_event(entry->priv->pid,
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index abe9100..debba18 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -151,6 +151,8 @@
 #define KGSL_MEMDESC_GLOBAL BIT(1)
 /* The memdesc is frozen during a snapshot */
 #define KGSL_MEMDESC_FROZEN BIT(2)
+/* The memdesc is scheduled to be freed on a timestamp */
+#define KGSL_MEMDESC_FREE_PENDING BIT(3)
 
 /* shared memory allocation */
 struct kgsl_memdesc {
@@ -251,6 +253,10 @@
 static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
 				unsigned int gpuaddr, unsigned int size)
 {
+	/* set a minimum size to search for */
+	if (!size)
+		size = 1;
+
 	/* don't overflow */
 	if ((gpuaddr + size) < gpuaddr)
 		return 0;
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index ef2a19a..c3bdf80 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -360,6 +360,8 @@
 void kgsl_cffdump_open(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	if (!kgsl_cff_dump_enable)
+		return;
 
 	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
 		kgsl_cffdump_memory_base(device->id,
@@ -379,24 +381,33 @@
 void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
 			      unsigned int range, unsigned gmemsize)
 {
+	if (!kgsl_cff_dump_enable)
+		return;
 	cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base,
 			range, gmemsize, 0, 0);
 }
 
 void kgsl_cffdump_hang(enum kgsl_deviceid device_id)
 {
+	if (!kgsl_cff_dump_enable)
+		return;
 	cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0);
 }
 
 void kgsl_cffdump_close(enum kgsl_deviceid device_id)
 {
+	if (!kgsl_cff_dump_enable)
+		return;
 	cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0);
 }
 
+
 void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
 		unsigned int op2, unsigned int op3,
 		unsigned int op4, unsigned int op5)
 {
+	if (!kgsl_cff_dump_enable)
+		return;
 	cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
 }
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 4165690..f09c623 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -347,6 +347,9 @@
 	int offset;
 	int ret = -EINVAL;
 
+	if (!gpuaddr)
+		return 0;
+
 	entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
 
 	if (entry == NULL) {
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
index fcda6c9..21e4829 100644
--- a/drivers/input/touchscreen/gen_vkeys.c
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -105,6 +105,12 @@
 			return -EINVAL;
 		}
 	}
+
+	rc = of_property_read_u32(np, "qcom,y-offset", &pdata->y_offset);
+	if (rc) {
+		dev_err(dev, "Failed to read y position offset\n");
+		return -EINVAL;
+	}
 	return 0;
 }
 
@@ -147,7 +153,7 @@
 	width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1)))
 			/ pdata->num_keys);
 	height = (pdata->panel_maxy - pdata->disp_maxy);
-	center_y = pdata->disp_maxy + (height / 2);
+	center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset;
 	height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
 
 	x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index dbe378c..d51481f 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -107,6 +107,9 @@
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count);
 
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
 static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count);
 
@@ -301,6 +304,9 @@
 };
 
 static struct device_attribute attrs[] = {
+	__ATTR(forceflash, S_IWUGO,
+			synaptics_rmi4_show_error,
+			fwu_sysfs_force_reflash_store),
 	__ATTR(doreflash, S_IWUGO,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_do_reflash_store),
@@ -1462,6 +1468,40 @@
 	return count;
 }
 
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int retval;
+	unsigned int input;
+	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+	if (sscanf(buf, "%u", &input) != 1) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if (input != 1) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	fwu->force_update = true;
+	retval = synaptics_fw_updater(fwu->ext_data_source);
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to do reflash\n",
+				__func__);
+		goto exit;
+	}
+
+	retval = count;
+
+exit:
+	kfree(fwu->ext_data_source);
+	fwu->ext_data_source = NULL;
+	return retval;
+}
+
 static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 426c7e7..ed53c41 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -107,13 +107,17 @@
 static int synaptics_rmi4_suspend(struct device *dev);
 
 static int synaptics_rmi4_resume(struct device *dev);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+
 static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
 		struct device_attribute *attr, char *buf);
 
 static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count);
 
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 static void synaptics_rmi4_early_suspend(struct early_suspend *h);
 
 static void synaptics_rmi4_late_resume(struct early_suspend *h);
@@ -229,7 +233,7 @@
 };
 
 static struct device_attribute attrs[] = {
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
 	__ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
 			synaptics_rmi4_full_pm_cycle_show,
 			synaptics_rmi4_full_pm_cycle_store),
@@ -260,8 +264,7 @@
 static bool exp_fn_inited;
 static struct mutex exp_fn_list_mutex;
 static struct list_head exp_fn_list;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
 static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -284,6 +287,36 @@
 
 	return count;
 }
+
+#ifdef CONFIG_FB
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+	int retval = 0;
+
+	rmi4_data->fb_notif.notifier_call = fb_notifier_callback;
+
+	retval = fb_register_client(&rmi4_data->fb_notif);
+	if (retval)
+		dev_err(&rmi4_data->i2c_client->dev,
+			"Unable to register fb_notifier: %d\n", retval);
+	return;
+}
+#elif defined CONFIG_HAS_EARLYSUSPEND
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+	rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
+	rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
+	register_early_suspend(&rmi4_data->early_suspend);
+
+	return;
+}
+#else
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+	return;
+}
+#endif
 #endif
 
 static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -2203,12 +2236,7 @@
 		goto err_register_input;
 	}
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
-	rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
-	rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
-	register_early_suspend(&rmi4_data->early_suspend);
-#endif
+	configure_sleep(rmi4_data);
 
 	if (!exp_fn_inited) {
 		mutex_init(&exp_fn_list_mutex);
@@ -2446,7 +2474,27 @@
 	return;
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct synaptics_rmi4_data *rmi4_data =
+		container_of(self, struct synaptics_rmi4_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+		rmi4_data && rmi4_data->i2c_client) {
+		blank = evdata->data;
+		if (*blank == FB_BLANK_UNBLANK)
+			synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+		else if (*blank == FB_BLANK_POWERDOWN)
+			synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+	}
+
+	return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
  /**
  * synaptics_rmi4_early_suspend()
  *
@@ -2629,10 +2677,15 @@
 	return 0;
 }
 
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
 static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
 	.suspend = synaptics_rmi4_suspend,
 	.resume  = synaptics_rmi4_resume,
 };
+#else
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+};
+#endif
 #endif
 
 static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 681822a..681b95c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -27,7 +27,11 @@
 #define SYNAPTICS_DSX_DRIVER_VERSION 0x1005
 
 #include <linux/version.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
+
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
 #endif
 
@@ -227,6 +231,13 @@
 			unsigned char *data, unsigned short length);
 	int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
 	int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+#ifdef CONFIG_FB
+	struct notifier_block fb_notif;
+#else
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+#endif
 };
 
 enum exp_fn {
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index b1960c6..b92ec7f 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -148,12 +148,26 @@
 		if (ret)
 			clk_disable_unprepare(drvdata->pclk);
 	}
+
+	if (ret)
+		goto fail;
+
+	if (drvdata->aclk) {
+		ret = clk_prepare_enable(drvdata->aclk);
+		if (ret) {
+			clk_disable_unprepare(drvdata->clk);
+			clk_disable_unprepare(drvdata->pclk);
+		}
+	}
+
 fail:
 	return ret;
 }
 
 static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
 {
+	if (drvdata->aclk)
+		clk_disable_unprepare(drvdata->aclk);
 	if (drvdata->clk)
 		clk_disable_unprepare(drvdata->clk);
 	clk_disable_unprepare(drvdata->pclk);
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 7ae0b21..059216e 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -129,7 +129,8 @@
 }
 
 static int msm_iommu_parse_dt(struct platform_device *pdev,
-				struct msm_iommu_drvdata *drvdata)
+				struct msm_iommu_drvdata *drvdata,
+				int *needs_alt_core_clk)
 {
 #ifdef CONFIG_OF_DEVICE
 	struct device_node *child;
@@ -169,6 +170,10 @@
 		pr_err("%s: Missing property label\n", __func__);
 		return -EINVAL;
 	}
+
+	*needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
+						   "qcom,needs-alt-core-clk");
+
 	drvdata->sec_id = -1;
 	drvdata->ttbr_split = 0;
 #endif
@@ -176,7 +181,8 @@
 }
 
 static int __get_clocks(struct platform_device *pdev,
-				 struct msm_iommu_drvdata *drvdata)
+			struct msm_iommu_drvdata *drvdata,
+			int needs_alt_core_clk)
 {
 	int ret = 0;
 
@@ -199,6 +205,18 @@
 	} else {
 		drvdata->clk = NULL;
 	}
+
+	if (needs_alt_core_clk) {
+		drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
+		if (IS_ERR(drvdata->aclk))
+			return PTR_ERR(drvdata->aclk);
+	}
+
+	if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
+		ret = clk_round_rate(drvdata->aclk, 1000);
+		clk_set_rate(drvdata->aclk, ret);
+	}
+
 	return 0;
 fail:
 	return ret;
@@ -206,35 +224,13 @@
 
 static void __put_clocks(struct msm_iommu_drvdata *drvdata)
 {
+	if (drvdata->aclk)
+		clk_put(drvdata->aclk);
 	if (drvdata->clk)
 		clk_put(drvdata->clk);
 	clk_put(drvdata->pclk);
 }
 
-static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
-{
-	int ret;
-
-	ret = clk_prepare_enable(drvdata->pclk);
-	if (ret)
-		goto fail;
-
-	if (drvdata->clk) {
-		ret = clk_prepare_enable(drvdata->clk);
-		if (ret)
-			clk_disable_unprepare(drvdata->pclk);
-	}
-fail:
-	return ret;
-}
-
-static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
-{
-	if (drvdata->clk)
-		clk_disable_unprepare(drvdata->clk);
-	clk_disable_unprepare(drvdata->pclk);
-}
-
 /*
  * Do a basic check of the IOMMU by performing an ATS operation
  * on context bank 0.
@@ -326,6 +322,7 @@
 	struct msm_iommu_drvdata *drvdata;
 	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
 	int ret;
+	int needs_alt_core_clk = 0;
 
 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 
@@ -335,7 +332,7 @@
 	}
 
 	if (pdev->dev.of_node) {
-		ret = msm_iommu_parse_dt(pdev, drvdata);
+		ret = msm_iommu_parse_dt(pdev, drvdata, &needs_alt_core_clk);
 		if (ret)
 			goto fail;
 	} else if (pdev->dev.platform_data) {
@@ -382,12 +379,12 @@
 
 	drvdata->dev = &pdev->dev;
 
-	ret = __get_clocks(pdev, drvdata);
+	ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
 
 	if (ret)
 		goto fail;
 
-	__enable_clocks(drvdata);
+	iommu_access_ops_v0.iommu_clk_on(drvdata);
 
 	msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
 
@@ -401,7 +398,7 @@
 	msm_iommu_add_drv(drvdata);
 	platform_set_drvdata(pdev, drvdata);
 
-	__disable_clocks(drvdata);
+	iommu_access_ops_v0.iommu_clk_off(drvdata);
 
 	pmon_info = msm_iommu_pm_alloc(&pdev->dev);
 	if (pmon_info != NULL) {
@@ -430,7 +427,7 @@
 	return 0;
 
 fail_clk:
-	__disable_clocks(drvdata);
+	iommu_access_ops_v0.iommu_clk_off(drvdata);
 	__put_clocks(drvdata);
 fail:
 	return ret;
@@ -618,9 +615,9 @@
 		goto fail;
 	}
 
-	__enable_clocks(drvdata);
+	iommu_access_ops_v0.iommu_clk_on(drvdata);
 	__program_m2v_tables(drvdata, ctx_drvdata);
-	__disable_clocks(drvdata);
+	iommu_access_ops_v0.iommu_clk_off(drvdata);
 
 	dev_info(&pdev->dev, "context %s using bank %d\n", ctx_drvdata->name,
 							   ctx_drvdata->num);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 5d5ff43..0233e18 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -93,6 +93,7 @@
 #define FLASH_LED_STROBE_CTRL(base)	(base + 0x47)
 #define FLASH_LED_UNLOCK_SECURE(base)	(base + 0xD0)
 #define FLASH_LED_TORCH(base)		(base + 0xE4)
+#define FLASH_FAULT_DETECT(base)	(base + 0x51)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define	FLASH_NO_MASK			0x00
@@ -106,10 +107,9 @@
 #define FLASH_TMR_MASK			0x03
 #define FLASH_TMR_WATCHDOG		0x03
 #define FLASH_TMR_SAFETY		0x00
-
+#define FLASH_FAULT_DETECT_MASK		0X80
 #define FLASH_HW_VREG_OK		0x80
 #define FLASH_VREG_MASK			0xC0
-
 #define FLASH_STARTUP_DLY_MASK		0x02
 
 #define FLASH_ENABLE_ALL		0xE0
@@ -120,6 +120,7 @@
 #define FLASH_ENABLE_LED_0		0x40
 #define FLASH_ENABLE_LED_1		0x20
 #define FLASH_INIT_MASK			0xE0
+#define	FLASH_SELFCHECK_ENABLE		0x80
 
 #define FLASH_STROBE_SW			0xC0
 #define FLASH_STROBE_HW			0xC4
@@ -130,7 +131,7 @@
 #define FLASH_CURRENT_PRGM_MIN		1
 #define FLASH_CURRENT_PRGM_SHIFT	1
 #define FLASH_CURRENT_MAX		0x4F
-#define FLASH_CURRENT_TORCH		0x0F
+#define FLASH_CURRENT_TORCH		0x07
 
 #define FLASH_DURATION_200ms		0x13
 #define FLASH_CLAMP_200mA		0x0F
@@ -171,6 +172,8 @@
 #define LED_MPP_SINK_MASK		0x07
 #define LED_MPP_MODE_MASK		0x7F
 #define LED_MPP_EN_MASK			0x80
+#define LED_MPP_SRC_MASK		0x0F
+#define LED_MPP_MODE_CTRL_MASK		0x70
 
 #define LED_MPP_MODE_SINK		(0x06 << 4)
 #define LED_MPP_MODE_ENABLE		0x01
@@ -551,7 +554,8 @@
 			return rc;
 		}
 
-		val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
+		val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
+			(led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
 
 		rc = qpnp_led_masked_write(led,
 		LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
@@ -632,18 +636,10 @@
 				return rc;
 			}
 
-			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
-				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"Max current reg write failed(%d)\n",
-					rc);
-				return rc;
-			}
-
 			rc = qpnp_led_masked_write(led,
 				led->flash_cfg->current_addr,
-				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
@@ -652,7 +648,8 @@
 
 			rc = qpnp_led_masked_write(led,
 				led->flash_cfg->second_addr,
-				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"2nd Current reg write failed(%d)\n",
@@ -660,6 +657,16 @@
 				return rc;
 			}
 
+			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+				FLASH_CURRENT_MASK,
+				led->max_current);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Max current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
 				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
@@ -669,9 +676,22 @@
 				return rc;
 			}
 		} else {
+			/* Set flash safety timer */
 			rc = qpnp_led_masked_write(led,
-				FLASH_MAX_CURR(led->base),
-				FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+				FLASH_SAFETY_TIMER(led->base),
+				FLASH_SAFETY_TIMER_MASK,
+				led->flash_cfg->duration);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Safety timer reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			/* Set max current */
+			rc = qpnp_led_masked_write(led,
+				FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK,
+				FLASH_MAX_LEVEL);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
@@ -679,6 +699,18 @@
 				return rc;
 			}
 
+			/* Set clamp current */
+			rc = qpnp_led_masked_write(led,
+				FLASH_CLAMP_CURR(led->base),
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->clamp_curr);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Clamp current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
 			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
 			 * in order to avoid reg value goes from 0x00 to
 			 * 0xE0. This causes a hardware bug.
@@ -714,16 +746,6 @@
 			}
 
 			rc = qpnp_led_masked_write(led,
-				FLASH_CLAMP_CURR(led->base),
-				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"Clamp Current reg write failed(%d)\n",
-					rc);
-				return rc;
-			}
-
-			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
 				FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
 			if (rc) {
@@ -762,25 +784,16 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-			}
-
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_TORCH(led->base),
-				FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"Torch reg write failed(%d)\n", rc);
 				return rc;
 			}
 
 			rc = qpnp_led_masked_write(led,
-				FLASH_SAFETY_TIMER(led->base),
-				FLASH_SAFETY_TIMER_MASK,
-				led->flash_cfg->duration);
+					FLASH_LED_TORCH(led->base),
+					FLASH_TORCH_MASK,
+					FLASH_LED_TORCH_DISABLE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
-					"Safety timer reg write failed(%d)\n",
-					rc);
+					"Torch reg write failed(%d)\n", rc);
 				return rc;
 			}
 		}
@@ -936,6 +949,7 @@
 		if (rc < 0)
 			dev_err(&led->spmi_dev->dev,
 					"MPP set brightness failed (%d)\n", rc);
+		break;
 	case QPNP_ID_KPDBL:
 		rc = qpnp_kpdbl_set(led);
 		if (rc < 0)
@@ -1208,52 +1222,7 @@
 			"LED %d flash write failed(%d)\n", led->id, rc);
 		return rc;
 	}
-	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-		FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Enable reg write failed(%d)\n", rc);
-		return rc;
-	}
 
-	/* Set flash safety timer */
-	rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
-		FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Safety timer reg write failed(%d)\n", rc);
-		return rc;
-	}
-
-	/* Set max current */
-	rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
-		FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Max current reg write failed(%d)\n", rc);
-		return rc;
-	}
-	/* Set clamp current */
-	rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
-		FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Clamp current reg write failed(%d)\n", rc);
-		return rc;
-	}
-
-	/* Set timer control - safety or watchdog */
-	if (led->flash_cfg->safety_timer)
-		rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
-			FLASH_TMR_MASK, FLASH_TMR_SAFETY);
-	else
-		rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
-			FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"LED timer ctrl reg write failed(%d)\n", rc);
-		return rc;
-	}
 	/* Set headroom */
 	rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
 		FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -1263,6 +1232,47 @@
 		return rc;
 	}
 
+	/* Set startup delay */
+	rc = qpnp_led_masked_write(led,
+		FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK,
+		led->flash_cfg->startup_dly);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Startup delay reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set timer control - safety or watchdog */
+	if (led->flash_cfg->safety_timer) {
+		rc = qpnp_led_masked_write(led,
+			FLASH_LED_TMR_CTRL(led->base),
+			FLASH_TMR_MASK, FLASH_TMR_SAFETY);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"LED timer ctrl reg write failed(%d)\n",
+				rc);
+			return rc;
+		}
+	}
+
+	/* Set Vreg force */
+	rc = qpnp_led_masked_write(led,	FLASH_VREG_OK_FORCE(led->base),
+		FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Vreg OK reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set self fault check */
+	rc = qpnp_led_masked_write(led, FLASH_FAULT_DETECT(led->base),
+		FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_ENABLE);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Fault detect reg write failed(%d)\n", rc);
+		return rc;
+	}
+
 	/* Set mask enable */
 	rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
 		FLASH_MASK_REG_MASK, FLASH_MASK_1);
@@ -1272,32 +1282,7 @@
 		return rc;
 	}
 
-	/* Set startup delay */
-	rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
-		FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Startup delay reg write failed(%d)\n", rc);
-		return rc;
-	}
-
-	rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
-		FLASH_VREG_MASK, FLASH_HW_VREG_OK);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Vreg OK reg write failed(%d)\n", rc);
-		return rc;
-	}
-
-	/* Set led current and disable module */
-	rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
-		FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Current reg write failed(%d)\n", rc);
-		return rc;
-	}
-
+	/* Disable flash LED module */
 	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
 		FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
 	if (rc) {
@@ -1306,7 +1291,6 @@
 		return rc;
 	}
 
-	led->flash_cfg->torch_enable = false;
 	led->flash_cfg->strobe_type = 0;
 
 	/* dump flash registers */
@@ -1679,6 +1663,9 @@
 	led->flash_cfg->safety_timer =
 		of_property_read_bool(node, "qcom,safety-timer");
 
+	led->flash_cfg->torch_enable =
+		of_property_read_bool(node, "qcom,torch-enable");
+
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 7347b37..2a750a6 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1796,19 +1796,10 @@
 	return 0;
 }
 
-static void dvb_dmxdev_ts_insertion_timer(unsigned long data)
-{
-	struct ts_insertion_buffer *ts_buffer =
-		(struct ts_insertion_buffer *)data;
-
-	if (ts_buffer && !ts_buffer->abort)
-		schedule_work(&ts_buffer->work);
-}
-
 static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
 {
 	struct ts_insertion_buffer *ts_buffer =
-		container_of(worker, struct ts_insertion_buffer, work);
+		container_of(worker, struct ts_insertion_buffer, dwork.work);
 	struct dmxdev_feed *feed;
 	size_t free_bytes;
 	struct dmx_ts_feed *ts;
@@ -1832,8 +1823,8 @@
 		ts->ts_insertion_insert_buffer(ts,
 			ts_buffer->buffer, ts_buffer->size);
 
-	if (ts_buffer->repetition_time)
-		mod_timer(&ts_buffer->timer, jiffies +
+	if (ts_buffer->repetition_time && !ts_buffer->abort)
+		schedule_delayed_work(&ts_buffer->dwork,
 				msecs_to_jiffies(ts_buffer->repetition_time));
 }
 
@@ -1854,7 +1845,7 @@
 	}
 
 	ts_buffer->abort = 0;
-	schedule_work(&ts_buffer->work);
+	schedule_delayed_work(&ts_buffer->dwork, 0);
 }
 
 static void dvb_dmxdev_cancel_ts_insertion(
@@ -1873,16 +1864,10 @@
 		return;
 	}
 
-	/*
-	 * Work should be stopped first as it might re-trigger the timer
-	 * until it is stopped. Timer would not re-schedule the work
-	 * due to the abort flag.
-	 */
 	ts_buffer->abort = 1;
 
 	mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
-	cancel_work_sync(&ts_buffer->work);
-	del_timer_sync(&ts_buffer->timer);
+	cancel_delayed_work_sync(&ts_buffer->dwork);
 	mutex_lock(&ts_buffer->dmxdevfilter->mutex);
 }
 
@@ -1928,11 +1913,7 @@
 	ts_buffer->identifier = params->identifier;
 	ts_buffer->repetition_time = params->repetition_time;
 	ts_buffer->dmxdevfilter = dmxdevfilter;
-	init_timer(&ts_buffer->timer);
-	ts_buffer->timer.function = dvb_dmxdev_ts_insertion_timer;
-	ts_buffer->timer.data = (unsigned long)ts_buffer;
-	ts_buffer->timer.expires = 0xffffffffL;
-	INIT_WORK(&ts_buffer->work, dvb_dmxdev_ts_insertion_work);
+	INIT_DELAYED_WORK(&ts_buffer->dwork, dvb_dmxdev_ts_insertion_work);
 
 	first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
 	list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index d8cd982..49e5e1b 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -117,7 +117,7 @@
 #define DMX_MIN_INSERTION_REPETITION_TIME	25 /* in msec */
 struct ts_insertion_buffer {
 	/* work scheduled for insertion of this buffer */
-	struct work_struct work;
+	struct delayed_work dwork;
 
 	struct list_head next;
 
@@ -133,9 +133,6 @@
 	/* repetition time for the buffer insertion */
 	u32 repetition_time;
 
-	/* timer used for insertion of the buffer */
-	struct timer_list timer;
-
 	/* the recording filter to which this buffer belongs */
 	struct dmxdev_filter *dmxdevfilter;
 
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 731056b..756cb41 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -520,26 +520,37 @@
 	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
 	comp_mask |= (axi_data->composite_info[comp_mask_index].
-	stream_composite_mask << (comp_mask_index * 8));
+		stream_composite_mask << (comp_mask_index * 8));
+	if (stream_info->plane_offset[0])
+		comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask |= 1 << (comp_mask_index + 25);
+	if (stream_info->plane_offset[0] && (comp_mask >> 24))
+		irq_mask |= BIT(28);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
 static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
 	struct msm_vfe_axi_stream *stream_info)
 {
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index;
 	uint32_t irq_mask;
 
 	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	if (stream_info->plane_offset[0])
+		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask &= ~(1 << (comp_mask_index + 25));
+	if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+		irq_mask &= ~BIT(28);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
@@ -1219,7 +1230,7 @@
 
 static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
 	.num_wm = 4,
-	.num_comp_mask = 4,
+	.num_comp_mask = 3,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
 	.min_wm_ub = 64,
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 613ad86..dd8db03 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
@@ -230,12 +230,12 @@
 	return rc;
 }
 
-static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, uint32_t rate)
+static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
 {
 	int rc = 0;
 	int clk_idx = vfe_dev->hw_info->vfe_clk_idx;
 	long round_rate =
-		clk_round_rate(vfe_dev->vfe_clk[clk_idx], rate);
+		clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
 	if (round_rate < 0) {
 		pr_err("%s: Invalid vfe clock rate\n", __func__);
 		return round_rate;
@@ -246,6 +246,7 @@
 		pr_err("%s: Vfe set rate error\n", __func__);
 		return rc;
 	}
+	*rate = round_rate;
 	return 0;
 }
 
@@ -266,7 +267,7 @@
 		input_cfg->d.pix_cfg.camif_cfg.pixels_per_line;
 
 	rc = msm_isp_set_clk_rate(vfe_dev,
-		vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
+		&vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
 	if (rc < 0) {
 		pr_err("%s: clock set rate failed\n", __func__);
 		return rc;
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 47e672d..3dd3a4e 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
@@ -42,13 +42,13 @@
 			e_ctrl->eboard_info->eeprom_name,
 			sizeof(cdata->cfg.eeprom_name));
 		break;
-	case CFG_EEPROM_GET_DATA:
-		CDBG("%s E CFG_EEPROM_GET_DATA\n", __func__);
+	case CFG_EEPROM_GET_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
 		cdata->cfg.get_data.num_bytes =
 			e_ctrl->num_bytes;
 		break;
-	case CFG_EEPROM_READ_DATA:
-		CDBG("%s E CFG_EEPROM_READ_DATA\n", __func__);
+	case CFG_EEPROM_READ_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
 		rc = copy_to_user(cdata->cfg.read_data.dbuffer,
 			e_ctrl->memory_data,
 			cdata->cfg.read_data.num_bytes);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 7fc8810..82a4f3c 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -316,6 +316,9 @@
 	case HAL_EXTRADATA_ASPECT_RATIO:
 		ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA;
 		break;
+	case HAL_EXTRADATA_MPEG2_SEQDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
 		break;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 43a3dad..19f5dcd 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1018,6 +1018,41 @@
 	callback(SESSION_END_DONE, &cmd_done);
 }
 
+static void hfi_process_session_abort_done(
+	msm_vidc_callback callback, u32 device_id,
+	struct hfi_msg_sys_session_abort_done_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	struct hal_session *sess_close;
+
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_ABORT_DONE");
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size: %d",
+				__func__, pkt ? pkt->size : 0);
+		return;
+	}
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	cmd_done.device_id = device_id;
+	cmd_done.session_id =
+		((struct hal_session *) pkt->session_id)->session_id;
+	cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
+	cmd_done.data = NULL;
+	cmd_done.size = 0;
+
+	sess_close = (struct hal_session *)pkt->session_id;
+	if (!sess_close) {
+		dprintk(VIDC_ERR, "%s: invalid session pointer\n", __func__);
+		return;
+	}
+	dprintk(VIDC_ERR, "deleted the session: 0x%x",
+		sess_close->session_id);
+	list_del(&sess_close->list);
+	kfree(sess_close);
+	callback(SESSION_ABORT_DONE, &cmd_done);
+}
+
 static void hfi_process_session_get_seq_hdr_done(
 	msm_vidc_callback callback, u32 device_id,
 	struct hfi_msg_session_get_sequence_header_done_packet *pkt)
@@ -1134,6 +1169,10 @@
 			hfi_msg_session_release_buffers_done_packet*)
 			msg_hdr);
 		break;
+	case HFI_MSG_SYS_SESSION_ABORT_DONE:
+		hfi_process_session_abort_done(callback, device_id, (struct
+			hfi_msg_sys_session_abort_done_packet*) msg_hdr);
+		break;
 	default:
 		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 1611a09..511a478 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -66,6 +66,7 @@
 	"Extradata input crop",
 	"Extradata digital zoom",
 	"Extradata aspect ratio",
+	"Extradata mpeg2 seqdisp",
 };
 
 static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
@@ -203,7 +204,7 @@
 		.name = "Extradata Type",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
-		.maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP,
 		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -223,7 +224,8 @@
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
-			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP)
 			),
 		.qmenu = mpeg_video_vidc_extradata,
 		.step = 0,
@@ -697,32 +699,43 @@
 }
 int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
 {
-	u32 us_per_frame = 0;
-	int rc = 0;
+	u64 us_per_frame = 0;
+	int rc = 0, fps = 0, rem = 0;
 	if (a->parm.output.timeperframe.denominator) {
 		switch (a->type) {
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-			us_per_frame = a->parm.output.timeperframe.numerator/
-				a->parm.output.timeperframe.denominator;
-			break;
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-			us_per_frame = a->parm.capture.timeperframe.numerator/
-				a->parm.capture.timeperframe.denominator;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			us_per_frame = a->parm.output.timeperframe.numerator *
+				(u64)USEC_PER_SEC;
+			do_div(us_per_frame, a->parm.output.\
+					timeperframe.denominator);
 			break;
 		default:
 			dprintk(VIDC_ERR,
-				"Scale clocks : Unknown buffer type\n");
+					"Scale clocks : Unknown buffer type %d\n",
+					a->type);
 			break;
 		}
 	}
+
 	if (!us_per_frame) {
 		dprintk(VIDC_ERR,
-				"Failed to scale clocks : time between frames is 0\n");
+			"Failed to scale clocks : time between frames is 0\n");
 		rc = -EINVAL;
 		goto exit;
 	}
-	inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
-	if (inst->prop.fps) {
+
+	fps = USEC_PER_SEC;
+	rem = do_div(fps, us_per_frame);
+	if (rem) {
+		/* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+		fps++;
+	}
+
+	if (inst->prop.fps != fps) {
+		dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+				inst, inst->prop.fps, fps);
+		inst->prop.fps = fps;
 		msm_comm_scale_clocks_and_bus(inst);
 	}
 exit:
@@ -1121,11 +1134,24 @@
 	int rc = 0;
 	struct v4l2_event dqevent = {0};
 	struct msm_vidc_core *core = inst->core;
+
+	if (!dec || !inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s invalid params", __func__);
+		return -EINVAL;
+	}
 	switch (dec->cmd) {
 	case V4L2_DEC_QCOM_CMD_FLUSH:
 		rc = msm_comm_flush(inst, dec->flags);
 		break;
 	case V4L2_DEC_CMD_STOP:
+		if (core->state != VIDC_CORE_INVALID &&
+			inst->state ==  MSM_VIDC_CORE_INVALID) {
+			rc = msm_comm_recover_from_session_error(inst);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed to recover from session_error: %d\n",
+					rc);
+		}
 		rc = msm_comm_release_scratch_buffers(inst);
 		if (rc)
 			dprintk(VIDC_ERR,
@@ -1191,7 +1217,6 @@
 	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
 	inst->capability.width.max = DEFAULT_WIDTH;
 	inst->prop.fps = 30;
-	inst->prop.prev_time_stamp = 0;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 66a3b6e..b6e77dc 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1970,7 +1970,7 @@
 {
 	u32 property_id = 0, us_per_frame = 0;
 	void *pdata;
-	int rc = 0;
+	int rc = 0, fps = 0, rem = 0;
 	struct hal_frame_rate frame_rate;
 	struct hfi_device *hdev;
 
@@ -1978,32 +1978,45 @@
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
-	hdev = inst->core->device;
 
+	hdev = inst->core->device;
 	property_id = HAL_CONFIG_FRAME_RATE;
+
 	if (a->parm.output.timeperframe.denominator) {
 		switch (a->type) {
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 			us_per_frame = a->parm.output.timeperframe.numerator *
-				USEC_PER_SEC / a->parm.output.\
-				timeperframe.denominator;
+				(u64)USEC_PER_SEC;
+			do_div(us_per_frame, a->parm.output.\
+					timeperframe.denominator);
 			break;
 		default:
 			dprintk(VIDC_ERR,
-				"Scale clocks : Unknown buffer type\n");
+					"Scale clocks : Unknown buffer type %d\n",
+					a->type);
 			break;
 		}
 	}
 
 	if (!us_per_frame) {
 		dprintk(VIDC_ERR,
-			"Failed to scale clocks : time between frames is 0\n");
+				"Failed to scale clocks : time between frames is 0\n");
 		rc = -EINVAL;
 		goto exit;
 	}
-	inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
-	if (inst->prop.fps) {
+
+	fps = USEC_PER_SEC;
+	rem = do_div(fps, us_per_frame);
+	if (rem) {
+		/* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+		fps++;
+	}
+
+	if (inst->prop.fps != fps) {
+		dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+				inst, inst->prop.fps, fps);
+		inst->prop.fps = fps;
 		frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
 		frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
 		pdata = &frame_rate;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index eb5a03c..39d73ca 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -47,8 +47,6 @@
 	__mbs;\
 })
 
-#define TIME_DIFF_THRESHOLD 200
-
 static int msm_comm_get_load(struct msm_vidc_core *core,
 	enum session_type type)
 {
@@ -638,56 +636,6 @@
 	}
 }
 
-static void msm_comm_update_clocks(struct msm_vidc_inst *inst,
-	u64 cur_time_stamp)
-{
-	u32 new_time_diff = 0, cur_time_diff = 0;
-	u8 updated_fps = 0;
-	struct v4l2_ctrl *ctrl = NULL;
-	u32 output_order = 0;
-
-	if (inst->session_type == MSM_VIDC_ENCODER)
-		goto exit;
-	if (cur_time_stamp >= LLONG_MAX) {
-		dprintk(VIDC_DBG,
-			"Clock scaling failed : Timestamp invalid\n");
-		goto exit;
-	}
-	ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
-		V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER);
-	if (!ctrl) {
-		dprintk(VIDC_WARN, "Unable to find output order control\n");
-		dprintk(VIDC_WARN,
-			"Performance might be impacted for higher fps clips\n");
-		goto exit;
-	}
-	output_order = v4l2_ctrl_g_ctrl(ctrl);
-	if (output_order == V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) {
-		new_time_diff =
-			(u32)(cur_time_stamp - inst->prop.prev_time_stamp);
-		inst->prop.prev_time_stamp = cur_time_stamp;
-		if (!new_time_diff)
-			goto exit;
-		if (inst->prop.fps)
-			cur_time_diff = USEC_PER_SEC / inst->prop.fps;
-		cur_time_diff = cur_time_diff > new_time_diff ?
-			cur_time_diff - new_time_diff :
-			new_time_diff - cur_time_diff;
-		if (cur_time_diff > TIME_DIFF_THRESHOLD) {
-			updated_fps = (u8) (USEC_PER_SEC / new_time_diff);
-			if (updated_fps && (updated_fps != inst->prop.fps)) {
-				inst->prop.fps = updated_fps;
-				dprintk(VIDC_DBG,
-						"Updating clocks: Decoding fps = %d\n",
-						inst->prop.fps);
-				msm_comm_scale_clocks_and_bus(inst);
-			}
-		}
-	}
-exit:
-	return;
-}
-
 static void handle_fbd(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
@@ -717,7 +665,6 @@
 				fill_buf_done->timestamp_lo;
 			vb->v4l2_buf.timestamp =
 				ns_to_timeval(time_usec * NSEC_PER_USEC);
-				msm_comm_update_clocks(inst, time_usec);
 		}
 		vb->v4l2_buf.flags = 0;
 
@@ -726,13 +673,17 @@
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
 			vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
-			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+			break;
 		case HAL_PICTURE_I:
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
 			break;
@@ -861,6 +812,7 @@
 		handle_release_res_done(cmd, data);
 		break;
 	case SESSION_END_DONE:
+	case SESSION_ABORT_DONE:
 		handle_session_close(cmd, data);
 		break;
 	case VIDC_EVENT_CHANGE:
@@ -2262,7 +2214,10 @@
 				kfree(temp);
 			}
 		}
-		rc = call_hfi_op(hdev, session_flush, inst->session,
+		/*Do not send flush in case of session_error */
+		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+			  core->state != VIDC_CORE_INVALID))
+			rc = call_hfi_op(hdev, session_flush, inst->session,
 				HAL_FLUSH_ALL);
 	}
 	mutex_unlock(&inst->sync_lock);
@@ -2323,6 +2278,9 @@
 	case V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO:
 		ret = HAL_EXTRADATA_ASPECT_RATIO;
 		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
+		ret = HAL_EXTRADATA_MPEG2_SEQDISP;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
 		break;
@@ -2432,3 +2390,33 @@
 	}
 	return rc;
 }
+
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
+{
+	struct hfi_device *hdev;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	init_completion(&inst->completions[SESSION_MSG_INDEX
+		(SESSION_ABORT_DONE)]);
+
+	/* We have received session_error. Send session_abort to firmware
+	 *  to clean up and release the session
+	 */
+	rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
+		return rc;
+	}
+
+	rc = wait_for_sess_signal_receipt(inst, SESSION_ABORT_DONE);
+	if (rc)
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
+			__func__, rc);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 862dfab..c018345 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -48,3 +48,4 @@
 		V4L2_CTRL_DRIVER_PRIV(idx))
 
 #endif
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index e5696be..d9a2332 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -130,7 +130,6 @@
 	u32 height;
 	u32 fps;
 	u32 bitrate;
-	u64 prev_time_stamp;
 };
 
 struct buf_queue {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 1311752..bb72da7 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -75,7 +75,8 @@
 #define HFI_EXTRADATA_PANSCAN_WINDOW		0x00000008
 #define HFI_EXTRADATA_RECOVERY_POINT_SEI	0x00000009
 #define HFI_EXTRADATA_CLOSED_CAPTION_UD		0x0000000A
-#define HFI_EXTRADATA_AFD_UD				0x0000000B
+#define HFI_EXTRADATA_AFD_UD			0x0000000B
+#define HFI_EXTRADATA_MPEG2_SEQDISP		0x0000000D
 #define HFI_EXTRADATA_MULTISLICE_INFO		0x7F100000
 #define HFI_EXTRADATA_NUM_CONCEALED_MB		0x7F100001
 #define HFI_EXTRADATA_INDEX					0x7F100002
@@ -191,6 +192,8 @@
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
 #define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
 
 #define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
 	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 3fbfec4..bf1c70b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -95,6 +95,7 @@
 	HAL_EXTRADATA_NUM_CONCEALED_MB,
 	HAL_EXTRADATA_METADATA_FILLER,
 	HAL_EXTRADATA_ASPECT_RATIO,
+	HAL_EXTRADATA_MPEG2_SEQDISP
 };
 
 enum hal_property {
@@ -482,7 +483,7 @@
 	HAL_PICTURE_I = 0x01,
 	HAL_PICTURE_P = 0x02,
 	HAL_PICTURE_B = 0x04,
-	HAL_PICTURE_IDR = 0x7F001000,
+	HAL_PICTURE_IDR = 0x08,
 	HAL_FRAME_NOTCODED = 0x7F002000,
 	HAL_FRAME_YUV = 0x7F004000,
 	HAL_UNUSED_PICT = 0x10000000,
@@ -1020,7 +1021,7 @@
 };
 
 #define call_hfi_op(q, op, args...)			\
-	(((q)->op) ? ((q)->op(args)) : 0)
+	(((q) && (q)->op) ? ((q)->op(args)) : 0)
 
 struct hfi_device {
 	void *hfi_device_data;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 046faac..130ff48 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -70,8 +70,7 @@
 static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		       int bytes, void *dest, bool interface_reg)
 {
-	int ret;
-	u8 *buf = dest;
+	int i, ret;
 
 	if (bytes <= 0) {
 		dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
@@ -82,9 +81,11 @@
 	if (ret < 0) {
 		dev_err(wcd9xxx->dev, "Codec read failed\n");
 		return ret;
-	} else
-		dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
-			 *buf, reg);
+	} else {
+		for (i = 0; i < bytes; i++)
+			dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
+				((u8 *)dest)[i], reg + i);
+	}
 
 	return 0;
 }
@@ -107,15 +108,16 @@
 static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg)
 {
-	u8 *buf = src;
+	int i;
 
 	if (bytes <= 0) {
 		pr_err("%s: Error, invalid write length\n", __func__);
 		return -EINVAL;
 	}
 
-	dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n",
-		 *buf, reg);
+	for (i = 0; i < bytes; i++)
+		dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n", ((u8 *)src)[i],
+			reg + i);
 
 	return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
 }
@@ -1147,6 +1149,10 @@
 	    (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
 	     MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 
+	micbias->bias2_is_headset_only =
+	    of_property_read_bool(dev->of_node,
+				  "qcom,cdc-micbias2-headset-only");
+
 	dev_dbg(dev, "ldoh_v  %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
 		(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
 		(u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
@@ -1162,6 +1168,8 @@
 	dev_dbg(dev, "bias3_ext_cap %d bias4_ext_cap %d\n",
 		micbias->bias3_cap_mode, micbias->bias4_cap_mode);
 
+	dev_dbg(dev, "bias2_is_headset_only %d\n",
+		micbias->bias2_is_headset_only);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 7e6cd4f..59a6b68 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -172,16 +172,13 @@
 		}
 
 		/* NV bit is set to indicate that platform driver is capable
-		 * of doing NV download. SSR should not set NV bit; during
-		 * SSR NV bin is downloaded by WLAN driver.
+		 * of doing NV download.
 		 */
-		if (!wcnss_cold_boot_done()) {
-			pr_debug("wcnss: Indicate NV bin download\n");
-			spare_reg = msm_wcnss_base + spare_offset;
-			reg = readl_relaxed(spare_reg);
-			reg |= NVBIN_DLND_BIT;
-			writel_relaxed(reg, spare_reg);
-		}
+		pr_debug("wcnss: Indicate NV bin download\n");
+		spare_reg = msm_wcnss_base + spare_offset;
+		reg = readl_relaxed(spare_reg);
+		reg |= NVBIN_DLND_BIT;
+		writel_relaxed(reg, spare_reg);
 
 		pmu_conf_reg = msm_wcnss_base + pmu_offset;
 		writel_relaxed(0, pmu_conf_reg);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 1a175c9..f837a06 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -28,6 +28,9 @@
 #include <linux/of_gpio.h>
 #include <linux/clk.h>
 #include <linux/ratelimit.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -48,6 +51,10 @@
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
 
+static int has_calibrated_data = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
+
 static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
 module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -92,20 +99,27 @@
 #define CCU_PRONTO_LAST_ADDR2_OFFSET		0x14
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
-#define WCNSS_MAX_FRAME_SIZE		500
+#define WCNSS_MAX_FRAME_SIZE		(4*1024)
 #define WCNSS_VERSION_LEN			30
 
 /* message types */
 #define WCNSS_CTRL_MSG_START	0x01000000
-#define	WCNSS_VERSION_REQ		(WCNSS_CTRL_MSG_START + 0)
-#define	WCNSS_VERSION_RSP		(WCNSS_CTRL_MSG_START + 1)
-#define	WCNSS_NVBIN_DNLD_REQ		(WCNSS_CTRL_MSG_START + 2)
-#define	WCNSS_NVBIN_DNLD_RSP		(WCNSS_CTRL_MSG_START + 3)
+#define	WCNSS_VERSION_REQ             (WCNSS_CTRL_MSG_START + 0)
+#define	WCNSS_VERSION_RSP             (WCNSS_CTRL_MSG_START + 1)
+#define	WCNSS_NVBIN_DNLD_REQ          (WCNSS_CTRL_MSG_START + 2)
+#define	WCNSS_NVBIN_DNLD_RSP          (WCNSS_CTRL_MSG_START + 3)
+#define	WCNSS_CALDATA_UPLD_REQ        (WCNSS_CTRL_MSG_START + 4)
+#define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
+#define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
+#define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
 
 
 #define VALID_VERSION(version) \
 	((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
 
+#define FW_CALDATA_CAPABLE() \
+	((penv->fw_major >= 1) && (penv->fw_minor >= 5) ? 1 : 0)
+
 struct smd_msg_hdr {
 	unsigned int msg_type;
 	unsigned int msg_len;
@@ -126,6 +140,13 @@
  * header, so NV fragment size as next multiple of 1Kb is 3Kb.
  */
 #define NV_FRAGMENT_SIZE  3072
+#define MAX_CALIBRATED_DATA_SIZE  (64*1024)
+#define LAST_FRAGMENT        (1 << 0)
+#define MESSAGE_TO_FOLLOW    (1 << 1)
+#define CAN_RECEIVE_CALDATA  (1 << 15)
+#define WCNSS_RESP_SUCCESS   1
+#define WCNSS_RESP_FAIL      0
+
 
 /* Macro to find the total number fragments of the NV bin Image */
 #define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \
@@ -144,11 +165,14 @@
 	unsigned short frag_number;
 
 	/*
-	 * When set to 1 it indicates that no more fragments will
-	 * be sent. Receiver shall send back response message after
-	 * the last fragment.
+	 * bit 0: When set to 1 it indicates that no more fragments will
+	 * be sent.
+	 * bit 1: When set, a new message will be followed by this message
+	 * bit 2- bit 14:  Reserved
+	 * bit 15: when set, it indicates that the sender is capable of
+	 * receiving Calibrated data.
 	 */
-	unsigned short is_last_fragment;
+	unsigned short msg_flags;
 
 	/* NV Image size (number of bytes) */
 	unsigned int nvbin_buffer_size;
@@ -160,6 +184,7 @@
 	 */
 };
 
+
 struct nvbin_dnld_req_msg {
 	/*
 	 * Note: The length specified in nvbin_dnld_req_msg messages
@@ -170,6 +195,39 @@
 	struct nvbin_dnld_req_params dnld_req_params;
 };
 
+struct cal_data_params {
+
+	/* The total size of the calibrated data, including all the
+	 * fragments.
+	 */
+	unsigned int total_size;
+	unsigned short frag_number;
+	/*
+	 * bit 0: When set to 1 it indicates that no more fragments will
+	 * be sent.
+	 * bit 1: When set, a new message will be followed by this message
+	 * bit 2- bit 15: Reserved
+	 */
+	unsigned short msg_flags;
+	/*
+	 * fragment size
+	 */
+	unsigned int frag_size;
+	/*
+	 * Following the frag_size, frag_size of fragmented
+	 * data will be followed.
+	 */
+};
+
+struct cal_data_msg {
+	/*
+	 * The length specified in cal_data_msg should be
+	 * hdr.msg_len = sizeof(cal_data_msg) + frag_size
+	 */
+	struct smd_msg_hdr hdr;
+	struct cal_data_params cal_params;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -180,9 +238,10 @@
 	const struct dev_pm_ops *pm_ops;
 	int		triggered;
 	int		smd_channel_ready;
-	int		cold_boot_done;
 	smd_channel_t	*smd_ch;
 	unsigned char	wcnss_version[WCNSS_VERSION_LEN];
+	unsigned char   fw_major;
+	unsigned char   fw_minor;
 	unsigned int	serial_number;
 	int		thermal_mitigation;
 	enum wcnss_hw_type	wcnss_hw_type;
@@ -198,6 +257,20 @@
 	void __iomem *pronto_a2xb_base;
 	void __iomem *pronto_ccpu_base;
 	void __iomem *fiq_reg;
+	int	ssr_boot;
+	int	nv_downloaded;
+	unsigned char *fw_cal_data;
+	unsigned char *user_cal_data;
+	int	fw_cal_rcvd;
+	int	fw_cal_exp_frag;
+	int	fw_cal_available;
+	int	user_cal_read;
+	int	user_cal_available;
+	int	user_cal_rcvd;
+	int	user_cal_exp_size;
+	int	device_opened;
+	struct mutex dev_lock;
+	wait_queue_head_t read_wait;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -459,21 +532,26 @@
 	switch (event) {
 	case SMD_EVENT_DATA:
 		len = smd_read_avail(penv->smd_ch);
-		if (len < 0)
+		if (len < 0) {
 			pr_err("wcnss: failed to read from smd %d\n", len);
+			return;
+		}
 		schedule_work(&penv->wcnssctrl_rx_work);
 		break;
 
 	case SMD_EVENT_OPEN:
 		pr_debug("wcnss: opening WCNSS SMD channel :%s",
 				WCNSS_CTRL_CHANNEL);
-		if (!VALID_VERSION(penv->wcnss_version))
-			schedule_work(&penv->wcnssctrl_version_work);
+		schedule_work(&penv->wcnssctrl_version_work);
+
 		break;
 
 	case SMD_EVENT_CLOSE:
 		pr_debug("wcnss: closing WCNSS SMD channel :%s",
 				WCNSS_CTRL_CHANNEL);
+		/* This SMD is closed only during SSR */
+		penv->ssr_boot = true;
+		penv->nv_downloaded = 0;
 		break;
 
 	default:
@@ -658,6 +736,15 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_config);
 
+int wcnss_device_ready(void)
+{
+	if (penv && penv->pdev && penv->nv_downloaded)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_device_ready);
+
+
 struct resource *wcnss_wlan_get_memory_map(struct device *dev)
 {
 	if (penv && dev && (dev == &penv->pdev->dev) && penv->smd_channel_ready)
@@ -837,15 +924,13 @@
 }
 EXPORT_SYMBOL(wcnss_hardware_type);
 
-int wcnss_cold_boot_done(void)
+int fw_cal_data_available(void)
 {
 	if (penv)
-		return penv->cold_boot_done;
+		return penv->fw_cal_available;
 	else
 		return -ENODEV;
 }
-EXPORT_SYMBOL(wcnss_cold_boot_done);
-
 
 static int wcnss_smd_tx(void *data, int len)
 {
@@ -864,14 +949,145 @@
 	return ret;
 }
 
+static unsigned char wcnss_fw_status(void)
+{
+	int len = 0;
+	int rc = 0;
+
+	unsigned char fw_status = 0xFF;
+
+	len = smd_read_avail(penv->smd_ch);
+	if (len < 1) {
+		pr_err("%s: invalid firmware status", __func__);
+		return fw_status;
+	}
+
+	rc = smd_read(penv->smd_ch, &fw_status, 1);
+	if (rc < 0) {
+		pr_err("%s: incomplete data read from smd\n", __func__);
+		return fw_status;
+	}
+	return fw_status;
+}
+
+static void wcnss_send_cal_rsp(unsigned char fw_status)
+{
+	struct smd_msg_hdr *rsphdr;
+	unsigned char *msg = NULL;
+	int rc;
+
+	msg = kmalloc((sizeof(struct smd_msg_hdr) + 1), GFP_KERNEL);
+	if (NULL == msg) {
+		pr_err("wcnss: %s: failed to get memory\n", __func__);
+		return;
+	}
+
+	rsphdr = (struct smd_msg_hdr *)msg;
+	rsphdr->msg_type = WCNSS_CALDATA_UPLD_RSP;
+	rsphdr->msg_len = sizeof(struct smd_msg_hdr) + 1;
+	memcpy(msg+sizeof(struct smd_msg_hdr), &fw_status, 1);
+
+	rc = wcnss_smd_tx(msg, rsphdr->msg_len);
+	if (rc < 0)
+		pr_err("wcnss: smd tx failed\n");
+}
+
+/* Collect calibrated data from WCNSS */
+void extract_cal_data(int len)
+{
+	int rc;
+	struct cal_data_params calhdr;
+	unsigned char fw_status = WCNSS_RESP_FAIL;
+
+	if (len < sizeof(struct cal_data_params)) {
+		pr_err("wcnss: incomplete cal header length\n");
+		return;
+	}
+
+	rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
+			sizeof(struct cal_data_params));
+	if (rc < sizeof(struct cal_data_params)) {
+		pr_err("wcnss: incomplete cal header read from smd\n");
+		return;
+	}
+
+	if (penv->fw_cal_exp_frag != calhdr.frag_number) {
+		pr_err("wcnss: Invalid frgament");
+		goto exit;
+	}
+
+	if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
+		pr_err("wcnss: Invalid fragment size");
+		goto exit;
+	}
+
+	if (0 == calhdr.frag_number) {
+		if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
+			pr_err("wcnss: Invalid cal data size %d",
+				calhdr.total_size);
+			goto exit;
+		}
+		kfree(penv->fw_cal_data);
+		penv->fw_cal_rcvd = 0;
+		penv->fw_cal_data = kmalloc(calhdr.total_size,
+				GFP_KERNEL);
+		if (penv->fw_cal_data == NULL) {
+			smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+			goto exit;
+		}
+	}
+
+	mutex_lock(&penv->dev_lock);
+	if (penv->fw_cal_rcvd + calhdr.frag_size >
+			MAX_CALIBRATED_DATA_SIZE) {
+		pr_err("calibrated data size is more than expected %d",
+				penv->fw_cal_rcvd + calhdr.frag_size);
+		penv->fw_cal_exp_frag = 0;
+		penv->fw_cal_rcvd = 0;
+		smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+		goto unlock_exit;
+	}
+
+	rc = smd_read(penv->smd_ch, penv->fw_cal_data + penv->fw_cal_rcvd,
+			calhdr.frag_size);
+	if (rc < calhdr.frag_size)
+		goto unlock_exit;
+
+	penv->fw_cal_exp_frag++;
+	penv->fw_cal_rcvd += calhdr.frag_size;
+
+	if (calhdr.msg_flags & LAST_FRAGMENT) {
+		penv->fw_cal_exp_frag = 0;
+		penv->fw_cal_available = true;
+		pr_info("wcnss: cal data collection completed\n");
+	}
+	mutex_unlock(&penv->dev_lock);
+	wake_up(&penv->read_wait);
+
+	if (penv->fw_cal_available) {
+		fw_status = WCNSS_RESP_SUCCESS;
+		wcnss_send_cal_rsp(fw_status);
+	}
+	return;
+
+unlock_exit:
+	mutex_unlock(&penv->dev_lock);
+
+exit:
+	wcnss_send_cal_rsp(fw_status);
+	return;
+}
+
+
 static void wcnssctrl_rx_handler(struct work_struct *worker)
 {
 	int len = 0;
 	int rc = 0;
-	unsigned char buf[WCNSS_MAX_FRAME_SIZE];
+	unsigned char buf[sizeof(struct wcnss_version)];
 	struct smd_msg_hdr *phdr;
 	struct wcnss_version *pversion;
 	int hw_type;
+	unsigned char fw_status = 0;
 
 	len = smd_read_avail(penv->smd_ch);
 	if (len > WCNSS_MAX_FRAME_SIZE) {
@@ -882,23 +1098,33 @@
 	if (len <= 0)
 		return;
 
-	rc = smd_read(penv->smd_ch, buf, len);
-	if (rc < len) {
-		pr_err("wcnss: incomplete data read from smd\n");
+	rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr));
+	if (rc < sizeof(struct smd_msg_hdr)) {
+		pr_err("wcnss: incomplete header read from smd\n");
 		return;
 	}
+	len -= sizeof(struct smd_msg_hdr);
 
 	phdr = (struct smd_msg_hdr *)buf;
 
 	switch (phdr->msg_type) {
 
 	case WCNSS_VERSION_RSP:
-		pversion = (struct wcnss_version *)buf;
-		if (len != sizeof(struct wcnss_version)) {
+		if (len != sizeof(struct wcnss_version)
+				- sizeof(struct smd_msg_hdr)) {
 			pr_err("wcnss: invalid version data from wcnss %d\n",
-				len);
+					len);
 			return;
 		}
+		rc = smd_read(penv->smd_ch, buf+sizeof(struct smd_msg_hdr),
+				len);
+		if (rc < len) {
+			pr_err("wcnss: incomplete data read from smd\n");
+			return;
+		}
+		pversion = (struct wcnss_version *)buf;
+		penv->fw_major = pversion->major;
+		penv->fw_minor = pversion->minor;
 		snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
 			"%02x%02x%02x%02x", pversion->major, pversion->minor,
 					pversion->version, pversion->revision);
@@ -930,7 +1156,22 @@
 		break;
 
 	case WCNSS_NVBIN_DNLD_RSP:
-		pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n");
+		penv->nv_downloaded = true;
+		fw_status = wcnss_fw_status();
+		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
+			fw_status);
+		break;
+
+	case WCNSS_CALDATA_DNLD_RSP:
+		penv->nv_downloaded = true;
+		fw_status = wcnss_fw_status();
+		pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
+			fw_status);
+		break;
+
+	case WCNSS_CALDATA_UPLD_REQ:
+		penv->fw_cal_available = 0;
+		extract_cal_data(len);
 		break;
 
 	default:
@@ -953,7 +1194,8 @@
 	return;
 }
 
-static void wcnss_nvbin_dnld_req(struct work_struct *worker)
+
+static void wcnss_nvbin_dnld(void)
 {
 	int ret = 0;
 	struct nvbin_dnld_req_msg *dnld_req_msg;
@@ -970,8 +1212,8 @@
 	ret = request_firmware(&nv, NVBIN_FILE, dev);
 
 	if (ret || !nv || !nv->data || !nv->size) {
-		pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n",
-			NVBIN_FILE);
+		pr_err("wcnss: %s: request_firmware failed for %s\n",
+			__func__, NVBIN_FILE);
 		return;
 	}
 
@@ -992,13 +1234,14 @@
 		NV_FRAGMENT_SIZE), GFP_KERNEL);
 
 	if (NULL == outbuffer) {
-		pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n");
+		pr_err("wcnss: %s: failed to get buffer\n", __func__);
 		goto err_free_nv;
 	}
 
 	dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer;
 
 	dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ;
+	dnld_req_msg->dnld_req_params.msg_flags = 0;
 
 	for (count = 0; count < total_fragments; count++) {
 		dnld_req_msg->dnld_req_params.frag_number = count;
@@ -1009,10 +1252,14 @@
 			if (!cur_frag_size)
 				cur_frag_size = NV_FRAGMENT_SIZE;
 
-			dnld_req_msg->dnld_req_params.is_last_fragment = 1;
+			dnld_req_msg->dnld_req_params.msg_flags |=
+				LAST_FRAGMENT;
+			dnld_req_msg->dnld_req_params.msg_flags |=
+				CAN_RECEIVE_CALDATA;
 		} else {
 			cur_frag_size = NV_FRAGMENT_SIZE;
-			dnld_req_msg->dnld_req_params.is_last_fragment = 0;
+			dnld_req_msg->dnld_req_params.msg_flags &=
+				~LAST_FRAGMENT;
 		}
 
 		dnld_req_msg->dnld_req_params.nvbin_buffer_size =
@@ -1030,7 +1277,8 @@
 
 		retry_count = 0;
 		while ((ret == -ENOSPC) && (retry_count <= 3)) {
-			pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n");
+			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+				__func__);
 			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
 				count, dnld_req_msg->hdr.msg_len,
 				total_fragments, retry_count);
@@ -1043,7 +1291,7 @@
 		}
 
 		if (ret < 0) {
-			pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n");
+			pr_err("wcnss: %s: smd tx failed\n", __func__);
 			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
 				count, dnld_req_msg->hdr.msg_len,
 				total_fragments, retry_count);
@@ -1062,6 +1310,138 @@
 	return;
 }
 
+
+static void wcnss_caldata_dnld(const void *cal_data,
+		unsigned int cal_data_size, bool msg_to_follow)
+{
+	int ret = 0;
+	struct cal_data_msg *cal_msg;
+	unsigned short total_fragments = 0;
+	unsigned short count = 0;
+	unsigned short retry_count = 0;
+	unsigned short cur_frag_size = 0;
+	unsigned char *outbuffer = NULL;
+
+	total_fragments = TOTALFRAGMENTS(cal_data_size);
+
+	outbuffer = kmalloc((sizeof(struct cal_data_msg) +
+		NV_FRAGMENT_SIZE), GFP_KERNEL);
+
+	if (NULL == outbuffer) {
+		pr_err("wcnss: %s: failed to get buffer\n", __func__);
+		return;
+	}
+
+	cal_msg = (struct cal_data_msg *)outbuffer;
+
+	cal_msg->hdr.msg_type = WCNSS_CALDATA_DNLD_REQ;
+	cal_msg->cal_params.msg_flags = 0;
+
+	for (count = 0; count < total_fragments; count++) {
+		cal_msg->cal_params.frag_number = count;
+
+		if (count == (total_fragments - 1)) {
+			cur_frag_size = cal_data_size % NV_FRAGMENT_SIZE;
+			if (!cur_frag_size)
+				cur_frag_size = NV_FRAGMENT_SIZE;
+
+			cal_msg->cal_params.msg_flags
+			    |= LAST_FRAGMENT;
+			if (msg_to_follow)
+				cal_msg->cal_params.msg_flags |=
+					MESSAGE_TO_FOLLOW;
+		} else {
+			cur_frag_size = NV_FRAGMENT_SIZE;
+			cal_msg->cal_params.msg_flags &=
+				~LAST_FRAGMENT;
+		}
+
+		cal_msg->cal_params.total_size = cal_data_size;
+		cal_msg->cal_params.frag_size =
+			cur_frag_size;
+
+		cal_msg->hdr.msg_len =
+			sizeof(struct cal_data_msg) + cur_frag_size;
+
+		memcpy((outbuffer + sizeof(struct cal_data_msg)),
+			(cal_data + count * NV_FRAGMENT_SIZE),
+			cur_frag_size);
+
+		ret = wcnss_smd_tx(outbuffer, cal_msg->hdr.msg_len);
+
+		retry_count = 0;
+		while ((ret == -ENOSPC) && (retry_count <= 3)) {
+			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+					__func__);
+			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, cal_msg->hdr.msg_len,
+				total_fragments, retry_count);
+
+			/* wait and try again */
+			msleep(20);
+			retry_count++;
+			ret = wcnss_smd_tx(outbuffer,
+				cal_msg->hdr.msg_len);
+		}
+
+		if (ret < 0) {
+			pr_err("wcnss: %s: smd tx failed\n", __func__);
+			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, cal_msg->hdr.msg_len,
+				total_fragments, retry_count);
+			goto err_dnld;
+		}
+	}
+
+
+err_dnld:
+	/* free buffer */
+	kfree(outbuffer);
+
+	return;
+}
+
+
+static void wcnss_nvbin_dnld_main(struct work_struct *worker)
+{
+	int retry = 0;
+
+	if (!FW_CALDATA_CAPABLE())
+		goto nv_download;
+
+	if (!penv->fw_cal_available && WCNSS_CONFIG_UNSPECIFIED
+		!= has_calibrated_data && !penv->user_cal_available) {
+		while (!penv->user_cal_available && retry++ < 5)
+			msleep(500);
+	}
+
+	/* only cal data is sent during ssr (if available) */
+	if (penv->fw_cal_available && penv->ssr_boot) {
+		pr_info_ratelimited("wcnss: cal download during SSR, using fw cal");
+		wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, false);
+		return;
+
+	} else if (penv->user_cal_available && penv->ssr_boot) {
+		pr_info_ratelimited("wcnss: cal download during SSR, using user cal");
+		wcnss_caldata_dnld(penv->user_cal_data,
+		penv->user_cal_rcvd, false);
+		return;
+
+	} else if (penv->user_cal_available) {
+		pr_info_ratelimited("wcnss: cal download during cold boot, using user cal");
+		wcnss_caldata_dnld(penv->user_cal_data,
+		penv->user_cal_rcvd, true);
+	}
+
+nv_download:
+	pr_info_ratelimited("wcnss: NV download");
+	wcnss_nvbin_dnld();
+
+	return;
+}
+
+
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
@@ -1146,7 +1526,7 @@
 	}
 	INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
 	INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
-	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req);
+	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
 
@@ -1201,7 +1581,6 @@
 			goto fail_ioremap3;
 		}
 	}
-	penv->cold_boot_done = 1;
 
 	return 0;
 
@@ -1229,20 +1608,128 @@
 	return ret;
 }
 
-#ifndef MODULE
 static int wcnss_node_open(struct inode *inode, struct file *file)
 {
 	struct platform_device *pdev;
 
-	pr_info(DEVICE " triggered by userspace\n");
+	/* first open is only to trigger WCNSS platform driver */
+	if (!penv->triggered) {
+		pr_info(DEVICE " triggered by userspace\n");
+		pdev = penv->pdev;
+		return wcnss_trigger_config(pdev);
 
-	pdev = penv->pdev;
-	return wcnss_trigger_config(pdev);
+	} else if (penv->device_opened) {
+		pr_info(DEVICE " already opened\n");
+		return -EBUSY;
+	}
+
+	mutex_lock(&penv->dev_lock);
+	penv->user_cal_rcvd = 0;
+	penv->user_cal_read = 0;
+	penv->user_cal_available = false;
+	penv->user_cal_data = NULL;
+	penv->device_opened = 1;
+	mutex_unlock(&penv->dev_lock);
+
+	return 0;
 }
 
+static ssize_t wcnss_wlan_read(struct file *fp, char __user
+			*buffer, size_t count, loff_t *position)
+{
+	int rc = 0;
+
+	if (!penv->device_opened)
+		return -EFAULT;
+
+	rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
+			> penv->user_cal_read || penv->fw_cal_available);
+
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&penv->dev_lock);
+
+	if (penv->fw_cal_available && penv->fw_cal_rcvd
+			== penv->user_cal_read) {
+		rc = 0;
+		goto exit;
+	}
+
+	if (count > penv->fw_cal_rcvd - penv->user_cal_read)
+		count = penv->fw_cal_rcvd - penv->user_cal_read;
+
+	rc = copy_to_user(buffer, penv->fw_cal_data +
+			penv->user_cal_read, count);
+	if (rc == 0) {
+		penv->user_cal_read += count;
+		rc = count;
+	}
+
+exit:
+	mutex_unlock(&penv->dev_lock);
+	return rc;
+}
+
+/* first (valid) write to this device should be 4 bytes cal file size */
+static ssize_t wcnss_wlan_write(struct file *fp, const char __user
+			*user_buffer, size_t count, loff_t *position)
+{
+	int rc = 0;
+	int size = 0;
+
+	if (!penv->device_opened || penv->user_cal_available)
+		return -EFAULT;
+
+	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) {
+			pr_err(DEVICE " invalid size to write %d\n", size);
+			return -EFAULT;
+		}
+
+		rc += count;
+		count -= 4;
+		penv->user_cal_exp_size =  size;
+		penv->user_cal_data = kmalloc(size, GFP_KERNEL);
+		if (penv->user_cal_data == NULL) {
+			pr_err(DEVICE " no memory to write\n");
+			return -ENOMEM;
+		}
+		if (0 == count)
+			goto exit;
+
+	} else if (penv->user_cal_rcvd == 0 && count < 4)
+		return -EFAULT;
+
+	if (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;
+		goto exit;
+	}
+	rc = copy_from_user((void *)penv->user_cal_data +
+			penv->user_cal_rcvd, user_buffer, count);
+	if (0 == rc) {
+		penv->user_cal_rcvd += count;
+		rc += count;
+	}
+	if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
+		penv->user_cal_available = true;
+		pr_info_ratelimited("wcnss: user cal written");
+	}
+
+exit:
+	return rc;
+}
+
+
 static const struct file_operations wcnss_node_fops = {
 	.owner = THIS_MODULE,
 	.open = wcnss_node_open,
+	.read = wcnss_wlan_read,
+	.write = wcnss_wlan_write,
 };
 
 static struct miscdevice wcnss_misc = {
@@ -1250,8 +1737,6 @@
 	.name = DEVICE,
 	.fops = &wcnss_node_fops,
 };
-#endif /* ifndef MODULE */
-
 
 static int __devinit
 wcnss_wlan_probe(struct platform_device *pdev)
@@ -1279,18 +1764,8 @@
 		return -ENOENT;
 	}
 
-
-#ifdef MODULE
-
-	/* Since we were built as a module, we are running because
-	 * the module was loaded, therefore we assume userspace
-	 * applications are available to service PIL, so we can
-	 * trigger the WCNSS configuration now
-	 */
-	pr_info(DEVICE " probed in MODULE mode\n");
-	return wcnss_trigger_config(pdev);
-
-#else
+	mutex_init(&penv->dev_lock);
+	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
 	 * of kernel initialization.  We don't know if userspace
@@ -1303,7 +1778,6 @@
 	pr_info(DEVICE " probed in built-in mode\n");
 	return misc_register(&wcnss_misc);
 
-#endif
 }
 
 static int __devexit
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 26353ec..fa71efc 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -92,11 +92,13 @@
 	bool bam_connect_in_progress;
 	int a2_mux_send_power_vote_on_init_once;
 	int a2_mux_sw_bridge_is_connected;
+	bool a2_mux_dl_wakeup;
 	u32 a2_device_handle;
 	struct mutex wakeup_lock;
 	struct completion ul_wakeup_ack_completion;
 	struct completion bam_connection_completion;
 	struct completion request_resource_completion;
+	struct completion dl_wakeup_completion;
 	rwlock_t ul_wakeup_lock;
 	int wait_for_ack;
 	struct wake_lock bam_wakelock;
@@ -431,6 +433,7 @@
 static void kickoff_ul_wakeup_func(struct work_struct *work)
 {
 	bool is_connected;
+	int ret;
 
 	ul_wakeup();
 	write_lock(&a2_mux_ctx->ul_wakeup_lock);
@@ -440,8 +443,19 @@
 	write_unlock(&a2_mux_ctx->ul_wakeup_lock);
 	if (is_connected)
 		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
-			IPA_RM_RESOURCE_A2_CONS);
-	else
+				IPA_RM_RESOURCE_A2_CONS);
+	INIT_COMPLETION(a2_mux_ctx->dl_wakeup_completion);
+	if (!a2_mux_ctx->a2_mux_dl_wakeup) {
+		ret = wait_for_completion_timeout(
+			&a2_mux_ctx->dl_wakeup_completion,
+			A2_MUX_COMPLETION_TIMEOUT);
+		if (unlikely(ret == 0)) {
+			IPAERR("%s timeout A2 PROD\n", __func__);
+			BUG();
+			return;
+		}
+	}
+	if (!is_connected)
 		msm_bam_dmux_kickoff_ul_power_down();
 }
 
@@ -468,6 +482,8 @@
 		}
 	}
 	toggle_apps_ack();
+	a2_mux_ctx->a2_mux_dl_wakeup = true;
+	complete_all(&a2_mux_ctx->dl_wakeup_completion);
 }
 
 static void ipa_embedded_notify(void *priv,
@@ -635,6 +651,7 @@
 	(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
 	if (a2_mux_ctx->disconnect_ack)
 		toggle_apps_ack();
+	a2_mux_ctx->a2_mux_dl_wakeup = false;
 	a2_mux_ctx->a2_mux_sw_bridge_is_connected = 0;
 	complete_all(&a2_mux_ctx->bam_connection_completion);
 	return 0;
@@ -1467,6 +1484,7 @@
 	init_completion(&a2_mux_ctx->ul_wakeup_ack_completion);
 	init_completion(&a2_mux_ctx->bam_connection_completion);
 	init_completion(&a2_mux_ctx->request_resource_completion);
+	init_completion(&a2_mux_ctx->dl_wakeup_completion);
 	wake_lock_init(&a2_mux_ctx->bam_wakelock,
 		       WAKE_LOCK_SUSPEND, "a2_mux_wakelock");
 	a2_mux_ctx->a2_mux_initialized = 1;
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 67728c2..76aaad0 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -187,6 +187,7 @@
 	int inactive_cycles = 0;
 	int cnt;
 
+	ipa_inc_client_enable_clks();
 	do {
 		cnt = ipa_handle_tx_core(sys, true, true);
 		if (cnt == 0) {
@@ -199,6 +200,7 @@
 	} while (inactive_cycles <= POLLING_INACTIVITY_TX);
 
 	ipa_tx_switch_to_intr_mode(sys);
+	ipa_dec_client_disable_clks();
 }
 
 static void ipa_wq_handle_tx(struct work_struct *work)
@@ -914,6 +916,7 @@
 	int inactive_cycles = 0;
 	int cnt;
 
+	ipa_inc_client_enable_clks();
 	do {
 		cnt = ipa_handle_rx_core(sys, true, true);
 		if (cnt == 0) {
@@ -926,6 +929,7 @@
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
 	ipa_rx_switch_to_intr_mode(sys);
+	ipa_dec_client_disable_clks();
 }
 
 static void switch_to_intr_rx_work_func(struct work_struct *work)
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 866b921..eec6d39 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -127,7 +127,7 @@
 	int				adjust_soc_low_threshold;
 	int				chg_term_ua;
 	enum battery_type		batt_type;
-	unsigned int			fcc;
+	unsigned int			fcc_mah;
 	struct single_row_lut		*fcc_temp_lut;
 	struct single_row_lut		*fcc_sf_lut;
 	struct pc_temp_ocv_lut		*pc_temp_ocv_lut;
@@ -842,7 +842,6 @@
 	int rbatt_mohm, scalefactor;
 
 	rbatt_mohm = chip->default_rbatt_mohm;
-	pr_debug("rbatt before scaling = %d\n", rbatt_mohm);
 	if (chip->rbatt_sf_lut == NULL)  {
 		pr_debug("RBATT = %d\n", rbatt_mohm);
 		return rbatt_mohm;
@@ -851,18 +850,10 @@
 	batt_temp = batt_temp / 10;
 	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
 						batt_temp, soc_rbatt_mohm);
-	pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
-				scalefactor, batt_temp, soc_rbatt_mohm);
 	rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
 
 	rbatt_mohm += chip->r_conn_mohm;
-	pr_debug("adding r_conn_mohm = %d rbatt = %d\n",
-				chip->r_conn_mohm, rbatt_mohm);
 	rbatt_mohm += chip->rbatt_capacitive_mohm;
-	pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
-				chip->rbatt_capacitive_mohm, rbatt_mohm);
-
-	pr_debug("RBATT = %d\n", rbatt_mohm);
 	return rbatt_mohm;
 }
 
@@ -915,9 +906,6 @@
 							+ (chip->v_cutoff_uv);
 		delta_uv = ocv_mv * 1000 - unusable_uv;
 
-		pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
-				i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
-
 		if (delta_uv > 0)
 			break;
 
@@ -933,10 +921,10 @@
 
 	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp);
 	uuc_uah = (params->fcc_uah * pc_unusable) / 100;
-	pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+	pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d rbatt_pc = %d uuc = %d\n",
 					uuc_iavg_ma,
 					uuc_rbatt_mohm, unusable_uv,
-					pc_unusable, uuc_uah);
+					pc_unusable, i, uuc_uah);
 	*ret_pc_unusable = pc_unusable;
 	return uuc_uah;
 }
@@ -1112,8 +1100,7 @@
 	if (rtc == NULL) {
 		pr_err("%s: unable to open rtc device (%s)\n",
 			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
-		rc = -EINVAL;
-		goto close_time;
+		return -EINVAL;
 	}
 
 	rc = rtc_read_time(rtc, &tm);
@@ -1180,6 +1167,7 @@
 	if (soc_rbatt < 0)
 		soc_rbatt = 0;
 	params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
+	pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
 
 	calculate_iavg(chip, params->cc_uah, &params->iavg_ua,
 						params->delta_time_s);
@@ -1534,10 +1522,6 @@
 		pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
 						vbat_uv, chip->v_cutoff_uv);
 		return 1;
-	} else if (soc > 0 && vbat_uv < chip->v_cutoff_uv) {
-		pr_debug("forcing soc to 0, vbat (%d) < cutoff (%d)\n",
-						vbat_uv, chip->v_cutoff_uv);
-		return 0;
 	} else {
 		pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
 				soc, vbat_uv, chip->v_cutoff_uv);
@@ -1963,7 +1947,7 @@
 /* Returns full charge design in uAh */
 static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
 {
-	return chip->fcc;
+	return chip->fcc_mah * 1000;
 }
 
 static int get_prop_bms_present(struct qpnp_bms_chip *chip)
@@ -2175,7 +2159,7 @@
 		}
 	}
 
-	chip->fcc = batt_data->fcc;
+	chip->fcc_mah = batt_data->fcc;
 	chip->fcc_temp_lut = batt_data->fcc_temp_lut;
 	chip->fcc_sf_lut = batt_data->fcc_sf_lut;
 	chip->pc_temp_ocv_lut = batt_data->pc_temp_ocv_lut;
@@ -2575,10 +2559,20 @@
 	return 0;
 }
 
+static int bms_suspend(struct device *dev)
+{
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
+	chip->last_soc_unbound = true;
+	return 0;
+}
+
 static int bms_resume(struct device *dev)
 {
 	int rc;
-	unsigned long soc_calc_period;
+	int soc_calc_period;
+	int time_until_next_recalc;
 	unsigned long time_since_last_recalc;
 	unsigned long tm_now_sec;
 	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -2591,7 +2585,6 @@
 		 * unbind the last soc so that the next
 		 * recalculation is not limited to changing by 1%
 		 */
-		chip->last_soc_unbound = true;
 		time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
 		pr_debug("Time since last recalc: %lu\n",
 				time_since_last_recalc);
@@ -2600,16 +2593,19 @@
 		else
 			soc_calc_period = chip->calculate_soc_ms;
 
-		if (time_since_last_recalc >= soc_calc_period) {
-			chip->last_recalc_time = tm_now_sec;
-			recalculate_soc(chip);
-		}
+		time_until_next_recalc = max(0, soc_calc_period
+				- (int)(time_since_last_recalc * 1000));
+
+		schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(time_until_next_recalc)));
 	}
 	return 0;
 }
 
 static const struct dev_pm_ops qpnp_bms_pm_ops = {
 	.resume		= bms_resume,
+	.suspend	= bms_suspend,
 };
 
 static struct spmi_driver qpnp_bms_driver = {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 993b2cb..de2e5c1 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1814,11 +1814,15 @@
 	case SMBBP_BOOST_SUBTYPE:
 		break;
 	case SMBB_MISC_SUBTYPE:
-		chip->type = SMBB;
 	case SMBBP_MISC_SUBTYPE:
-		chip->type = SMBBP;
 	case SMBCL_MISC_SUBTYPE:
-		chip->type = SMBCL;
+		if (subtype == SMBB_MISC_SUBTYPE)
+			chip->type = SMBB;
+		else if (subtype == SMBBP_MISC_SUBTYPE)
+			chip->type = SMBBP;
+		else if (subtype == SMBCL_MISC_SUBTYPE)
+			chip->type = SMBCL;
+
 		pr_debug("Setting BOOT_DONE\n");
 		rc = qpnp_chg_masked_write(chip,
 			chip->misc_base + CHGR_MISC_BOOT_DONE,
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index 6d8985e..e0bffb9 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-13, 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
@@ -503,12 +503,17 @@
 		}
 	}
 
-	rtc_dd->rtc_ctrl_reg = BIT_RTC_ENABLE;
-	rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
+	rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
 				rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
 	if (rc) {
 		dev_err(&spmi->dev,
-				"Write to RTC control reg failed\n");
+			"Read from RTC control reg failed\n");
+		goto fail_rtc_enable;
+	}
+
+	if (!(rtc_dd->rtc_ctrl_reg & BIT_RTC_ENABLE)) {
+		dev_err(&spmi->dev,
+			"RTC h/w disabled, rtc not registered\n");
 		goto fail_rtc_enable;
 	}
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e12b9b4..c8fdc6b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1384,17 +1384,17 @@
 			 *  The result is saved with the response so that
 			 *  the ufs_core layer will handle it.
 			 */
-			result |= DID_OK << 16;
+			result = DID_OK << 16;
 			ufshcd_copy_query_response(hba, lrbp);
 			break;
 		case UPIU_TRANSACTION_REJECT_UPIU:
 			/* TODO: handle Reject UPIU Response */
-			result |= DID_ERROR << 16;
+			result = DID_ERROR << 16;
 			dev_err(hba->dev,
 				"Reject UPIU not fully implemented\n");
 			break;
 		default:
-			result |= DID_ERROR << 16;
+			result = DID_ERROR << 16;
 			dev_err(hba->dev,
 				"Unexpected request response code = %x\n",
 				result);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a0179cb..86ae8db 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -471,6 +471,8 @@
 	DECLARE_COMPLETION_ONSTACK(done);
 	u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
 
+	*clkgear = ctrl->clkgear;
+	*subfrmc = 0;
 	txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
 	txn.dt = SLIM_MSG_DEST_LOGICALADDR;
 	txn.la = SLIM_LA_MGR;
@@ -479,6 +481,34 @@
 	txn.wbuf = wbuf;
 	txn.rbuf = NULL;
 
+	if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
+		pr_debug("slim reserve BW for messaging: req: %d",
+				ctrl->sched.pending_msgsl);
+		txn.mc = SLIM_USR_MC_REQ_BW;
+		wbuf[txn.len++] = ((sb->laddr & 0x1f) |
+				((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
+		wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
+		ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+		if (ret)
+			return ret;
+		txn.rl = txn.len + 4;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+
+		txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+		txn.len = 2;
+		wbuf[1] = sb->laddr;
+		txn.rl = txn.len + 4;
+		ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+		if (ret)
+			return ret;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+
+		txn.len = 0;
+	}
 	list_for_each_entry(pch, &sb->mark_define, pending) {
 		struct slim_ich *slc;
 		slc = &ctrl->chans[pch->chan];
@@ -1039,8 +1069,6 @@
 	dev->ctrl.config_port = msm_config_port;
 	dev->ctrl.port_xfer = msm_slim_port_xfer;
 	dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
-	/* Reserve some messaging BW for satellite-apps driver communication */
-	dev->ctrl.sched.pending_msgsl = 30;
 	dev->bam_mem = bam_mem;
 
 	init_completion(&dev->reconf);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index b89f608..c5aa7e5 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2280,7 +2280,7 @@
 		bam_props.phys_addr = dd->bam.phys_addr;
 		bam_props.virt_addr = dd->bam.base;
 		bam_props.irq       = dd->bam.irq;
-		bam_props.manage    = SPS_BAM_MGR_LOCAL;
+		bam_props.manage    = SPS_BAM_MGR_DEVICE_REMOTE;
 		bam_props.summing_threshold = 0x10;
 
 		rc = sps_register_bam_device(&bam_props, &bam_handle);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 991cf2e..f01a078 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -199,8 +199,8 @@
 #define TSENS0_8X10_POINT1_SHIFT	16
 #define TSENS0_8X10_POINT2_SHIFT	22
 #define TSENS1_8X10_POINT2_SHIFT	6
-#define TSENS_8X10_BASE0_MASK		0xf
-#define TSENS_8X10_BASE1_MASK		0xf0
+#define TSENS_8X10_BASE0_MASK		0xff
+#define TSENS_8X10_BASE1_MASK		0xff00
 #define TSENS0_8X10_POINT1_MASK		0x3f0000
 #define TSENS0_8X10_POINT2_MASK		0xfc00000
 #define TSENS_8X10_TSENS_CAL_SEL	0x70000000
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index f672bd4..290e317 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -32,6 +32,8 @@
 #include <linux/spinlock.h>
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
+#include <linux/file.h>
+#include <linux/msm_kgsl.h>
 
 #include <mach/board.h>
 #include <mach/clk.h>
@@ -125,7 +127,7 @@
 	pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
 
 	spin_lock(&mdata->irq_lock);
-	mdp_interrupt &= mdata->irqMask;
+	mdp_interrupt &= mdata->irq_mask;
 
 	while (mdp_interrupt && i < MDP3_MAX_INTR) {
 		if ((mdp_interrupt & 0x1) && mdata->callbacks[i].cb)
@@ -145,14 +147,15 @@
 
 	pr_debug("mdp3_irq_enable type=%d\n", type);
 	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
-	if (mdp3_res->irqMask & BIT(type)) {
+	mdp3_res->irq_ref_count[type] += 1;
+	if (mdp3_res->irq_ref_count[type] > 1) {
 		pr_debug("interrupt %d already enabled\n", type);
 		spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
 		return;
 	}
-	irqEnabled = mdp3_res->irqMask;
-	mdp3_res->irqMask |= BIT(type);
-	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
+	irqEnabled = mdp3_res->irq_mask;
+	mdp3_res->irq_mask |= BIT(type);
+	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
 	if (!irqEnabled)
 		enable_irq(mdp3_res->irq);
 	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
@@ -163,26 +166,33 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
-	if (mdp3_res->irqMask & BIT(type)) {
-		mdp3_res->irqMask &= ~BIT(type);
-		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
-		if (!mdp3_res->irqMask)
-			disable_irq(mdp3_res->irq);
-	} else {
+	if (mdp3_res->irq_ref_count[type] <= 0) {
 		pr_debug("interrupt %d not enabled\n", type);
+		spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+		return;
+	}
+	mdp3_res->irq_ref_count[type] -= 1;
+	if (mdp3_res->irq_ref_count[type] == 0) {
+		mdp3_res->irq_mask &= ~BIT(type);
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
+		if (!mdp3_res->irq_mask)
+			disable_irq(mdp3_res->irq);
 	}
 	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
 }
 
 void mdp3_irq_disable_nosync(int type)
 {
-	if (mdp3_res->irqMask & BIT(type)) {
-		mdp3_res->irqMask &= ~BIT(type);
-		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
-		if (!mdp3_res->irqMask)
-			disable_irq_nosync(mdp3_res->irq);
-	} else {
+	if (mdp3_res->irq_ref_count[type] <= 0) {
 		pr_debug("interrupt %d not enabled\n", type);
+		return;
+	}
+	mdp3_res->irq_ref_count[type] -= 1;
+	if (mdp3_res->irq_ref_count[type] == 0) {
+		mdp3_res->irq_mask &= ~BIT(type);
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
+		if (!mdp3_res->irq_mask)
+			disable_irq_nosync(mdp3_res->irq);
 	}
 }
 
@@ -688,6 +698,108 @@
 	return 0;
 }
 
+int mdp3_put_img(struct mdp3_img_data *data)
+{
+	struct ion_client *iclient = mdp3_res->ion_client;
+	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+	if (!data->srcp_file) {
+		pr_debug("No img to put\n");
+		return 0;
+	}
+	if (data->flags & MDP_BLIT_SRC_GEM) {
+		pr_debug("memory source MDP_BLIT_SRC_GEM\n");
+	} else if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+		pr_debug("fb mem buf=0x%x\n", data->addr);
+		fput_light(data->srcp_file, data->p_need);
+		data->srcp_file = NULL;
+	} else {
+		ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+		ion_free(iclient, data->srcp_ihdl);
+		data->srcp_ihdl = NULL;
+	}
+	return 0;
+}
+
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data)
+{
+	struct file *file;
+	int ret = -EINVAL;
+	int fb_num;
+	unsigned long *start, *len;
+	struct ion_client *iclient = mdp3_res->ion_client;
+	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+	start = (unsigned long *) &data->addr;
+	len = (unsigned long *) &data->len;
+	data->flags |= img->flags;
+	data->p_need = 0;
+
+	if (img->flags & MDP_BLIT_SRC_GEM) {
+		data->srcp_file = NULL;
+		ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
+					&data->addr, &data->len);
+		if (!ret)
+			goto done;
+	}
+	if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
+		file = fget_light(img->memory_id, &data->p_need);
+		if (file == NULL) {
+			pr_err("invalid framebuffer file (%d)\n",
+					img->memory_id);
+			return -EINVAL;
+		}
+		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+			ret = mdss_fb_get_phys_info(start, len, fb_num);
+			if (ret) {
+				pr_err("mdss_fb_get_phys_info() failed\n");
+				fput_light(file, data->p_need);
+				file = NULL;
+			}
+		} else {
+			pr_err("invalid FB_MAJOR\n");
+			fput_light(file, data->p_need);
+			file = NULL;
+			ret = -EINVAL;
+		}
+		data->srcp_file = file;
+		if (!ret)
+			goto done;
+	}
+	if (iclient) {
+		data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
+		if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
+			pr_err("error on ion_import_fd\n");
+			ret = PTR_ERR(data->srcp_ihdl);
+			data->srcp_ihdl = NULL;
+			return ret;
+		}
+
+		ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
+		    0, SZ_4K, 0, start, len, 0, 0);
+
+		if (IS_ERR_VALUE(ret)) {
+			ion_free(iclient, data->srcp_ihdl);
+			pr_err("failed to map ion handle (%d)\n", ret);
+			return ret;
+		}
+	}
+done:
+	if (!ret && (img->offset < data->len)) {
+		data->addr += img->offset;
+		data->len -= img->offset;
+
+		pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
+			 data->srcp_ihdl, data->addr, data->len);
+	} else {
+		mdp3_put_img(data);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static int mdp3_init(struct msm_fb_data_type *mfd)
 {
 	return mdp3_ctrl_init(mfd);
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 5774e5a..7e395e1 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -23,6 +23,7 @@
 #include <mach/iommu_domains.h>
 
 #include "mdp3_dma.h"
+#include "mdss_fb.h"
 
 enum  {
 	MDP3_CLK_AHB,
@@ -100,12 +101,22 @@
 	struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
 
 	spinlock_t irq_lock;
-	u32 irqMask;
+	u32 irq_ref_count[MDP3_MAX_INTR];
+	u32 irq_mask;
 	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
 
 	struct early_suspend suspend_handler;
 };
 
+struct mdp3_img_data {
+	u32 addr;
+	u32 len;
+	u32 flags;
+	int p_need;
+	struct file *srcp_file;
+	struct ion_handle *srcp_ihdl;
+};
+
 extern struct mdp3_hw_resource *mdp3_res;
 
 struct mdp3_dma *mdp3_get_dma_pipe(int capability);
@@ -117,6 +128,8 @@
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate);
 int mdp3_clk_enable(int enable);
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
+int mdp3_put_img(struct mdp3_img_data *data);
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 929e5f8..f5ac5e9 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -26,37 +26,108 @@
 #define MDP_VSYNC_CLK_RATE	19200000
 #define VSYNC_PERIOD 16
 
+static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+
+static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
+{
+	bufq->count = 0;
+	bufq->push_idx = 0;
+	bufq->pop_idx = 0;
+}
+
+static void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq)
+{
+	int count = bufq->count;
+
+	if (!count)
+		return;
+
+	while (count--) {
+		struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
+		bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
+		mdp3_put_img(data);
+	}
+	bufq->count = 0;
+	bufq->push_idx = 0;
+	bufq->pop_idx = 0;
+}
+
+static int mdp3_bufq_push(struct mdp3_buffer_queue *bufq,
+			struct mdp3_img_data *data)
+{
+	if (bufq->count >= MDP3_MAX_BUF_QUEUE) {
+		pr_err("bufq full\n");
+		return -EPERM;
+	}
+
+	bufq->img_data[bufq->push_idx] = *data;
+	bufq->push_idx = (bufq->push_idx + 1) % MDP3_MAX_BUF_QUEUE;
+	bufq->count++;
+	return 0;
+}
+
+static struct mdp3_img_data *mdp3_bufq_pop(struct mdp3_buffer_queue *bufq)
+{
+	struct mdp3_img_data *data;
+	if (bufq->count == 0)
+		return NULL;
+
+	data = &bufq->img_data[bufq->pop_idx];
+	bufq->count--;
+	bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
+	return data;
+}
+
+static int mdp3_bufq_count(struct mdp3_buffer_queue *bufq)
+{
+	return bufq->count;
+}
+
 void vsync_notify_handler(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+	spin_lock(&session->vsync_lock);
+	session->vsync_time = ktime_get();
 	complete(&session->vsync_comp);
+	spin_unlock(&session->vsync_lock);
 }
 
 static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
 {
 	struct mdp3_session_data *mdp3_session;
 	struct mdp3_vsync_notification vsync_client;
+	struct mdp3_vsync_notification *arg = NULL;
+	unsigned long flag;
 
+	pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
 	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
 	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
 		!mdp3_session->intf)
 		return -ENODEV;
 
-	vsync_client.handler = vsync_notify_handler;
-	vsync_client.arg = mdp3_session;
-
-	mutex_lock(&mdp3_session->lock);
 	if (!mdp3_session->status) {
 		pr_debug("fb%d is not on yet", mfd->index);
-		mutex_unlock(&mdp3_session->lock);
 		return -EINVAL;
 	}
+	if (enable) {
+		vsync_client.handler = vsync_notify_handler;
+		vsync_client.arg = mdp3_session;
+		arg = &vsync_client;
+	}
 
-	mdp3_session->dma->vsync_enable(mdp3_session->dma, &vsync_client);
+	mutex_lock(&mdp3_session->lock);
+	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
 	mutex_unlock(&mdp3_session->lock);
+	spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
+	if (enable)
+		INIT_COMPLETION(mdp3_session->vsync_comp);
+	else
+		complete_all(&mdp3_session->vsync_comp);
+	spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
 	return 0;
 }
 
+
 static ssize_t mdp3_vsync_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -64,8 +135,8 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
 	struct mdp3_session_data *mdp3_session = NULL;
 	u64 vsync_ticks;
-	ktime_t vsync_time;
 	int rc;
+	unsigned long flag;
 
 	if (!mfd || !mfd->mdp.private1)
 		return 0;
@@ -78,11 +149,11 @@
 	if (rc <= 0) {
 		pr_warn("vsync wait on fb%d interrupted (%d)\n",
 			mfd->index, rc);
-		return -EBUSY;
 	}
 
-	vsync_time = mdp3_session->dma->get_vsync_time(mdp3_session->dma);
-	vsync_ticks = ktime_to_ns(vsync_time);
+	spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
+	vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
+	spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
 
 	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
 	rc = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
@@ -395,6 +466,148 @@
 	return 0;
 }
 
+static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
+				struct mdp_overlay *req)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (mdp3_session->overlay.id == req->id)
+		*req = mdp3_session->overlay;
+	else
+		rc = -EINVAL;
+
+	mutex_unlock(&mdp3_session->lock);
+
+	return rc;
+}
+
+static int mdp3_overlay_set(struct msm_fb_data_type *mfd,
+				struct mdp_overlay *req)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (mdp3_session->overlay.id == req->id) {
+		mdp3_session->overlay = *req;
+		if (req->id == MSMFB_NEW_REQUEST) {
+			mdp3_session->overlay.id = 1;
+			req->id = 1;
+		}
+	} else {
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mdp3_session->lock);
+
+	return rc;
+}
+
+static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+	mdp3_ctrl_pan_display(mfd);
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (mdp3_session->overlay.id == ndx && ndx == 1) {
+		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+		mdp3_bufq_deinit(&mdp3_session->bufq_in);
+		mdp3_bufq_deinit(&mdp3_session->bufq_out);
+	} else {
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&mdp3_session->lock);
+
+	return rc;
+}
+
+static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_data *req)
+{
+	int rc;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct msmfb_data *img = &req->data;
+	struct mdp3_img_data data;
+
+	rc = mdp3_get_img(img, &data);
+	if (rc) {
+		pr_err("fail to get overlay buffer\n");
+		return rc;
+	}
+
+	rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
+	if (rc) {
+		pr_err("fail to queue the overlay buffer, buffer drop\n");
+		mdp3_put_img(&data);
+		return rc;
+	}
+	return 0;
+}
+
+static int mdp3_overlay_play(struct msm_fb_data_type *mfd,
+				 struct msmfb_overlay_data *req)
+{
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	int rc = 0;
+
+	pr_debug("mdp3_overlay_play req id=%x mem_id=%d\n",
+		req->id, req->data.memory_id);
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (mfd->panel_power_on)
+		rc = mdp3_overlay_queue_buffer(mfd, req);
+	else
+		rc = -EPERM;
+
+	mutex_unlock(&mdp3_session->lock);
+
+	return rc;
+}
+
+static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd)
+{
+	struct mdp3_session_data *mdp3_session;
+	struct mdp3_img_data *data;
+	int rc = 0;
+
+	if (!mfd || !mfd->mdp.private1)
+		return -EINVAL;
+
+	mdp3_session = mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->dma)
+		return -EINVAL;
+
+	if (!mdp3_session->status) {
+		pr_err("%s, display off!\n", __func__);
+		return -EPERM;
+	}
+
+	mutex_lock(&mdp3_session->lock);
+
+	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
+	if (data) {
+		mdp3_session->dma->update(mdp3_session->dma,
+			(void *)data->addr);
+		mdp3_bufq_push(&mdp3_session->bufq_out, data);
+	}
+
+	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
+		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
+		mdp3_put_img(data);
+	}
+
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi;
@@ -445,6 +658,9 @@
 		break;
 	case metadata_op_get_caps:
 		metadata->data.caps.mdp_rev = 304;
+		metadata->data.caps.rgb_pipes = 0;
+		metadata->data.caps.vig_pipes = 0;
+		metadata->data.caps.dma_pipes = 1;
 		break;
 	default:
 		pr_warn("Unsupported request to MDP META IOCTL.\n");
@@ -460,6 +676,8 @@
 	int rc = -EINVAL;
 	struct mdp3_session_data *mdp3_session;
 	struct msmfb_metadata metadata;
+	struct mdp_overlay req;
+	struct msmfb_overlay_data ov_data;
 	int val;
 
 	pr_debug("mdp3_ctrl_ioctl_handler\n");
@@ -478,8 +696,6 @@
 	case MSMFB_OVERLAY_VSYNC_CTRL:
 		if (!copy_from_user(&val, argp, sizeof(val))) {
 			rc = mdp3_ctrl_vsync_enable(mfd, val);
-			if (!val)
-				init_completion(&mdp3_session->vsync_comp);
 		} else {
 			pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
 			rc = -EFAULT;
@@ -493,10 +709,42 @@
 		if (!rc)
 			rc = copy_to_user(argp, &metadata, sizeof(metadata));
 		break;
+	case MSMFB_OVERLAY_GET:
+		rc = copy_from_user(&req, argp, sizeof(req));
+		if (!rc) {
+			rc = mdp3_overlay_get(mfd, &req);
+
+		if (!IS_ERR_VALUE(rc))
+			rc = copy_to_user(argp, &req, sizeof(req));
+		}
+		if (rc)
+			pr_err("OVERLAY_GET failed (%d)\n", rc);
+		break;
+	case MSMFB_OVERLAY_SET:
+		rc = copy_from_user(&req, argp, sizeof(req));
+		if (!rc) {
+			rc = mdp3_overlay_set(mfd, &req);
+
+		if (!IS_ERR_VALUE(rc))
+			rc = copy_to_user(argp, &req, sizeof(req));
+		}
+		if (rc)
+			pr_err("OVERLAY_SET failed (%d)\n", rc);
+		break;
+	case MSMFB_OVERLAY_UNSET:
+		if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
+			rc = mdp3_overlay_unset(mfd, val);
+		break;
+	case MSMFB_OVERLAY_PLAY:
+		rc = copy_from_user(&ov_data, argp, sizeof(ov_data));
+		if (!rc)
+			rc = mdp3_overlay_play(mfd, &ov_data);
+		if (rc)
+			pr_err("OVERLAY_PLAY failed (%d)\n", rc);
+		break;
 	default:
 		break;
 	}
-
 	return rc;
 }
 
@@ -515,7 +763,7 @@
 	mdp3_interface->cursor_update = NULL;
 	mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
 	mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
-	mdp3_interface->kickoff_fnc = NULL;
+	mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
 
 	mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
 	if (!mdp3_session) {
@@ -525,6 +773,7 @@
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
 	init_completion(&mdp3_session->vsync_comp);
+	spin_lock_init(&mdp3_session->vsync_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
 	if (!mdp3_session->dma) {
 		rc = -ENODEV;
@@ -540,6 +789,9 @@
 
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
 	mdp3_session->status = 0;
+	mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+	mdp3_bufq_init(&mdp3_session->bufq_in);
+	mdp3_bufq_init(&mdp3_session->bufq_out);
 
 	mfd->mdp.private1 = mdp3_session;
 
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index d42ece7..fb3bd36 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -18,10 +18,20 @@
 #include <linux/mutex.h>
 #include <linux/completion.h>
 
+#include "mdp3.h"
 #include "mdp3_dma.h"
 #include "mdss_fb.h"
 #include "mdss_panel.h"
 
+#define MDP3_MAX_BUF_QUEUE 8
+
+struct mdp3_buffer_queue {
+	struct mdp3_img_data img_data[MDP3_MAX_BUF_QUEUE];
+	int count;
+	int push_idx;
+	int pop_idx;
+};
+
 struct mdp3_session_data {
 	struct mutex lock;
 	int status;
@@ -29,7 +39,12 @@
 	struct mdss_panel_data *panel;
 	struct mdp3_intf *intf;
 	struct msm_fb_data_type *mfd;
+	ktime_t vsync_time;
+	spinlock_t vsync_lock;
 	struct completion vsync_comp;
+	struct mdp_overlay overlay;
+	struct mdp3_buffer_queue bufq_in;
+	struct mdp3_buffer_queue bufq_out;
 };
 
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 69e3d7e..a09f503 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -20,17 +20,6 @@
 #define DMA_STOP_POLL_SLEEP_US 1000
 #define DMA_STOP_POLL_TIMEOUT_US 16000
 
-static ktime_t mdp3_get_vsync_time(struct mdp3_dma *dma)
-{
-	unsigned long flag;
-	ktime_t time;
-
-	spin_lock_irqsave(&dma->dma_lock, flag);
-	time = dma->vsync_time;
-	spin_unlock_irqrestore(&dma->dma_lock, flag);
-	return time;
-}
-
 static void mdp3_vsync_intr_handler(int type, void *arg)
 {
 	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
@@ -41,13 +30,11 @@
 	vsync_client = dma->vsync_client;
 	if (!vsync_client.handler)
 		dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_VSYNC;
-	dma->vsync_time = ktime_get();
 	complete(&dma->vsync_comp);
+	spin_unlock(&dma->dma_lock);
 	if (vsync_client.handler)
 		vsync_client.handler(vsync_client.arg);
-	spin_unlock(&dma->dma_lock);
-
-	if (!vsync_client.handler)
+	else
 		mdp3_irq_disable_nosync(type);
 }
 
@@ -186,7 +173,7 @@
 			updated = 1;
 		}
 	} else {
-		if (!dma->vsync_client.handler) {
+		if (dma->vsync_client.handler) {
 			dma->vsync_client.handler = NULL;
 			dma->vsync_client.arg = NULL;
 			updated = 1;
@@ -696,7 +683,6 @@
 		dma->histo_intr_enable = mdp3_dmap_histo_intr_enable;
 		dma->histo_intr_clear = mdp3_dmap_histo_intr_clear;
 		dma->vsync_enable = mdp3_dma_vsync_enable;
-		dma->get_vsync_time = mdp3_get_vsync_time;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
 		break;
@@ -717,7 +703,6 @@
 		dma->histo_intr_enable = NULL;
 		dma->histo_intr_clear = NULL;
 		dma->vsync_enable = mdp3_dma_vsync_enable;
-		dma->get_vsync_time = mdp3_get_vsync_time;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
 		break;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 2fb8427..cef749b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -231,7 +231,6 @@
 	spinlock_t dma_lock;
 	struct completion vsync_comp;
 	struct completion dma_comp;
-	ktime_t vsync_time;
 	struct mdp3_vsync_notification vsync_client;
 	u32 cb_type;
 
@@ -275,9 +274,6 @@
 
 	void (*vsync_enable)(struct mdp3_dma *dma,
 			struct mdp3_vsync_notification *vsync_client);
-
-	ktime_t (*get_vsync_time)(struct mdp3_dma *dma);
-
 };
 
 struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index a650522..122dcb9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -465,7 +465,7 @@
 				u32 *copyback);
 int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
 				struct mdp_igc_lut_data *config,
-				u32 *copyback);
+				u32 *copyback, u32 copy_from_kernel);
 int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
 				struct mdp_pgc_lut_data *config,
 				u32 *copyback);
@@ -536,6 +536,7 @@
 u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
 
 int mdss_panel_register_done(struct mdss_panel_data *pdata);
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
 
 #define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
 #define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b2147c3..e346082 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -248,13 +248,14 @@
 	return ret;
 }
 
-static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata)
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
+					       u32 off)
 {
 	struct mdss_mdp_ctl *ctl = NULL;
-	int cnum;
+	u32 cnum;
 
 	mutex_lock(&mdss_mdp_ctl_lock);
-	for (cnum = 0; cnum < mdata->nctl; cnum++) {
+	for (cnum = off; cnum < mdata->nctl; cnum++) {
 		ctl = mdata->ctl_off + cnum;
 		if (ctl->ref_cnt == 0) {
 			ctl->ref_cnt++;
@@ -391,7 +392,7 @@
 	struct mdss_mdp_ctl *ctl = NULL;
 	struct mdss_mdp_mixer *mixer = NULL;
 
-	ctl = mdss_mdp_ctl_alloc(mdss_res);
+	ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
 	if (!ctl)
 		return NULL;
 
@@ -669,7 +670,7 @@
 	int ret = 0;
 
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
-	ctl = mdss_mdp_ctl_alloc(mdata);
+	ctl = mdss_mdp_ctl_alloc(mdata, MDSS_MDP_CTL0);
 	if (!ctl) {
 		pr_err("unable to allocate ctl\n");
 		return ERR_PTR(-ENOMEM);
@@ -711,6 +712,9 @@
 		ctl->intf_type = MDSS_INTF_HDMI;
 		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
 		ctl->start_fnc = mdss_mdp_video_start;
+		ret = mdss_mdp_limited_lut_igc_config(ctl);
+		if (ret)
+			pr_err("Unable to config IGC LUT data");
 		break;
 	case WRITEBACK_PANEL:
 		ctl->intf_num = MDSS_MDP_NO_INTF;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 56fd163..3cb23f3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -65,11 +65,19 @@
 {
 	u32 xres, yres;
 	u32 min_src_size, min_dst_size;
+	int content_secure;
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
+	content_secure = (req->flags & MDP_SECURE_OVERLAY_SESSION);
+	if (!ctl->is_secure && content_secure &&
+				 (mfd->panel.type == WRITEBACK_PANEL)) {
+		pr_debug("return due to security concerns\n");
+		return -EPERM;
+	}
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
 		min_src_size = fmt->is_yuv ? 2 : 1;
 		min_dst_size = 1;
@@ -1467,6 +1475,7 @@
 	int ret;
 	struct msmfb_mdp_pp mdp_pp;
 	u32 copyback = 0;
+	u32 copy_from_kernel = 0;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
@@ -1493,7 +1502,7 @@
 					mdp5_data->ctl,
 					(struct mdp_igc_lut_data *)
 					&mdp_pp.data.lut_cfg_data.data,
-					&copyback);
+					&copyback, copy_from_kernel);
 			break;
 
 		case mdp_lut_pgc:
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 4e7cc37..65b5fc4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -93,6 +93,72 @@
 static u32 dither_depth_map[9] = {
 	0, 0, 0, 0, 0, 1, 2, 3, 3};
 
+static u32 igc_limited[IGC_LUT_ENTRIES] = {
+	16777472, 17826064, 18874656, 19923248,
+	19923248, 20971840, 22020432, 23069024,
+	24117616, 25166208, 26214800, 26214800,
+	27263392, 28311984, 29360576, 30409168,
+	31457760, 32506352, 32506352, 33554944,
+	34603536, 35652128, 36700720, 37749312,
+	38797904, 38797904, 39846496, 40895088,
+	41943680, 42992272, 44040864, 45089456,
+	45089456, 46138048, 47186640, 48235232,
+	49283824, 50332416, 51381008, 51381008,
+	52429600, 53478192, 54526784, 55575376,
+	56623968, 57672560, 58721152, 58721152,
+	59769744, 60818336, 61866928, 62915520,
+	63964112, 65012704, 65012704, 66061296,
+	67109888, 68158480, 69207072, 70255664,
+	71304256, 71304256, 72352848, 73401440,
+	74450032, 75498624, 76547216, 77595808,
+	77595808, 78644400, 79692992, 80741584,
+	81790176, 82838768, 83887360, 83887360,
+	84935952, 85984544, 87033136, 88081728,
+	89130320, 90178912, 90178912, 91227504,
+	92276096, 93324688, 94373280, 95421872,
+	96470464, 96470464, 97519056, 98567648,
+	99616240, 100664832, 101713424, 102762016,
+	102762016, 103810608, 104859200, 105907792,
+	106956384, 108004976, 109053568, 109053568,
+	110102160, 111150752, 112199344, 113247936,
+	114296528, 115345120, 115345120, 116393712,
+	117442304, 118490896, 119539488, 120588080,
+	121636672, 121636672, 122685264, 123733856,
+	124782448, 125831040, 126879632, 127928224,
+	127928224, 128976816, 130025408, 131074000,
+	132122592, 133171184, 134219776, 135268368,
+	135268368, 136316960, 137365552, 138414144,
+	139462736, 140511328, 141559920, 141559920,
+	142608512, 143657104, 144705696, 145754288,
+	146802880, 147851472, 147851472, 148900064,
+	149948656, 150997248, 152045840, 153094432,
+	154143024, 154143024, 155191616, 156240208,
+	157288800, 158337392, 159385984, 160434576,
+	160434576, 161483168, 162531760, 163580352,
+	164628944, 165677536, 166726128, 166726128,
+	167774720, 168823312, 169871904, 170920496,
+	171969088, 173017680, 173017680, 174066272,
+	175114864, 176163456, 177212048, 178260640,
+	179309232, 179309232, 180357824, 181406416,
+	182455008, 183503600, 184552192, 185600784,
+	185600784, 186649376, 187697968, 188746560,
+	189795152, 190843744, 191892336, 191892336,
+	192940928, 193989520, 195038112, 196086704,
+	197135296, 198183888, 198183888, 199232480,
+	200281072, 201329664, 202378256, 203426848,
+	204475440, 204475440, 205524032, 206572624,
+	207621216, 208669808, 209718400, 210766992,
+	211815584, 211815584, 212864176, 213912768,
+	214961360, 216009952, 217058544, 218107136,
+	218107136, 219155728, 220204320, 221252912,
+	222301504, 223350096, 224398688, 224398688,
+	225447280, 226495872, 227544464, 228593056,
+	229641648, 230690240, 230690240, 231738832,
+	232787424, 233836016, 234884608, 235933200,
+	236981792, 236981792, 238030384, 239078976,
+	240127568, 241176160, 242224752, 243273344,
+	243273344, 244321936, 245370528, 246419120};
+
 #define GAMUT_T0_SIZE	125
 #define GAMUT_T1_SIZE	100
 #define GAMUT_T2_SIZE	80
@@ -1543,9 +1609,30 @@
 		MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
 }
 
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
+{
+	int ret = 0;
+	u32 copyback = 0;
+	u32 copy_from_kernel = 1;
+	struct mdp_igc_lut_data config;
+
+	if (!ctl)
+		return -EINVAL;
+
+	config.len = IGC_LUT_ENTRIES;
+	config.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+	config.block = (ctl->mfd->index) + MDP_LOGICAL_BLOCK_DISP_0;
+	config.c0_c1_data = igc_limited;
+	config.c2_data = igc_limited;
+
+	ret = mdss_mdp_igc_lut_config(ctl, &config, &copyback,
+					copy_from_kernel);
+	return ret;
+}
+
 int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
 					struct mdp_igc_lut_data *config,
-					u32 *copyback)
+					u32 *copyback, u32 copy_from_kernel)
 {
 	int ret = 0;
 	u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
@@ -1597,15 +1684,25 @@
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
-		if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
-			config->c0_c1_data, config->len * sizeof(u32))) {
-			ret = -EFAULT;
-			goto igc_config_exit;
-		}
-		if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
-			config->c2_data, config->len * sizeof(u32))) {
-			ret = -EFAULT;
-			goto igc_config_exit;
+		if (copy_from_kernel) {
+			memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+			config->c0_c1_data, config->len * sizeof(u32));
+			memcpy(&mdss_pp_res->igc_lut_c2[disp_num][0],
+			config->c2_data, config->len * sizeof(u32));
+		} else {
+			if (copy_from_user(
+				&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+				config->c0_c1_data,
+				config->len * sizeof(u32))) {
+				ret = -EFAULT;
+				goto igc_config_exit;
+			}
+			if (copy_from_user(
+				&mdss_pp_res->igc_lut_c2[disp_num][0],
+				config->c2_data, config->len * sizeof(u32))) {
+				ret = -EFAULT;
+				goto igc_config_exit;
+			}
 		}
 		mdss_pp_res->igc_disp_cfg[disp_num] = *config;
 		mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 2f77d29..73b94af 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -286,7 +286,7 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
-	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
@@ -725,7 +725,7 @@
 /* LOG CODES */
 
 #define LOG_0	0x0
-#define LOG_1	0x17F4
+#define LOG_1	0x17FA
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/input/gen_vkeys.h b/include/linux/input/gen_vkeys.h
index ce29351..a58158d 100644
--- a/include/linux/input/gen_vkeys.h
+++ b/include/linux/input/gen_vkeys.h
@@ -19,5 +19,6 @@
 	int panel_maxy;
 	int *keycodes;
 	int num_keys;
+	int y_offset;
 };
 #endif
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index c6e4ab3..b7ba6fb 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -126,6 +126,7 @@
 	u8 bias2_cap_mode;
 	u8 bias3_cap_mode;
 	u8 bias4_cap_mode;
+	bool bias2_is_headset_only;
 };
 
 struct wcd9xxx_ocp_setting {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 4bce95c..323f1e7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -700,7 +700,9 @@
 #define V4L2_QCOM_BUF_FLAG_CODECCONFIG  0x4000
 #define V4L2_QCOM_BUF_FLAG_EOSEQ  0x8000
 #define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
+#define V4L2_QCOM_BUF_FLAG_IDRFRAME	0x20000	/* Image is a IDR-frame */
 #define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
+#define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
 
 /*
  *	O V E R L A Y   P R E V I E W
@@ -1838,6 +1840,7 @@
 	V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP,
 	V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
 	V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+	V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP
 };
 #define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2319c48..da56df6 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -33,6 +33,7 @@
 #define WCNSS_WLAN_IRQ_INVALID -1
 #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
 #define HAVE_WCNSS_RESET_INTR 1
+#define HAVE_WCNSS_CAL_DOWNLOAD 1
 
 struct device *wcnss_wlan_get_device(void);
 struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -65,7 +66,7 @@
 void wcnss_resume_notify(void);
 void wcnss_riva_log_debug_regs(void);
 void wcnss_pronto_log_debug_regs(void);
-int wcnss_cold_boot_done(void);
+int wcnss_device_ready(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 992649f..47cf184 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -289,8 +289,8 @@
 
 enum eeprom_cfg_type_t {
 	CFG_EEPROM_GET_INFO,
-	CFG_EEPROM_GET_DATA,
-	CFG_EEPROM_READ_DATA,
+	CFG_EEPROM_GET_CAL_DATA,
+	CFG_EEPROM_READ_CAL_DATA,
 	CFG_EEPROM_WRITE_DATA,
 };
 struct eeprom_get_t {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index f632ad6..2164275 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -73,6 +73,16 @@
 	unsigned int aspect_height;
 };
 
+struct msm_vidc_mpeg2_seqdisp_payload {
+	unsigned int video_format;
+	bool color_descp;
+	unsigned int color_primaries;
+	unsigned int transfer_char;
+	unsigned int matrix_coeffs;
+	unsigned int disp_width;
+	unsigned int disp_height;
+};
+
 struct msm_vidc_panscan_window {
 	unsigned int panscan_height_offset;
 	unsigned int panscan_width_offset;
@@ -94,6 +104,7 @@
 	EXTRADATA_FRAME_RATE = 0x00000007,
 	EXTRADATA_PANSCAN_WINDOW = 0x00000008,
 	EXTRADATA_RECOVERY_POINT_SEI = 0x00000009,
+	EXTRADATA_MPEG2_SEQDISP = 0x0000000D,
 	EXTRADATA_MULTISLICE_INFO = 0x7F100000,
 	EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
 	EXTRADATA_INDEX = 0x7F100002,
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 01e30d0..0d3b5a0 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -2237,7 +2237,7 @@
 */
 #define ADSP_MEMORY_MAP_PHYSICAL_MEMORY 0
 
-
+#define NULL_COPP_TOPOLOGY				0x00010312
 #define DEFAULT_COPP_TOPOLOGY				0x00010be3
 #define DEFAULT_POPP_TOPOLOGY				0x00010be4
 #define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 4bea1e1..449694e 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -47,10 +47,10 @@
 int adm_memory_unmap_regions(int port_id, uint32_t *buf_add, uint32_t *bufsz,
 						uint32_t bufcnt);
 
-int adm_close(int port);
+int adm_close(int port, bool perf_mode);
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-				unsigned int *port_id, int copp_id);
+		unsigned int *port_id, int copp_id, bool perf_mode);
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
 
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 0dd14e6..2d34d70 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -70,7 +70,6 @@
 #define COMPRESSED_IO	0x0040
 #define NT_MODE        0x0400
 
-
 #define NO_TIMESTAMP    0xFF00
 #define SET_TIMESTAMP   0x0000
 
@@ -79,6 +78,19 @@
 
 #define SESSION_MAX	0x08
 
+/* payload structure bytes */
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFADD_LSW 1
+#define READDONE_IDX_BUFADD_MSW 2
+#define READDONE_IDX_MEMMAP_HDL 3
+#define READDONE_IDX_SIZE 4
+#define READDONE_IDX_OFFSET 5
+#define READDONE_IDX_LSW_TS 6
+#define READDONE_IDX_MSW_TS 7
+#define READDONE_IDX_FLAGS 8
+#define READDONE_IDX_NUMFRAMES 9
+#define READDONE_IDX_SEQ_ID 10
+
 #define SOFT_PAUSE_PERIOD       30   /* ramp up/down for 30ms    */
 #define SOFT_PAUSE_STEP         2000 /* Step value 2ms or 2000us */
 enum {
diff --git a/kernel/timer.c b/kernel/timer.c
index 24c5d20..cf7217a 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1679,12 +1679,12 @@
 			boot_done = 1;
 			base = &boot_tvec_bases;
 		}
+		spin_lock_init(&base->lock);
 		tvec_base_done[cpu] = 1;
 	} else {
 		base = per_cpu(tvec_bases, cpu);
 	}
 
-	spin_lock_init(&base->lock);
 
 	for (j = 0; j < TVN_SIZE; j++) {
 		INIT_LIST_HEAD(base->tv5.vec + j);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 845f1a2..5d4f9e6 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -488,6 +488,8 @@
 	bool spkr_pa_widget_on;
 	struct regulator *spkdrv_reg;
 
+	bool mbhc_started;
+
 	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
 
 	/* resmgr module */
@@ -2648,7 +2650,9 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
 
-		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+		if (taiko->mbhc_started &&
+		    taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+		    micb_ctl_reg == TAIKO_A_MICB_2_CTL)
 			wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
 						  WCD9XXX_COND_HPH_MIC,
 						  micb_ctl_reg, w->shift,
@@ -2663,7 +2667,9 @@
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+		if (taiko->mbhc_started &&
+		    taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+		    micb_ctl_reg == TAIKO_A_MICB_2_CTL)
 			wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
 						  WCD9XXX_COND_HPH_MIC,
 						  micb_ctl_reg, 7, false);
@@ -5960,8 +5966,12 @@
 int taiko_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
+	int rc;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
-	return wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+	rc = wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+	if (!rc)
+		taiko->mbhc_started = true;
+	return rc;
 }
 EXPORT_SYMBOL_GPL(taiko_hs_detect);
 
@@ -6017,13 +6027,20 @@
 	taiko_init_slim_slave_cfg(codec);
 	taiko_slim_interface_init_reg(codec);
 
-	wcd9xxx_mbhc_deinit(&taiko->mbhc);
-	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
-				WCD9XXX_MBHC_VERSION_TAIKO);
-	if (ret)
-		pr_err("%s: mbhc init failed %d\n", __func__, ret);
-	else
-		wcd9xxx_mbhc_start(&taiko->mbhc, taiko->mbhc.mbhc_cfg);
+	if (taiko->mbhc_started) {
+		wcd9xxx_mbhc_deinit(&taiko->mbhc);
+		taiko->mbhc_started = false;
+		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
+					WCD9XXX_MBHC_VERSION_TAIKO);
+		if (ret) {
+			pr_err("%s: mbhc init failed %d\n", __func__, ret);
+		} else {
+			ret = wcd9xxx_mbhc_start(&taiko->mbhc,
+						 taiko->mbhc.mbhc_cfg);
+			if (!ret)
+				taiko->mbhc_started = true;
+		}
+	}
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index b140b5b..c3967dc 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.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
@@ -2336,6 +2336,9 @@
 {
 	int ret;
 
+	/* Set GPIO headset detection by default */
+	hs_detect_use_gpio = true;
+
 	if (!cpu_is_msm9615()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
@@ -2413,8 +2416,6 @@
 	sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
 	secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
 
-	hs_detect_use_gpio = true;
-
 	return ret;
 }
 module_init(mdm9615_audio_init);
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 9359ed7..9dbbf20 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -39,7 +39,10 @@
 #define COMPRE_CAPTURE_NUM_PERIODS	16
 /* Allocate the worst case frame size for compressed audio */
 #define COMPRE_CAPTURE_HEADER_SIZE	(sizeof(struct snd_compr_audio_info))
-#define COMPRE_CAPTURE_MAX_FRAME_SIZE	(6144)
+/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE
+ * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1
+ */
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE	(4032)
 #define COMPRE_CAPTURE_PERIOD_SIZE	((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
 					  COMPRE_CAPTURE_HEADER_SIZE) * \
 					  MAX_NUM_FRAMES_PER_BUFFER)
@@ -226,7 +229,7 @@
 				prtd->pcm_irq_pos);
 
 		memcpy(prtd->audio_client->port[OUT].buf->data +
-			   prtd->pcm_irq_pos, (ptrmem + 2),
+			   prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
 			   COMPRE_CAPTURE_HEADER_SIZE);
 		pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
 				prtd->audio_client->port[OUT].buf,
@@ -235,9 +238,10 @@
 				prtd->audio_client->port[OUT].buf->data);
 		if (!atomic_read(&prtd->start))
 			break;
-		pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
-				ptrmem[1]);
-		if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+		pr_debug("frame size=%d, buffer = 0x%X\n",
+				ptrmem[READDONE_IDX_SIZE],
+				ptrmem[READDONE_IDX_BUFADD_LSW]);
+		if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
 			pr_err("Frame length exceeded the max length");
 			break;
 		}
@@ -546,7 +550,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 4;
+	compr->info.compr_cap.num_codecs = 5;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -555,6 +559,7 @@
 	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
 	compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
+	compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB;
 	/* Add new codecs here */
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 04b090a..04a0a84 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1358,16 +1358,25 @@
 	SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
-	SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
+	SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("TERT MI2S RX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("QUAT MI2S RX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
 	SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
-	SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+	SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
-	SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
+	SOC_ENUM_EXT("TERT MI2S TX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("QUAT MI2S TX Format", mi2s_config_enum[0],
 		     msm_dai_q6_mi2s_format_get,
 		     msm_dai_q6_mi2s_format_put),
 };
@@ -1384,6 +1393,10 @@
 		if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
 			ctrl = &mi2s_config_controls[0];
 		if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+			ctrl = &mi2s_config_controls[1];
+		if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+			ctrl = &mi2s_config_controls[2];
+		if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
 			ctrl = &mi2s_config_controls[3];
 	}
 
@@ -1402,9 +1415,13 @@
 	ctrl = NULL;
 	if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
 		if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
-			ctrl = &mi2s_config_controls[2];
-		if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
 			ctrl = &mi2s_config_controls[4];
+		if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+			ctrl = &mi2s_config_controls[5];
+		if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+			ctrl = &mi2s_config_controls[6];
+		if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
+			ctrl = &mi2s_config_controls[7];
 	}
 
 	if (ctrl) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index fa476ee..643f280 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -44,7 +44,7 @@
 	unsigned int  sample_rate;
 	unsigned int  channel;
 	unsigned int  format;
-	bool perf_mode;
+	unsigned long perf_mode;
 };
 
 #define INVALID_SESSION -1
@@ -270,7 +270,7 @@
 }
 
 static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
-	int path_type)
+	int path_type, bool perf_mode)
 {
 	int i, port_type;
 	struct route_payload payload;
@@ -290,7 +290,7 @@
 
 	if (payload.num_copps)
 		adm_matrix_map(dspst_id, path_type,
-			payload.num_copps, payload.copp_ids, 0);
+			payload.num_copps, payload.copp_ids, 0, perf_mode);
 }
 
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
@@ -365,8 +365,8 @@
 		msm_send_eq_values(fedai_id);
 	topology = get_topology(path_type);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
-			msm_bedais[i].perf_mode = perf_mode;
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
+			set_bit(fedai_id, &msm_bedais[i].perf_mode);
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
@@ -385,7 +385,8 @@
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				topology, msm_bedais[i].perf_mode,
+				topology,
+				test_bit(fedai_id, &msm_bedais[i].perf_mode),
 				bits_per_sample);
 			else
 				adm_open(msm_bedais[i].port_id,
@@ -408,7 +409,7 @@
 	}
 	if (payload.num_copps)
 		adm_matrix_map(dspst_id, path_type,
-			payload.num_copps, payload.copp_ids, 0);
+			payload.num_copps, payload.copp_ids, 0, perf_mode);
 
 	mutex_unlock(&routing_lock);
 }
@@ -440,7 +441,8 @@
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
 		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
-			adm_close(msm_bedais[i].port_id);
+			adm_close(msm_bedais[i].port_id,
+				test_bit(fedai_id, &msm_bedais[i].perf_mode));
 			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
 				dolby_dap_deinit(msm_bedais[i].port_id);
 		}
@@ -473,6 +475,7 @@
 	int session_type, path_type, port_id, topology;
 	u32 channels;
 	uint16_t bits_per_sample = 16;
+	bool perf_mode = false;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
@@ -507,12 +510,14 @@
 
 			if ((session_type == SESSION_TYPE_RX) &&
 				(channels > 0)) {
+				perf_mode = test_bit(val,
+						&msm_bedais[reg].perf_mode);
 				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate,
 				channels,
 				topology,
-				msm_bedais[reg].perf_mode,
+				perf_mode,
 				bits_per_sample);
 			} else
 				adm_open(msm_bedais[reg].port_id,
@@ -521,7 +526,8 @@
 				topology, false, bits_per_sample);
 
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type);
+				fe_dai_map[val][session_type], path_type,
+				perf_mode);
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
@@ -536,11 +542,13 @@
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
 		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
 			INVALID_SESSION) {
-			adm_close(msm_bedais[reg].port_id);
+			perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
+			adm_close(msm_bedais[reg].port_id, perf_mode);
 			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type);
+				fe_dai_map[val][session_type], path_type,
+				perf_mode);
 		}
 	}
 	if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1411,6 +1419,21 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX ,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1595,6 +1618,9 @@
 	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
@@ -2596,6 +2622,8 @@
 	SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
 						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback",
+						0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback",
 			     0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
@@ -2606,6 +2634,8 @@
 						0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
 			    0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
+						0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
 			    0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -2681,6 +2711,9 @@
 	SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 				quaternary_mi2s_rx_mixer_controls,
 				ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tertiary_mi2s_rx_mixer_controls,
+				ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 			   secondary_mi2s_rx_mixer_controls,
 			   ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
@@ -2872,6 +2905,11 @@
 	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
 
+	{"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"},
 
 	{"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2895,6 +2933,7 @@
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia5 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
@@ -3093,7 +3132,7 @@
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
 	{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
 	{"PCM_RX", NULL, "PCM_RX_DL_HL"},
-	{"MI2S_UL_HL", NULL, "MI2S_TX"},
+	{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
 	{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
 	{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
 	{"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
@@ -3163,6 +3202,7 @@
 	{"BE_OUT", NULL, "HDMI"},
 	{"BE_OUT", NULL, "MI2S_RX"},
 	{"BE_OUT", NULL, "QUAT_MI2S_RX"},
+	{"BE_OUT", NULL, "TERT_MI2S_RX"},
 	{"BE_OUT", NULL, "SEC_MI2S_RX"},
 	{"BE_OUT", NULL, "PRI_MI2S_RX"},
 	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
@@ -3183,6 +3223,7 @@
 	{"MI2S_TX", NULL, "BE_IN"},
 	{"QUAT_MI2S_TX", NULL, "BE_IN"},
 	{"PRI_MI2S_TX", NULL, "BE_IN"},
+	{"TERT_MI2S_TX", NULL, "BE_IN"},
 	{"SEC_MI2S_TX", NULL, "BE_IN"},
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
@@ -3243,8 +3284,10 @@
 	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) {
-			adm_close(bedai->port_id);
+			adm_close(bedai->port_id,
+				test_bit(i, &(bedai->perf_mode)));
 			srs_port_id = -1;
+			clear_bit(i, &(bedai->perf_mode));
 			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
 				dolby_dap_deinit(bedai->port_id);
 		}
@@ -3253,7 +3296,6 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
-	bedai->perf_mode = false;
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -3268,6 +3310,7 @@
 	u32 channels;
 	bool playback, capture;
 	uint16_t bits_per_sample = 16;
+	bool perf_mode = false;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3306,11 +3349,13 @@
 				bits_per_sample = 24;
 
 			if ((playback) && (channels > 0)) {
+				perf_mode = test_bit(i, &(bedai->perf_mode));
 				adm_multi_ch_copp_open(bedai->port_id,
 					path_type,
 					bedai->sample_rate,
 					channels,
-					topology, bedai->perf_mode,
+					topology,
+					perf_mode,
 					bits_per_sample);
 			} else if (capture) {
 				adm_open(bedai->port_id,
@@ -3322,7 +3367,8 @@
 			}
 
 			msm_pcm_routing_build_matrix(i,
-				fe_dai_map[i][session_type], path_type);
+				fe_dai_map[i][session_type], path_type,
+				perf_mode);
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1bd3eac..29c06cb 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -39,6 +39,9 @@
 	void *apr;
 	atomic_t copp_id[AFE_MAX_PORTS];
 	atomic_t copp_cnt[AFE_MAX_PORTS];
+	atomic_t copp_low_latency_id[AFE_MAX_PORTS];
+	atomic_t copp_low_latency_cnt[AFE_MAX_PORTS];
+	atomic_t copp_perf_mode[AFE_MAX_PORTS];
 	atomic_t copp_stat[AFE_MAX_PORTS];
 	wait_queue_head_t wait[AFE_MAX_PORTS];
 
@@ -445,7 +448,12 @@
 			for (i = 0; i < AFE_MAX_PORTS; i++) {
 				atomic_set(&this_adm.copp_id[i],
 							RESET_COPP_ID);
+				atomic_set(&this_adm.copp_low_latency_id[i],
+							RESET_COPP_ID);
 				atomic_set(&this_adm.copp_cnt[i], 0);
+				atomic_set(&this_adm.copp_low_latency_cnt[i],
+						0);
+				atomic_set(&this_adm.copp_perf_mode[i], 0);
 				atomic_set(&this_adm.copp_stat[i], 0);
 			}
 			this_adm.apr = NULL;
@@ -545,7 +553,13 @@
 				wake_up(&this_adm.wait[index]);
 				break;
 			}
-			atomic_set(&this_adm.copp_id[index], open->copp_id);
+			if (atomic_read(&this_adm.copp_perf_mode[index])) {
+				atomic_set(&this_adm.copp_low_latency_id[index],
+						open->copp_id);
+			} else {
+				atomic_set(&this_adm.copp_id[index],
+					open->copp_id);
+			}
 			atomic_set(&this_adm.copp_stat[index], 1);
 			pr_debug("%s: coppid rxed=%d\n", __func__,
 							open->copp_id);
@@ -892,8 +906,8 @@
 	int index;
 	int tmp_port = q6audio_get_port_id(port_id);
 
-	pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
-				port_id, path, rate, channel_mode);
+	pr_debug("%s: port %#x path:%d rate:%d mode:%d perf_mode:%d\n",
+		 __func__, port_id, path, rate, channel_mode, perf_mode);
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 
@@ -916,11 +930,19 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 
-	send_adm_custom_topology(port_id);
+	if (!perf_mode) {
+		atomic_set(&this_adm.copp_perf_mode[index], 0);
+		send_adm_custom_topology(port_id);
+	} else {
+		atomic_set(&this_adm.copp_perf_mode[index], 1);
+	}
 
 	/* Create a COPP if port id are not enabled */
-	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
-
+	if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+		(perf_mode &&
+		(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
+		pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
+			perf_mode);
 		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 		open.hdr.pkt_size = sizeof(open);
@@ -950,6 +972,9 @@
 			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 
+		if (perf_mode)
+			open.topology_id = NULL_COPP_TOPOLOGY;
+
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
 		open.sample_rate  = rate;
@@ -1026,7 +1051,15 @@
 			goto fail_cmd;
 		}
 	}
-	atomic_inc(&this_adm.copp_cnt[index]);
+	if (perf_mode) {
+		atomic_inc(&this_adm.copp_low_latency_cnt[index]);
+		pr_debug("%s: index: %d coppid: %d", __func__, index,
+			atomic_read(&this_adm.copp_low_latency_id[index]));
+	} else {
+		atomic_inc(&this_adm.copp_cnt[index]);
+		pr_debug("%s: index: %d coppid: %d", __func__, index,
+			atomic_read(&this_adm.copp_id[index]));
+	}
 	return 0;
 
 fail_cmd:
@@ -1046,7 +1079,7 @@
 }
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-			unsigned int *port_id, int copp_id)
+			unsigned int *port_id, int copp_id, bool perf_mode)
 {
 	struct adm_cmd_matrix_map_routings_v5	*route;
 	struct adm_session_map_node_v5 *node;
@@ -1085,7 +1118,12 @@
 	route->hdr.src_port = copp_id;
 	route->hdr.dest_svc = APR_SVC_ADM;
 	route->hdr.dest_domain = APR_DOMAIN_ADSP;
-	route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	if (perf_mode) {
+		route->hdr.dest_port =
+			atomic_read(&this_adm.copp_low_latency_id[index]);
+	} else {
+		route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	}
 	route->hdr.token = copp_id;
 	route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
 	route->num_sessions = 1;
@@ -1117,9 +1155,14 @@
 		tmp = q6audio_get_port_index(port_id[i]);
 
 
-		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
-			copps_list[i] =
+		if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+			if (perf_mode)
+				copps_list[i] =
+				atomic_read(&this_adm.copp_low_latency_id[tmp]);
+			else
+				copps_list[i] =
 					atomic_read(&this_adm.copp_id[tmp]);
+		}
 		else
 			continue;
 		pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
@@ -1144,21 +1187,42 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	for (i = 0; i < num_copps; i++)
-		send_adm_cal(port_id[i], path);
+	if (perf_mode) {
+		for (i = 0; i < num_copps; i++) {
+			int tmp;
 
-	for (i = 0; i < num_copps; i++) {
-		int tmp;
-		tmp = afe_get_port_index(port_id[i]);
-		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
-			rtac_add_adm_device(port_id[i],
-				atomic_read(&this_adm.copp_id[tmp]),
-				path, session_id);
-		else
-			pr_debug("%s: Invalid port index %d",
-				__func__, tmp);
+			tmp = afe_get_port_index(port_id[i]);
+			if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+				rtac_add_adm_device(port_id[i], atomic_read(
+					&this_adm.copp_low_latency_id[tmp]),
+					path, session_id);
+				pr_debug("%s, copp_id: %d\n", __func__,
+					atomic_read(
+					&this_adm.copp_low_latency_id[tmp]));
+			} else {
+				pr_debug("%s: Invalid port index %d",
+					__func__, tmp);
+			}
+		}
+	} else {
+		for (i = 0; i < num_copps; i++)
+			send_adm_cal(port_id[i], path);
+
+		for (i = 0; i < num_copps; i++) {
+			int tmp;
+			tmp = afe_get_port_index(port_id[i]);
+			if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+				rtac_add_adm_device(port_id[i],
+					atomic_read(&this_adm.copp_id[tmp]),
+					path, session_id);
+				pr_debug("%s, copp_id: %d\n", __func__,
+					atomic_read(&this_adm.copp_id[tmp]));
+			} else {
+				pr_debug("%s: Invalid port index %d",
+					__func__, tmp);
+			}
+		}
 	}
-
 fail_cmd:
 	kfree(matrix_map);
 	return ret;
@@ -1319,7 +1383,7 @@
 	return atomic_read(&this_adm.copp_id[port_index]);
 }
 
-int adm_close(int port_id)
+int adm_close(int port_id, bool perf_mode)
 {
 	struct apr_hdr close;
 
@@ -1332,16 +1396,30 @@
 	if (q6audio_validate_port(port_id) < 0)
 		return -EINVAL;
 
-	pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
+	pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
+		index, perf_mode);
 
-	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
-		pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
-
-		goto fail_cmd;
+	if (perf_mode) {
+		if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
+			pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+				port_id);
+			goto fail_cmd;
+		}
+		atomic_dec(&this_adm.copp_low_latency_cnt[index]);
+	} else {
+		if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+			pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+				port_id);
+			goto fail_cmd;
+		}
+		atomic_dec(&this_adm.copp_cnt[index]);
 	}
-	atomic_dec(&this_adm.copp_cnt[index]);
-	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+	if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
+		(perf_mode &&
+		!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
 
+		pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
+				perf_mode);
 		close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 		close.pkt_size = sizeof(close);
@@ -1350,19 +1428,33 @@
 		close.src_port = port_id;
 		close.dest_svc = APR_SVC_ADM;
 		close.dest_domain = APR_DOMAIN_ADSP;
-		close.dest_port = atomic_read(&this_adm.copp_id[index]);
+		if (perf_mode)
+			close.dest_port =
+			     atomic_read(&this_adm.copp_low_latency_id[index]);
+		else
+			close.dest_port = atomic_read(&this_adm.copp_id[index]);
 		close.token = port_id;
 		close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
 
-		atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
 		atomic_set(&this_adm.copp_stat[index], 0);
 
-
-		pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+		if (perf_mode) {
+			pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+			    __func__,
+			    atomic_read(&this_adm.copp_low_latency_id[index]),
+			    port_id, index,
+			    atomic_read(&this_adm.copp_low_latency_cnt[index]));
+			atomic_set(&this_adm.copp_low_latency_id[index],
+				RESET_COPP_ID);
+		} else {
+			pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
 				__func__,
 				atomic_read(&this_adm.copp_id[index]),
 				port_id, index,
 				atomic_read(&this_adm.copp_cnt[index]));
+			atomic_set(&this_adm.copp_id[index],
+				RESET_COPP_ID);
+		}
 
 		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
 		if (ret < 0) {
@@ -1380,7 +1472,10 @@
 			ret = -EINVAL;
 			goto fail_cmd;
 		}
-
+	}
+	if (!atomic_read(&this_adm.copp_cnt[index]) &&
+		!atomic_read(&this_adm.copp_low_latency_cnt[index])) {
+		pr_debug("%s: remove adm device from rtac\n", __func__);
 		rtac_remove_adm_device(port_id);
 	}
 
@@ -1396,8 +1491,11 @@
 
 	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_low_latency_id[i], RESET_COPP_ID);
 		atomic_set(&this_adm.copp_cnt[i], 0);
+		atomic_set(&this_adm.copp_low_latency_cnt[i], 0);
 		atomic_set(&this_adm.copp_stat[i], 0);
+		atomic_set(&this_adm.copp_perf_mode[i], 0);
 		init_waitqueue_head(&this_adm.wait[i]);
 	}
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5b4244e..ce5e816 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -1341,6 +1341,10 @@
 		return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 		return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+		 return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+	case AFE_PORT_ID_TERTIARY_MI2S_TX:
+		 return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
 
 	default: return -EINVAL;
 	}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 59d4de2..af8e873 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -45,17 +45,6 @@
 
 #define TRUE        0x01
 #define FALSE       0x00
-#define READDONE_IDX_STATUS 0
-#define READDONE_IDX_BUFADD_LSW 1
-#define READDONE_IDX_BUFADD_MSW 2
-#define READDONE_IDX_MEMMAP_HDL 3
-#define READDONE_IDX_SIZE 4
-#define READDONE_IDX_OFFSET 5
-#define READDONE_IDX_LSW_TS 6
-#define READDONE_IDX_MSW_TS 7
-#define READDONE_IDX_FLAGS 8
-#define READDONE_IDX_NUMFRAMES 9
-#define READDONE_IDX_SEQ_ID 10
 
 /* TODO, combine them together */
 static DEFINE_MUTEX(session_lock);
@@ -3371,6 +3360,7 @@
 	struct list_head *ptr, *next;
 	u32 lbuf_addr_lsw;
 	u32 liomode;
+	u32 io_compressed;
 
 	if (!ac || ac->apr == NULL) {
 		pr_err("%s: APR handle NULL\n", __func__);
@@ -3387,12 +3377,15 @@
 	read.buf_size = param->len;
 	read.seq_id = param->uid;
 	liomode = (NT_MODE | ASYNC_IO_MODE);
+	io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
 	if (ac->io_mode == liomode)
 		lbuf_addr_lsw = (read.buf_addr_lsw - 32);
+	else if (ac->io_mode == io_compressed)
+		lbuf_addr_lsw = (read.buf_addr_lsw - 64);
 	else
 		lbuf_addr_lsw = read.buf_addr_lsw;
 
-	list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+	list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node, list);
 			if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
 				read.mem_map_handle = buf_node->mmap_hdl;
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index dae1ebd..bc7ad4d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -70,6 +70,10 @@
 		return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 		return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+		return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+	case AFE_PORT_ID_TERTIARY_MI2S_TX:
+		return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
 
 	default: return -EINVAL;
 	}
@@ -126,7 +130,10 @@
 			     return AFE_PORT_ID_SECONDARY_MI2S_RX;
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 			     return AFE_PORT_ID_SECONDARY_MI2S_TX;
-
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+			     return AFE_PORT_ID_TERTIARY_MI2S_RX;
+	case AFE_PORT_ID_TERTIARY_MI2S_TX:
+			     return AFE_PORT_ID_TERTIARY_MI2S_TX;
 	default:
 		pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
 		return -EINVAL;