Merge "ASoC: msm: Add FE DAI for QCHAT"
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 195a98d..f57d928 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -3,10 +3,8 @@
 The application processor in MSM can do a variety of C-States for low power
 management. These C-States are invoked by the CPUIdle framework when the core
 becomes idle. But based on the time available until the next scheduled wakeup,
-the system can do a combination of low power modes of different resources -
-L2, XO, Vdd Dig and Vdd Mem. The combination is captured in the device tree as
-lpm-level. The units for voltage are dependent on the PMIC used on the target
-and are in uV.
+the system can do several low power modes. The combination is captured in the
+device tree as lpm-level.
 
 The required nodes for lpm-levels are:
 
@@ -20,20 +18,11 @@
 		"retention" - Retention
 		"pc_suspend" - Suspended Power Collapse
 		"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
-- qcom,xo: The state of XO clock. Values are "xo_on" and "xo_off"
 - qcom,l2: The state of L2 cache. Values are:
 		"l2_cache_pc" - L2 cache in power collapse
 		"l2_cache_retenetion" - L2 cache in retention
 		"l2_cache_gdhs" - L2 cache in GDHS
 		"l2_cache_active" - L2 cache in active mode
-- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
-- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
-- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
-                            or an RBCPR (Rapid Bridge Core Power Reduction)
-                            corner voltage.
-- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
-                            or an RBCPR (Rapid Bridge Core Power Reduction)
-                            corner voltage.
 - qcom,latency-us: The latency in handling the interrupt if this level was
 	chosen, in uSec
 - qcom,ss-power: The steady state power expelled when the processor is in this
@@ -42,29 +31,18 @@
 	in mWatts.uSec
 - qcom,time-overhead: The time spent in entering and exiting this level in uS
 
-Optional properties
-- qcom,irqs-detectable: The field indicates whether the IRQs are detectable by
-			the GIC controller when entering a low power mode.
-- qcom,gpio-detectable: The field indicates whether the GPIOs can be detected
-			by the GPIO interrupt controller during a given low
-			power mode.
-- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
+The optional nodes for lpm-levels are :
+-  qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
+-  qcom,default-l2-state: Indicates what the default low power state of the L2 SAW should be. This property is used only when there is an L2 SAW.
 
 Example:
 
 qcom,lpm-levels {
-	qcom,use-qtimer;
+	qcom,no-l2-saw;
 	qcom,lpm-level@0 {
 		reg = <0>;
 		qcom,mode = "wfi";
-		qcom,xo = "xo_on";
 		qcom,l2 = "l2_cache_active";
-		qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-		qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-		qcom,vdd-dig-upper-bound = <5>; /* MAX */
-		qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-		qcom,irqs-detectable;
-		qcom,gpio-detectable;
 		qcom,latency-us = <100>;
 		qcom,ss-power = <650>;
 		qcom,energy-overhead = <801>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
deleted file mode 100644
index 7b5fda3..0000000
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-* Low Power Management Resources
-
-The application processor in the MSM can enter several different low power
-states depending on the sleep time and on the required system resources. The
-MSM cannot enter a given low power state if that state involves turning off
-some shared resources which are required by some components of the
-system.The lpm-resources device tree node represents the shared resources
-that need to be monitored for usage requirement to check if a given low power
-state can be entered.Each resource is identified by a combination of the name,
-id,type and key which is also used by the RPM to identify a shared resource.
-The name and resource-type are required nodes; the type, id and key are
-optional nodes which are needed if the resource type is RPM shared resource
-(MSM_LPM_RPM_RS_TYPE).
-
-The nodes for lpm-resources are:
-
-Required Nodes:
-
-- compatible: "qcom,lpm-resources"
-- reg: The numeric level id
-- qcom,name: The name of the low power resource represented
-             as a string.
-- qcom,init-value: Initialization value of the LPM resource represented as
-			decimal value for vdd-dig and vdd-mem resources and
-			as string for pxo and l2 resources.
-
-
-Optional Nodes:
-
-- qcom,type: The type of resource used like smps or pxo
-             represented as a hex value.
-- qcom,id: The id representing a device within a resource type.
-- qcom,key: The key is the specific attribute of the resource being
-            monitored represented as a hex value.
-- qcom,local-resource-type: The property exists only for locally managed
-				resource and is represented as a bool.
-
-Example:
-            qcom,lpm-resources@0 {
-                        reg = <0x0>;
-                        qcom,name = "vdd-dig";
-                        qcom,type = <0x62706d73>;   /* "smpb" */
-                        qcom,id = <0x02>;
-                        qcom,key = <0x6e726f63>;   /* "corn" */
-			qcom,init-value= <5>;   /* Active Corner*/
-                };
-
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index d24e671..7f7ee25 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -118,6 +118,12 @@
 - 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
+- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
+			  the device. Only relevant in case of tmc-etr device.
+- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
+		spi/ppi, b is the interrupt number and c is the mask,
+- interrupt-names : a list of strings that map in order to the list of
+		    interrupts specified in the 'interrupts' property.
 
 Examples:
 
@@ -128,6 +134,11 @@
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
 
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
+
+		qcom,byte-cntr-absent;
+
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 0f35e73..3720172 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -20,6 +20,7 @@
  - synaptics,panel-x		: panel x dimension
  - synaptics,panel-y		: panel y dimension
  - synaptics,fw-image-name	: name of firmware .img file in /etc/firmware
+ - synaptics,power-down		: fully power down regulators in suspend
 
 Example:
 	i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 7acb1fe..d94b41d 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -35,6 +35,7 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
 		};
 	};
 
@@ -75,7 +76,7 @@
 			compatible = "micrel,ks8851";
 			reg = <3>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
+			interrupts = <115 0x8>;
 			spi-max-frequency = <4800000>;
 			rst-gpio = <&msmgpio 114 0>;
 			vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 11f6369..cbfdfc9 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -16,6 +16,8 @@
 		reg = <0xfc322000 0x1000>,
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
 
 		qcom,memory-reservation-type = "EBI1";
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index ddb61bc..825e853 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -35,6 +35,7 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
 		};
 	};
 
@@ -86,7 +87,7 @@
 			compatible = "micrel,ks8851";
 			reg = <3>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
+			interrupts = <115 0x8>;
 			spi-max-frequency = <4800000>;
 			rst-gpio = <&msmgpio 114 0>;
 			vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 0fc6af4..ef0a55e 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -101,62 +101,16 @@
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
 	};
 
-	qcom,lpm-resources {
-		compatible = "qcom,lpm-resources";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-resources@0 {
-			reg = <0x0>;
-			qcom,name = "vdd-dig";
-			qcom,type = <0x61706d73>;	/* "smpa" */
-			qcom,id = <0x01>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* SVS SOC */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,type = <0x616F646C>;	/* "ldoa" */
-			qcom,id = <0x03>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* SVS SOC */
-		};
-
-		qcom,lpm-resources@2 {
-			reg = <0x2>;
-			qcom,name = "pxo";
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = "xo_on";
-		};
-
-		qcom,lpm-resources@3 {
-			reg = <0x3>;
-			qcom,name = "l2";
-			qcom,local-resource-type;
-			qcom,init-value = "l2_cache_active";
-		};
-	};
-
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
 		#size-cells = <0>;
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = "wfi";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			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>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
 		qcom,lpm-level@1 {
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			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>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_retention";
-			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>;
+			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
 			qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			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>;
+			qcom,latency-us = <30000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
 			qcom,time-overhead = <9500>;
 		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <24200>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <33000>;
-		};
-
-		qcom,lpm-level@6 {
-			reg = <0x6>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <38000>;
-		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 9bf37af..55d8691 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -31,6 +31,7 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
 		};
 		focaltech@38 {
 			compatible = "focaltech,5x06";
@@ -98,7 +99,7 @@
 			compatible = "micrel,ks8851";
 			reg = <3>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
+			interrupts = <115 0x8>;
 			spi-max-frequency = <4800000>;
 			rst-gpio = <&msmgpio 114 0>;
 			vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index c531740..d31a65c 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -101,62 +101,16 @@
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
 	};
 
-	qcom,lpm-resources {
-		compatible = "qcom,lpm-resources";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-resources@0 {
-			reg = <0x0>;
-			qcom,name = "vdd-dig";
-			qcom,type = <0x61706d73>;	/* "smpa" */
-			qcom,id = <0x01>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* SVS SOC */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,type = <0x616F646C>;	/* "ldoa" */
-			qcom,id = <0x03>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <3>;		/* SVS SOC */
-		};
-
-		qcom,lpm-resources@2 {
-			reg = <0x2>;
-			qcom,name = "pxo";
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = "xo_on";
-		};
-
-		qcom,lpm-resources@3 {
-			reg = <0x3>;
-			qcom,name = "l2";
-			qcom,local-resource-type;
-			qcom,init-value = "l2_cache_active";
-		};
-	};
-
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
 		#size-cells = <0>;
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = "wfi";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			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>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
 		qcom,lpm-level@1 {
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			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>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_retention";
-			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>;
+			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
 			qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			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>;
+			qcom,latency-us = <30000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
 			qcom,time-overhead = <9500>;
 		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <24200>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <33000>;
-		};
-
-		qcom,lpm-level@6 {
-			reg = <0x6>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			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>;
-			qcom,time-overhead = <38000>;
-		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
index 220f642..aeaf8ca 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
@@ -40,3 +40,8 @@
         qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
     };
 };
+
+&pm8110_bms {
+	status = "ok";
+	qcom,batt-type = <5>;
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index e41adac..9fd0cd9 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -16,6 +16,8 @@
 		reg = <0xfc322000 0x1000>,
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
 
 		qcom,memory-reservation-type = "EBI1";
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 288a703..7362b64 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -129,64 +129,16 @@
 				50 02 32 50 0f];
 	};
 
-	qcom,lpm-resources {
-		compatible = "qcom,lpm-resources";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-resources@0 {
-			reg = <0x0>;
-			qcom,name = "vdd-dig";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x02>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <6>;		/* Super Turbo */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x01>;
-			qcom,key = <0x7675>;		/* "uv" */
-			qcom,init-value = <1050000>;	/* Super Turbo */
-		};
-
-		qcom,lpm-resources@2 {
-			reg = <0x2>;
-			qcom,name = "pxo";
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = "xo_on";
-		};
-
-		qcom,lpm-resources@3 {
-			reg = <0x3>;
-			qcom,name = "l2";
-			qcom,local-resource-type;
-			qcom,init-value = "l2_cache_retention";
-		};
-	};
-
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,use-qtimer;
-
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = "wfi";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -196,14 +148,7 @@
 		qcom,lpm-level@1 {
 			reg = <0x1>;
 			qcom,mode = "retention";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <75>;
 			qcom,ss-power = <735>;
 			qcom,energy-overhead = <77341>;
@@ -214,14 +159,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <95>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -231,15 +169,8 @@
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <2000>;
+			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
 			qcom,time-overhead = <3200>;
@@ -248,79 +179,12 @@
 		qcom,lpm-level@4 {
 			reg = <0x4>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
-			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
-			qcom,irqs-detectable;
-			qcom,gpio-detectable;
-			qcom,latency-us = <3000>;
+			qcom,latency-us = <30000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
 			qcom,time-overhead = <3500>;
 		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <68>;
-			qcom,energy-overhead = <1350200>;
-			qcom,time-overhead = <4000>;
-		};
-
-		qcom,lpm-level@6 {
-			reg = <0x6>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,latency-us = <10300>;
-			qcom,ss-power = <63>;
-			qcom,energy-overhead = <2128000>;
-			qcom,time-overhead = <18200>;
-		};
-
-		qcom,lpm-level@7 {
-			reg = <0x7>;
-			qcom,mode= "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
-			qcom,latency-us = <18000>;
-			qcom,ss-power = <10>;
-			qcom,energy-overhead = <3202600>;
-			qcom,time-overhead = <27000>;
-		};
-
-		qcom,lpm-level@8 {
-			reg = <0x8>;
-			qcom,mode= "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
-			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
-			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
-			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <2>;
-			qcom,energy-overhead = <4252000>;
-			qcom,time-overhead = <32000>;
-		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index cfacac6..7b801da 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -65,6 +65,7 @@
 /* CoreSight */
 &tmc_etr {
 	qcom,reset-flush-race;
+	qcom,byte-cntr-absent;
 };
 
 &stm {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 03f7e80..5efa17d 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -42,14 +42,14 @@
 				0x2034
 				0x2038>;
 
-	qcom,iommu-bfb-data =  <0xFFFFFFFF
-				0xFFFFFFFF
-				0x00000004
-				0x00000008
-				0x00000000
-				0x00013205
-				0x00004000
-				0x00014020
+	qcom,iommu-bfb-data =  <0xffffffff
+				0xffffffff
+				0x4
+				0x8
+				0x0
+				0x13205
+				0x4000
+				0x14020
 				0x0
 				0x94
 				0x114
@@ -116,8 +116,8 @@
 				0x2010
 				0x2014>;
 
-	qcom,iommu-bfb-data =  <0x3FFF
-				0x00000000
+	qcom,iommu-bfb-data =  <0xffff
+				0x0
 				0x4
 				0x4
 				0x0
@@ -125,8 +125,8 @@
 				0x10
 				0x50
 				0x0
-				0x00002804
-				0x00009614
+				0x2804
+				0x9614
 				0x0
 				0x0
 				0x0
@@ -157,14 +157,14 @@
 				0x201c
 				0x2020>;
 
-	qcom,iommu-bfb-data =  <0xFFFFF
-				0x00000000
-				0x00000004
-				0x00000010
-				0x00000000
-				0x00006800
-				0x00006221
-				0x00016231
+	qcom,iommu-bfb-data =  <0xffffffff
+				0x0
+				0x4
+				0x10
+				0x0
+				0x6800
+				0x6221
+				0x16231
 				0x0
 				0x34
 				0x74
@@ -197,14 +197,14 @@
 				0x2414
 				0x2008>;
 
-	qcom,iommu-bfb-data =  <0x00000003
+	qcom,iommu-bfb-data =  <0x3
 				0x0
-				0x00000004
-				0x00000010
-				0x00000000
-				0x00000000
-				0x00000000
-				0x00000020
+				0x4
+				0x10
+				0x0
+				0x0
+				0x0
+				0x20
 				0x0
 				0x1
 				0x81
@@ -236,7 +236,7 @@
 				0x2020>;
 
 	qcom,iommu-bfb-data =  <0xffffffff
-				0x00000000
+				0x0
 				0x4
 				0x8
 				0x0
@@ -244,8 +244,8 @@
 				0x20
 				0x78
 				0x0
-				0x00003c08
-				0x0000b41e
+				0x3c08
+				0xb41e
 				0x0
 				0x0
 				0x0
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index a162bb7..1235c6e 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -125,64 +125,16 @@
 				50 02 32 50 0f];
 	};
 
-	qcom,lpm-resources {
-		compatible = "qcom,lpm-resources";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-resources@0 {
-			reg = <0x0>;
-			qcom,name = "vdd-dig";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x02>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <6>;		/* Super Turbo */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x01>;
-			qcom,key = <0x7675>;		/* "uv" */
-			qcom,init-value = <1050000>;	/* Super Turbo */
-		};
-
-		qcom,lpm-resources@2 {
-			reg = <0x2>;
-			qcom,name = "pxo";
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = "xo_on";
-		};
-
-		qcom,lpm-resources@3 {
-			reg = <0x3>;
-			qcom,name = "l2";
-			qcom,local-resource-type;
-			qcom,init-value = "l2_cache_retention";
-		};
-	};
-
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,use-qtimer;
-
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = "wfi";
-			qcom,xo = "xo_on";
-			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,irqs-detectable;
-			qcom,gpio-detectable;
+			qcom,l2 = "l2_cache_retention";
 			qcom,latency-us = <1>;
 			qcom,ss-power = <715>;
 			qcom,energy-overhead = <17700>;
@@ -192,14 +144,7 @@
 		qcom,lpm-level@1 {
 			reg = <0x1>;
 			qcom,mode = "retention";
-			qcom,xo = "xo_on";
-			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,irqs-detectable;
-			qcom,gpio-detectable;
+			qcom,l2 = "l2_cache_retention";
 			qcom,latency-us = <35>;
 			qcom,ss-power = <542>;
 			qcom,energy-overhead = <34920>;
@@ -210,14 +155,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
-			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,irqs-detectable;
-			qcom,gpio-detectable;
+			qcom,l2 = "l2_cache_retention";
 			qcom,latency-us = <300>;
 			qcom,ss-power = <476>;
 			qcom,energy-overhead = <225300>;
@@ -227,32 +165,19 @@
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <300>;
+			qcom,latency-us = <320>;
 			qcom,ss-power = <476>;
 			qcom,energy-overhead = <225300>;
-			qcom,time-overhead = <350>;
+			qcom,time-overhead = <375>;
 		};
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <2817>;
+			qcom,latency-us = <20000>;
 			qcom,ss-power = <163>;
 			qcom,energy-overhead = <1577736>;
 			qcom,time-overhead = <5067>;
@@ -261,64 +186,12 @@
 		qcom,lpm-level@5 {
 			reg = <0x5>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
-			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
-			qcom,irqs-detectable;
-			qcom,gpio-detectable;
-			qcom,latency-us = <3922>;
+			qcom,latency-us = <30000>;
 			qcom,ss-power = <83>;
 			qcom,energy-overhead = <2274420>;
 			qcom,time-overhead = <6605>;
 		};
-
-		qcom,lpm-level@6 {
-			reg = <0x6>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,latency-us = <4922>;
-			qcom,ss-power = <68>;
-			qcom,energy-overhead = <2568180>;
-			qcom,time-overhead = <8812>;
-		};
-
-		qcom,lpm-level@7 {
-			reg = <0x7>;
-			qcom,mode= "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
-			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
-			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
-			qcom,latency-us = <5890>;
-			qcom,ss-power = <60>;
-			qcom,energy-overhead = <2675900>;
-			qcom,time-overhead = <10140>;
-		};
-
-		qcom,lpm-level@8 {
-			reg = <0x8>;
-			qcom,mode= "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
-			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
-			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
-			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
-			qcom,latency-us = <8500>;
-			qcom,ss-power = <18>;
-			qcom,energy-overhead = <3286600>;
-			qcom,time-overhead = <15760>;
-		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 60472c8..4a903b7 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -16,6 +16,8 @@
 		reg = <0xfc322000 0x1000>,
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
 
 		qcom,memory-reservation-type = "EBI1";
 		qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index e18e143..7989f2b 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -28,57 +28,16 @@
 		3e 0f];
 	};
 
-	qcom,lpm-resources {
-		compatible = "qcom,lpm-resources";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-resources@0 {
-			reg = <0x0>;
-			qcom,name = "vdd-dig";
-			qcom,type = <0x616F646C>;       /* "ldoa" */
-			qcom,id = <0x0A>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,type = <0x616F646C>;       /* "ldoa" */
-			qcom,id = <0x0C>;
-			qcom,key =  <0x7675>;		/* "uv" */
-			qcom,init-value = <1050000>;	/* Super Turbo */
-		};
-
-		qcom,lpm-resources@2 {
-			reg = <0x2>;
-			qcom,name = "pxo";
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = "xo_on";
-		};
-	};
-
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,no-l2-saw;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,use-qtimer;
-
 		qcom,lpm-level@0 {
 			reg = <0x0>;
 			qcom,mode = "wfi";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <100>;
 			qcom,ss-power = <8000>;
 			qcom,energy-overhead = <100000>;
@@ -88,14 +47,7 @@
 		qcom,lpm-level@1 {
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_active";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <2000>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60100000>;
@@ -105,15 +57,8 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <3500>;
+			qcom,latency-us = <20000>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60350000>;
 			qcom,time-overhead = <6300>;
@@ -122,66 +67,12 @@
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
-			qcom,xo = "xo_on";
 			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* 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 = <4500>;
+			qcom,latency-us = <30000>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60350000>;
 			qcom,time-overhead = <7300>;
 		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
-			qcom,irqs-detectable;
-			qcom,latency-us = <6800>;
-			qcom,ss-power = <2000>;
-			qcom,energy-overhead = <71850000>;
-			qcom,time-overhead = <13300>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
-			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
-			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
-			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
-			qcom,irqs-detectable;
-			qcom,latency-us = <8000>;
-			qcom,ss-power = <1800>;
-			qcom,energy-overhead = <71950000>;
-			qcom,time-overhead = <15300>;
-		};
-
-		qcom,lpm-level@6 {
-			reg = <0x6>;
-			qcom,mode = "pc";
-			qcom,xo = "xo_off";
-			qcom,l2 = "l2_cache_pc";
-			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
-			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
-			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
-			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
-			qcom,latency-us = <9800>;
-			qcom,ss-power = <0>;
-			qcom,energy-overhead = <76350000>;
-			qcom,time-overhead = <28300>;
-		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index b238ba5..daf774b 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -48,6 +48,7 @@
 /* CoreSight */
 &tmc_etr {
 	qcom,reset-flush-race;
+	qcom,byte-cntr-absent;
 };
 
 &stm {
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 3549307..fef6543 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -52,6 +52,8 @@
 CONFIG_MSM_RPM_REGULATOR_SMD=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_VENUS=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 7615eb2..f49b5f7 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -223,6 +223,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_PPP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 7b2d38b..aced8f2 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -225,6 +225,7 @@
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
+CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_PPP=y
@@ -458,6 +459,7 @@
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2a8bc91..cfd346e 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -422,6 +422,7 @@
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8447dd55..0c28cc4 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -499,6 +499,7 @@
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 10e580b..b80949c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -282,7 +282,6 @@
 	select QMI_ENCDEC
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_ULTRASOUND_B
-	select MSM_LPM_TEST
 	select MSM_RPM_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 
@@ -307,6 +306,10 @@
 	select MEMORY_HOLE_CARVEOUT
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select QMI_ENCDEC
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
+	select MSM_RPM_SMD
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
@@ -430,6 +433,7 @@
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MEMORY_HOLE_CARVEOUT
+	select QMI_ENCDEC
 
 config ARCH_MSM8610
 	bool "MSM8610"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 56fb625..8c42b8d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -331,7 +331,7 @@
 obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
 obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
 obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
-obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o lpm_resources.o
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
 obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
 obj-$(CONFIG_MSM_MPM) += mpm.o
 obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 2a6bbb7..8f35a29 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -29,6 +29,8 @@
 #include <mach/socinfo.h>
 #include <mach/clk-provider.h>
 #include <mach/msm_smem.h>
+#include <mach/rpm-smd.h>
+#include "spm.h"
 #include "board-dt.h"
 #include "clock.h"
 #include "devices.h"
@@ -88,6 +90,8 @@
 	msm_smem_init();
 	msm_init_modem_notifier_list();
 	msm_smd_init();
+	msm_rpm_driver_init();
+	msm_spm_device_init();
 	msm_clock_init(&msm8084_clock_init_data);
 	tsens_tm_init_driver();
 }
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 0d62b7a..aff2d75 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -51,7 +51,6 @@
 #include "platsmp.h"
 #include "spm.h"
 #include "pm.h"
-#include "lpm_resources.h"
 #include "modem_notifier.h"
 
 static struct memtype_reserve msm8226_reserve_table[] __initdata = {
@@ -116,7 +115,6 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_rpm_driver_init();
-	msm_lpmrs_module_init();
 	msm_spm_device_init();
 	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index f8ca143..01f1468 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -531,7 +531,8 @@
 	}
 	msm_gpiomux_install(wcnss_5wire_interface,
 			ARRAY_SIZE(wcnss_5wire_interface));
-	msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
+	msm_gpiomux_install_nowrite(msm_lcd_configs,
+				ARRAY_SIZE(msm_lcd_configs));
 	msm_gpiomux_install(msm_keypad_configs,
 				ARRAY_SIZE(msm_keypad_configs));
 	msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index c6c9d14..d175bb4 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -52,7 +52,6 @@
 #include "platsmp.h"
 #include "spm.h"
 #include "pm.h"
-#include "lpm_resources.h"
 #include "modem_notifier.h"
 
 static struct memtype_reserve msm8610_reserve_table[] __initdata = {
@@ -107,7 +106,6 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_rpm_driver_init();
-	msm_lpmrs_module_init();
 	msm_spm_device_init();
 	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 68af757..80a957f 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -45,8 +45,8 @@
 #include "clock.h"
 #include "devices.h"
 #include "spm.h"
+#include "pm.h"
 #include "modem_notifier.h"
-#include "lpm_resources.h"
 #include "platsmp.h"
 
 
@@ -96,7 +96,6 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_rpm_driver_init();
-	msm_lpmrs_module_init();
 	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 36ad755..058789a 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -42,7 +42,6 @@
 #include <mach/msm_smem.h>
 #include "clock.h"
 #include "modem_notifier.h"
-#include "lpm_resources.h"
 #include "spm.h"
 
 #define MSM_KERNEL_EBI_SIZE	0x51000
@@ -240,7 +239,6 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_rpm_driver_init();
-	msm_lpmrs_module_init();
 	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
 	msm_clock_init(&msm9625_clock_init_data);
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index be09b54..6133983 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -44,6 +44,8 @@
 	CLK_DUMMY("core_clk",	USB_HS_SYSTEM_CLK, "msm_otg", OFF),
 	CLK_DUMMY("iface_clk",	USB_HS_AHB_CLK,    "msm_otg", OFF),
 	CLK_DUMMY("xo",         CXO_OTG_CLK,       "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	"msm_sps", OFF),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	"msm_sps", OFF),
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index f52bc28..97b8448 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/proc_fs.h>
 #include <linux/cpu.h>
+#include <linux/seq_file.h>
 #include <linux/io.h>
 #include <mach/msm-krait-l2-accessors.h>
 #include <mach/msm_iomap.h>
@@ -159,25 +160,23 @@
 	return cesynr;
 }
 
-static int proc_read_status(char *page, char **start, off_t off, int count,
-			    int *eof, void *data)
+static int cache_erp_show(struct seq_file *m, void *v)
 {
 	struct msm_l1_err_stats *l1_stats;
-	char *p = page;
-	int len, cpu, ret, bytes_left = PAGE_SIZE;
+	int cpu;
 
 	for_each_present_cpu(cpu) {
 		l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
 
-		ret = snprintf(p, bytes_left,
-			"CPU %d:\n"	\
-			"\tD-cache tag parity errors:\t%u\n"	\
-			"\tD-cache data parity errors:\t%u\n"	\
-			"\tI-cache tag parity errors:\t%u\n"	\
-			"\tI-cache data parity errors:\t%u\n"	\
-			"\tD-cache timing errors:\t\t%u\n"	\
-			"\tI-cache timing errors:\t\t%u\n"	\
-			"\tTLB multi-hit errors:\t\t%u\n\n",	\
+		seq_printf(m,
+			"CPU %d:\n"
+			"\tD-cache tag parity errors:\t%u\n"
+			"\tD-cache data parity errors:\t%u\n"
+			"\tI-cache tag parity errors:\t%u\n"
+			"\tI-cache data parity errors:\t%u\n"
+			"\tD-cache timing errors:\t\t%u\n"
+			"\tI-cache timing errors:\t\t%u\n"
+			"\tTLB multi-hit errors:\t\t%u\n\n",
 			cpu,
 			l1_stats->dctpe,
 			l1_stats->dcdpe,
@@ -186,18 +185,16 @@
 			l1_stats->dcte,
 			l1_stats->icte,
 			l1_stats->tlbmh);
-		p += ret;
-		bytes_left -= ret;
 	}
 
-	p += snprintf(p, bytes_left,
-			"L2 master port decode errors:\t\t%u\n"	\
-			"L2 master port slave errors:\t\t%u\n"		\
-			"L2 tag soft errors, single-bit:\t\t%u\n"	\
-			"L2 tag soft errors, double-bit:\t\t%u\n"	\
-			"L2 data soft errors, single-bit:\t%u\n"	\
-			"L2 data soft errors, double-bit:\t%u\n"	\
-			"L2 modified soft errors:\t\t%u\n"		\
+	seq_printf(m,
+			"L2 master port decode errors:\t\t%u\n"
+			"L2 master port slave errors:\t\t%u\n"
+			"L2 tag soft errors, single-bit:\t\t%u\n"
+			"L2 tag soft errors, double-bit:\t\t%u\n"
+			"L2 data soft errors, single-bit:\t%u\n"
+			"L2 data soft errors, double-bit:\t%u\n"
+			"L2 modified soft errors:\t\t%u\n"
 			"L2 master port LDREX NOK errors:\t%u\n",
 			msm_l2_erp_stats.mpdcd,
 			msm_l2_erp_stats.mpslv,
@@ -208,16 +205,21 @@
 			msm_l2_erp_stats.mse,
 			msm_l2_erp_stats.mplxrexnok);
 
-	len = (p - page) - off;
-	if (len < 0)
-		len = 0;
-
-	*eof = (len <= count) ? 1 : 0;
-	*start = page + off;
-
-	return len;
+	return 0;
 }
 
+static int cache_erp_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cache_erp_show, NULL);
+}
+
+static const struct file_operations cache_erp_fops = {
+	.open		= cache_erp_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static int msm_erp_dump_regions(void)
 {
 	int i = 0;
@@ -235,26 +237,30 @@
 }
 
 #ifdef CONFIG_MSM_L1_ERR_LOG
-static int proc_read_log(char *page, char **start, off_t off, int count,
-	int *eof, void *data)
+static int cache_erp_log_show(struct seq_file *m, void *v)
 {
-	char *p = page;
-	int len, log_value;
+	int log_value;
+
 	log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
 			ERP_LOG_MAGIC ? 1 : 0;
 
-	p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+	seq_printf(m, "%d\n", log_value);
 
-	len = (p - page) - off;
-	if (len < 0)
-		len = 0;
-
-	*eof = (len <= count) ? 1 : 0;
-	*start = page + off;
-
-	return len;
+	return 0;
 }
 
+static int cache_erp_log_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cache_erp_log_show, NULL);
+}
+
+static const struct file_operations cache_erp_log_fops = {
+	.open		= cache_erp_log_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static void log_cpu_event(void)
 {
 	__raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
@@ -263,11 +269,10 @@
 
 static int procfs_event_log_init(void)
 {
-	procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
-
+	procfs_log_entry = proc_create("cpu/msm_erp_log", S_IRUGO, NULL,
+			&cache_erp_log_fops);
 	if (!procfs_log_entry)
 		return -ENODEV;
-	procfs_log_entry->read_proc = proc_read_log;
 	return 0;
 }
 
@@ -561,7 +566,8 @@
 		goto fail_l1;
 	}
 
-	procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+	procfs_entry = proc_create("cpu/msm_cache_erp", S_IRUGO, NULL,
+			&cache_erp_fops);
 
 	if (!procfs_entry) {
 		pr_err("Failed to create procfs node for cache error reporting\n");
@@ -580,8 +586,6 @@
 		smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
 	put_online_cpus();
 
-	procfs_entry->read_proc = proc_read_status;
-
 	ret = procfs_event_log_init();
 	if (ret)
 		pr_err("Failed to create procfs node for ERP log access\n");
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
index b92c039..e76a6a9 100644
--- a/arch/arm/mach-msm/include/mach/mpm.h
+++ b/arch/arm/mach-msm/include/mach/mpm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -163,4 +163,23 @@
 static inline void msm_mpm_exit_sleep(bool from_idle) {}
 static inline void __init of_mpm_init(struct device_node *node) {}
 #endif
+#ifdef CONFIG_MSM_MPM_OF
+/** msm_mpm_suspend_prepare() - Called at prepare_late() op during suspend
+ *
+ *
+ *  When called the MPM driver checks if the wakeup interrupts can be monitored
+ *  by MPM hardware and program them accordingly. If wake up interrupts cannot
+ *  be monitored then it disallows system low power modes.
+ */
+void msm_mpm_suspend_prepare(void);
+/** msm_mpm_suspend_wake - Called during wake() op in suspend.
+ *
+ *  When called MPM drivers sets the vote for system low power modes depending
+ *  on the active interrupts.
+ */
+void msm_mpm_suspend_wake(void);
+#else
+static inline void msm_mpm_suspend_prepare(void){}
+static inline void msm_mpm_suspend_wake(void) {}
+#endif
 #endif /* __ARCH_ARM_MACH_MSM_MPM_H */
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index aa33f2c..4d7c3d4 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -16,19 +16,60 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
 #include <linux/of.h>
 #include <mach/mpm.h>
-#include "lpm_resources.h"
 #include "pm.h"
 #include "rpm-notifier.h"
-
+#include "spm.h"
+#include "idle.h"
 
 enum {
 	MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
 	MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
 };
 
-#define MAX_STR_LEN 30
+enum {
+	MSM_SCM_L2_ON = 0,
+	MSM_SCM_L2_OFF = 1,
+	MSM_SCM_L2_GDHS = 3,
+};
+
+struct msm_rpmrs_level {
+	enum msm_pm_sleep_mode sleep_mode;
+	uint32_t l2_cache;
+	bool available;
+	uint32_t latency_us;
+	uint32_t steady_state_power;
+	uint32_t energy_overhead;
+	uint32_t time_overhead_us;
+};
+
+struct lpm_lookup_table {
+	uint32_t modes;
+	const char *mode_name;
+};
+
+static void msm_lpm_level_update(void);
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+				unsigned long action, void *hcpu);
+
+static struct notifier_block __refdata msm_lpm_cpu_nblk = {
+	.notifier_call = msm_lpm_cpu_callback,
+};
+
+static uint32_t allowed_l2_mode;
+static uint32_t sysfs_dbg_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+static uint32_t default_l2_mode;
+
+static bool no_l2_saw;
+
+static ssize_t msm_lpm_levels_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count);
 
 static int msm_lpm_lvl_dbg_msk;
 
@@ -39,9 +80,54 @@
 static struct msm_rpmrs_level *msm_lpm_levels;
 static int msm_lpm_level_count;
 
-static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
-static DEFINE_PER_CPU(int , lpm_permitted_level);
-static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+static struct kobj_attribute lpm_l2_kattr = __ATTR(l2,  S_IRUGO|S_IWUSR,\
+		msm_lpm_levels_attr_show, msm_lpm_levels_attr_store);
+
+static struct attribute *lpm_levels_attr[] = {
+	&lpm_l2_kattr.attr,
+	NULL,
+};
+
+static struct attribute_group lpm_levels_attr_grp = {
+	.attrs = lpm_levels_attr,
+};
+
+/* SYSFS */
+static ssize_t msm_lpm_levels_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct kernel_param kp;
+	int rc;
+
+	kp.arg = &sysfs_dbg_l2_mode;
+
+	rc = param_get_uint(buf, &kp);
+
+	if (rc > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		rc++;
+	}
+
+	return rc;
+}
+
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	struct kernel_param kp;
+	unsigned int temp;
+	int rc;
+
+	kp.arg = &temp;
+	rc = param_set_uint(buf, &kp);
+	if (rc)
+		return rc;
+
+	sysfs_dbg_l2_mode = temp;
+	msm_lpm_level_update();
+
+	return count;
+}
 
 static int msm_pm_get_sleep_mode_value(struct device_node *node,
 			const char *key, uint32_t *sleep_mode_val)
@@ -74,8 +160,7 @@
 	if (!ret) {
 		ret = -EINVAL;
 		for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
-			if (!strncmp(mode_name, pm_sm_lookup[i].mode_name,
-				MAX_STR_LEN)) {
+			if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
 				*sleep_mode_val = pm_sm_lookup[i].modes;
 				ret = 0;
 				break;
@@ -85,16 +170,61 @@
 	return ret;
 }
 
+static int msm_lpm_set_l2_mode(int sleep_mode)
+{
+	int lpm = sleep_mode;
+	int rc = 0;
+
+	if (no_l2_saw)
+		goto bail_set_l2_mode;
+
+	msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
+
+	switch (sleep_mode) {
+	case MSM_SPM_L2_MODE_POWER_COLLAPSE:
+		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
+		break;
+	case MSM_SPM_L2_MODE_GDHS:
+		msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
+		break;
+	case MSM_SPM_L2_MODE_RETENTION:
+	case MSM_SPM_L2_MODE_DISABLED:
+		break;
+	default:
+		lpm = MSM_SPM_L2_MODE_DISABLED;
+		break;
+	}
+
+	rc = msm_spm_l2_set_low_power_mode(lpm, true);
+
+	if (rc) {
+		if (rc == -ENXIO)
+			WARN_ON_ONCE(1);
+		else
+			pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
+			__func__, lpm, rc);
+	}
+
+bail_set_l2_mode:
+	return rc;
+}
+
 static void msm_lpm_level_update(void)
 {
-	unsigned int lpm_level;
+	int lpm_level;
 	struct msm_rpmrs_level *level = NULL;
+	uint32_t max_l2_mode;
+	static DEFINE_MUTEX(lpm_lock);
+
+	mutex_lock(&lpm_lock);
+
+	max_l2_mode = min(allowed_l2_mode, sysfs_dbg_l2_mode);
 
 	for (lpm_level = 0; lpm_level < msm_lpm_level_count; lpm_level++) {
 		level = &msm_lpm_levels[lpm_level];
-		level->available =
-			!msm_lpm_level_beyond_limit(&level->rs_limits);
+		level->available = !(level->l2_cache > max_l2_mode);
 	}
+	mutex_unlock(&lpm_lock);
 }
 
 int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
@@ -102,13 +232,7 @@
 {
 	int ret = 0;
 	int debug_mask;
-	struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
-	struct msm_lpm_sleep_data sleep_data;
-
-	sleep_data.limits = limits;
-	sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
-	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
-		MSM_LPM_STATE_ENTER, &sleep_data);
+	uint32_t l2 = *(uint32_t *)limits;
 
 	if (from_idle)
 		debug_mask = msm_lpm_lvl_dbg_msk &
@@ -118,19 +242,20 @@
 			MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
 
 	if (debug_mask)
-		pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
-				__func__, l->pxo, l->l2_cache,
-				l->vdd_mem_lower_bound,
-				l->vdd_mem_upper_bound,
-				l->vdd_dig_lower_bound,
-				l->vdd_dig_upper_bound);
+		pr_info("%s(): l2:%d", __func__, l2);
 
-	ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+	ret = msm_lpm_set_l2_mode(l2);
+
 	if (ret) {
-		pr_warn("%s() LPM resources failed to enter sleep\n",
-				__func__);
-		goto bail;
+		if (ret == -ENXIO)
+			ret = 0;
+		else {
+			pr_warn("%s(): Failed to set L2 SPM Mode %d",
+					__func__, l2);
+			goto bail;
+		}
 	}
+
 	if (notify_rpm) {
 		ret = msm_rpm_enter_sleep(debug_mask);
 		if (ret) {
@@ -138,6 +263,8 @@
 					__func__, ret);
 			goto bail;
 		}
+
+		msm_mpm_enter_sleep(sclk_count, from_idle);
 	}
 bail:
 	return ret;
@@ -147,12 +274,12 @@
 		bool notify_rpm, bool collapsed)
 {
 
-	msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
-				from_idle, notify_rpm, collapsed);
-	if (notify_rpm)
+	msm_lpm_set_l2_mode(default_l2_mode);
+
+	if (notify_rpm) {
+		msm_mpm_exit_sleep(from_idle);
 		msm_rpm_exit_sleep();
-	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
-			MSM_LPM_STATE_EXIT, NULL);
+	}
 }
 
 void msm_lpm_show_resources(void)
@@ -161,48 +288,6 @@
 	return;
 }
 
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
-{
-	return limits->pxo;
-}
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
-{
-	return limits->l2_cache;
-}
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
-{
-	return limits->vdd_mem_upper_bound;
-}
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
-{
-	return limits->vdd_dig_upper_bound;
-}
-
-static bool lpm_level_permitted(int cur_level_count)
-{
-	if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
-		return true;
-	return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
-}
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
-			struct notifier_block *nb, bool is_latency_measure)
-{
-	per_cpu(lpm_permitted_level, cpu) = level_iter;
-	return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
-			cpu), nb);
-}
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
-{
-	per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
-	return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
-				nb);
-}
-
 s32 msm_cpuidle_get_deep_idle_latency(void)
 {
 	int i;
@@ -225,17 +310,26 @@
 	}
 	return best->latency_us - 1;
 }
-static bool msm_lpm_irqs_detectable(struct msm_rpmrs_limits *limits,
-		bool irqs_detectable, bool gpio_detectable)
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+	unsigned long action, void *hcpu)
 {
-	if (!limits->irqs_detectable)
-		return irqs_detectable;
-
-	if (!limits->gpio_detectable)
-		return gpio_detectable;
-
-	return true;
-
+	switch (action) {
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
+		allowed_l2_mode = default_l2_mode;
+		msm_lpm_level_update();
+		break;
+	case CPU_DEAD_FROZEN:
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
+		if (num_online_cpus() == 1)
+			allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+		msm_lpm_level_update();
+		break;
+	}
+	return NOTIFY_OK;
 }
 
 static void *msm_lpm_lowest_limits(bool from_idle,
@@ -244,24 +338,15 @@
 {
 	unsigned int cpu = smp_processor_id();
 	struct msm_rpmrs_level *best_level = NULL;
+	uint32_t best_level_pwr = 0;
 	uint32_t pwr;
 	int i;
-	int best_level_iter = msm_lpm_level_count + 1;
-	bool irqs_detect = false;
-	bool gpio_detect = false;
 	bool modify_event_timer;
 	uint32_t next_wakeup_us = time_param->sleep_us;
 
 	if (!msm_lpm_levels)
 		return NULL;
 
-	msm_lpm_level_update();
-
-	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
-		irqs_detect = msm_mpm_irqs_detectable(from_idle);
-		gpio_detect = msm_mpm_gpio_irqs_detectable(from_idle);
-	}
-
 	for (i = 0; i < msm_lpm_level_count; i++) {
 		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
 
@@ -293,11 +378,6 @@
 		if (next_wakeup_us <= level->time_overhead_us)
 			continue;
 
-		if ((sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) &&
-			!msm_lpm_irqs_detectable(&level->rs_limits,
-				irqs_detect, gpio_detect))
-				continue;
-
 		if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
 			|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
 			if (!cpu && msm_rpm_waiting_for_ack())
@@ -318,12 +398,10 @@
 			pwr += level->energy_overhead / next_wakeup_us;
 		}
 
-		if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
+		if (!best_level || (best_level_pwr >= pwr)) {
 
-			level->rs_limits.latency_us[cpu] = level->latency_us;
-			level->rs_limits.power[cpu] = pwr;
 			best_level = level;
-			best_level_iter = i;
+			best_level_pwr = pwr;
 			if (power)
 				*power = pwr;
 			if (modify_event_timer &&
@@ -336,32 +414,78 @@
 				time_param->modified_time_us = 0;
 		}
 	}
-	if (best_level && !lpm_level_permitted(best_level_iter))
-		best_level = NULL;
-	else
-		per_cpu(msm_lpm_sleep_time, cpu) =
-			time_param->modified_time_us ?
-			time_param->modified_time_us : time_param->sleep_us;
 
-	return best_level ? &best_level->rs_limits : NULL;
+	return best_level ? &best_level->l2_cache : NULL;
 }
 
-static struct lpm_test_platform_data lpm_test_pdata;
-
-static struct platform_device msm_lpm_test_device = {
-	.name		= "lpm_test",
-	.id		= -1,
-	.dev		= {
-		.platform_data = &lpm_test_pdata,
-	},
-};
-
 static struct msm_pm_sleep_ops msm_lpm_ops = {
 	.lowest_limits = msm_lpm_lowest_limits,
 	.enter_sleep = msm_lpm_enter_sleep,
 	.exit_sleep = msm_lpm_exit_sleep,
 };
 
+static int msm_lpm_get_l2_cache_value(struct device_node *node,
+			char *key, uint32_t *l2_val)
+{
+	int i;
+	struct lpm_lookup_table l2_mode_lookup[] = {
+		{MSM_SPM_L2_MODE_POWER_COLLAPSE, "l2_cache_pc"},
+		{MSM_SPM_L2_MODE_GDHS, "l2_cache_gdhs"},
+		{MSM_SPM_L2_MODE_RETENTION, "l2_cache_retention"},
+		{MSM_SPM_L2_MODE_DISABLED, "l2_cache_active"}
+	};
+	const char *l2_str;
+	int ret;
+
+	ret = of_property_read_string(node, key, &l2_str);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
+			if (!strcmp(l2_str, l2_mode_lookup[i].mode_name)) {
+				*l2_val = l2_mode_lookup[i].modes;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+static int __devinit msm_lpm_levels_sysfs_add(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *low_power_kobj = NULL;
+	int rc = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		rc = -ENOENT;
+		goto resource_sysfs_add_exit;
+	}
+
+	low_power_kobj = kobject_create_and_add(
+				"enable_low_power", module_kobj);
+	if (!low_power_kobj) {
+		pr_err("%s: cannot create kobject\n", __func__);
+		rc = -ENOMEM;
+		goto resource_sysfs_add_exit;
+	}
+
+	rc = sysfs_create_group(low_power_kobj, &lpm_levels_attr_grp);
+resource_sysfs_add_exit:
+	if (rc) {
+		if (low_power_kobj) {
+			sysfs_remove_group(low_power_kobj,
+						&lpm_levels_attr_grp);
+			kobject_del(low_power_kobj);
+		}
+	}
+
+	return rc;
+}
+
 static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
 {
 	struct msm_rpmrs_level *levels = NULL;
@@ -372,7 +496,6 @@
 	int ret = 0;
 	uint32_t num_levels = 0;
 	int idx = 0;
-	unsigned int m_cpu = 0;
 
 	for_each_child_of_node(pdev->dev.of_node, node)
 		num_levels++;
@@ -392,49 +515,11 @@
 			goto fail;
 		level->sleep_mode = val;
 
-		key = "qcom,xo";
-		ret = msm_lpm_get_xo_value(node, key, &val);
-		if (ret)
-			goto fail;
-		level->rs_limits.pxo = val;
-
 		key = "qcom,l2";
 		ret = msm_lpm_get_l2_cache_value(node, key, &val);
 		if (ret)
 			goto fail;
-		level->rs_limits.l2_cache = val;
-
-		key = "qcom,vdd-dig-upper-bound";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->rs_limits.vdd_dig_upper_bound = val;
-
-		key = "qcom,vdd-dig-lower-bound";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->rs_limits.vdd_dig_lower_bound = val;
-
-		key = "qcom,vdd-mem-upper-bound";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->rs_limits.vdd_mem_upper_bound = val;
-
-		key = "qcom,vdd-mem-lower-bound";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->rs_limits.vdd_mem_lower_bound = val;
-
-		key = "qcom,gpio-detectable";
-		level->rs_limits.gpio_detectable =
-				of_property_read_bool(node, key);
-
-		key = "qcom,irqs-detectable";
-		level->rs_limits.irqs_detectable =
-				of_property_read_bool(node, key);
+		level->l2_cache = val;
 
 		key = "qcom,latency-us";
 		ret = of_property_read_u32(node, key, &val);
@@ -463,22 +548,33 @@
 		level->available = true;
 	}
 
+	node = pdev->dev.of_node;
+	key = "qcom,no-l2-saw";
+	no_l2_saw = of_property_read_bool(node, key);
+
 	msm_lpm_levels = levels;
 	msm_lpm_level_count = idx;
 
-	lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
-	lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
-	key = "qcom,use-qtimer";
-	lpm_test_pdata.use_qtimer =
-			of_property_read_bool(pdev->dev.of_node, key);
+	if (num_online_cpus() == 1)
+		allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
 
-	for_each_possible_cpu(m_cpu)
-		per_cpu(lpm_permitted_level, m_cpu) =
-					msm_lpm_level_count + 1;
+	/* Do the following two steps only if L2 SAW is present */
+	if (!no_l2_saw) {
+		key = "qcom,default-l2-state";
+		if (msm_lpm_get_l2_cache_value(node, key, &default_l2_mode))
+			goto fail;
 
-	platform_device_register(&msm_lpm_test_device);
+		if (msm_lpm_levels_sysfs_add())
+			goto fail;
+		register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+		msm_pm_set_l2_flush_flag(0);
+	} else {
+		msm_pm_set_l2_flush_flag(1);
+		default_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+	}
+
+	msm_lpm_level_update();
 	msm_pm_set_sleep_ops(&msm_lpm_ops);
-
 	return 0;
 fail:
 	pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
deleted file mode 100644
index 1d9c539..0000000
--- a/arch/arm/mach-msm/lpm_resources.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <mach/mpm.h>
-#include <mach/rpm-smd.h>
-#include <mach/trace_msm_low_power.h>
-#include "spm.h"
-#include "lpm_resources.h"
-#include "rpm-notifier.h"
-#include "idle.h"
-
-
-/*Debug Definitions*/
-enum {
-	MSM_LPMRS_DEBUG_RPM = BIT(0),
-	MSM_LPMRS_DEBUG_PXO = BIT(1),
-	MSM_LPMRS_DEBUG_VDD_DIG = BIT(2),
-	MSM_LPMRS_DEBUG_VDD_MEM = BIT(3),
-	MSM_LPMRS_DEBUG_L2 = BIT(4),
-	MSM_LPMRS_DEBUG_LVLS = BIT(5),
-};
-
-static int msm_lpm_debug_mask;
-module_param_named(
-	debug_mask, msm_lpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-static bool msm_lpm_get_rpm_notif = true;
-
-/*Macros*/
-#define MAX_RS_NAME		(16)
-#define MAX_RS_SIZE		(4)
-#define IS_RPM_CTL(rs) \
-	(!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
-#define MAX_STR_LEN		30
-
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_dig(int notify_rpm);
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
-					*rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
-					char *key, uint32_t *default_value);
-
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_mem(int notify_rpm);
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
-					*rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
-					char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_pxo(int notify_rpm);
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
-					*rpm_notifier_cb);
-static int msm_lpm_init_value_pxo(struct device_node *node,
-				char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_l2(int notify_rpm);
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
-static int msm_lpm_init_value_l2(struct device_node *node,
-				char *key, uint32_t *default_value);
-
-static void msm_lpm_flush_rpm_ctl(int notify_rpm);
-
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
-				unsigned long action, void *rpm_notif);
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
-				unsigned long action, void *hcpu);
-
-static ssize_t msm_lpm_resource_attr_show(
-	struct kobject *kobj, struct kobj_attribute *attr, char *buf);
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
-	struct kobj_attribute *attr, const char *buf, size_t count);
-
-
-#define RPMRS_ATTR(_name) \
-	__ATTR(_name, S_IRUGO|S_IWUSR, \
-		msm_lpm_resource_attr_show, msm_lpm_resource_attr_store)
-
-/*Data structures*/
-struct msm_lpm_rs_data {
-	uint32_t type;
-	uint32_t id;
-	uint32_t key;
-	uint32_t value;
-	uint32_t default_value;
-	struct msm_rpm_request *handle;
-};
-
-enum {
-	MSM_LPM_RPM_RS_TYPE = 0,
-	MSM_LPM_LOCAL_RS_TYPE = 1,
-};
-
-enum {
-	MSM_SCM_L2_ON = 0,
-	MSM_SCM_L2_OFF = 1,
-	MSM_SCM_L2_GDHS = 3,
-};
-
-struct msm_lpm_resource {
-	struct msm_lpm_rs_data rs_data;
-	uint32_t sleep_value;
-	char name[MAX_RS_NAME];
-
-	uint32_t  enable_low_power;
-	bool valid;
-
-	bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
-	void (*aggregate)(struct msm_rpmrs_limits *limits);
-	void (*flush)(int notify_rpm);
-	void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
-	struct kobj_attribute ko_attr;
-	int (*init_value)(struct device_node *node,
-			char *key, uint32_t *default_value);
-};
-
-struct lpm_lookup_table {
-	uint32_t modes;
-	const char *mode_name;
-};
-
-static struct msm_lpm_resource msm_lpm_l2 = {
-	.name = "l2",
-	.beyond_limits = msm_lpm_beyond_limits_l2,
-	.aggregate = msm_lpm_aggregate_l2,
-	.flush = msm_lpm_flush_l2,
-	.notify = NULL,
-	.valid = false,
-	.ko_attr = RPMRS_ATTR(l2),
-	.init_value = msm_lpm_init_value_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_dig = {
-	.name = "vdd-dig",
-	.beyond_limits = msm_lpm_beyond_limits_vdd_dig,
-	.aggregate = msm_lpm_aggregate_vdd_dig,
-	.flush = msm_lpm_flush_vdd_dig,
-	.notify = msm_lpm_notify_vdd_dig,
-	.valid = false,
-	.ko_attr = RPMRS_ATTR(vdd_dig),
-	.init_value = msm_lpm_init_value_vdd_dig,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_mem = {
-	.name = "vdd-mem",
-	.beyond_limits = msm_lpm_beyond_limits_vdd_mem,
-	.aggregate = msm_lpm_aggregate_vdd_mem,
-	.flush = msm_lpm_flush_vdd_mem,
-	.notify = msm_lpm_notify_vdd_mem,
-	.valid = false,
-	.ko_attr = RPMRS_ATTR(vdd_mem),
-	.init_value = msm_lpm_init_value_vdd_mem,
-};
-
-static struct msm_lpm_resource msm_lpm_pxo = {
-	.name = "pxo",
-	.beyond_limits = msm_lpm_beyond_limits_pxo,
-	.aggregate = msm_lpm_aggregate_pxo,
-	.flush = msm_lpm_flush_pxo,
-	.notify = msm_lpm_notify_pxo,
-	.valid = false,
-	.ko_attr = RPMRS_ATTR(pxo),
-	.init_value = msm_lpm_init_value_pxo,
-};
-
-static struct msm_lpm_resource *msm_lpm_resources[] = {
-	&msm_lpm_vdd_dig,
-	&msm_lpm_vdd_mem,
-	&msm_lpm_pxo,
-	&msm_lpm_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_rpm_ctl = {
-	.name = "rpm_ctl",
-	.beyond_limits = NULL,
-	.aggregate = NULL,
-	.flush = msm_lpm_flush_rpm_ctl,
-	.valid = true,
-	.ko_attr = RPMRS_ATTR(rpm_ctl),
-};
-
-static struct notifier_block msm_lpm_rpm_nblk = {
-	.notifier_call = msm_lpm_rpm_callback,
-};
-
-static struct notifier_block __refdata msm_lpm_cpu_nblk = {
-	.notifier_call = msm_lpm_cpu_callback,
-};
-
-static DEFINE_SPINLOCK(msm_lpm_sysfs_lock);
-
-/* Attribute Definitions */
-static struct attribute *msm_lpm_attributes[] = {
-	&msm_lpm_vdd_dig.ko_attr.attr,
-	&msm_lpm_vdd_mem.ko_attr.attr,
-	&msm_lpm_pxo.ko_attr.attr,
-	&msm_lpm_l2.ko_attr.attr,
-	NULL,
-};
-
-static struct attribute_group msm_lpm_attribute_group = {
-	.attrs = msm_lpm_attributes,
-};
-
-static struct attribute *msm_lpm_rpm_ctl_attribute[] = {
-	&msm_lpm_rpm_ctl.ko_attr.attr,
-	NULL,
-};
-
-static struct attribute_group msm_lpm_rpm_ctl_attr_group = {
-	.attrs = msm_lpm_rpm_ctl_attribute,
-};
-
-#define GET_RS_FROM_ATTR(attr) \
-	(container_of(attr, struct msm_lpm_resource, ko_attr))
-
-/* RPM */
-static struct msm_rpm_request *msm_lpm_create_rpm_request
-				(uint32_t rsc_type, uint32_t rsc_id)
-{
-	struct msm_rpm_request *handle = NULL;
-
-	handle = msm_rpm_create_request(MSM_RPM_CTX_SLEEP_SET,
-						rsc_type,
-						rsc_id, 1);
-	return handle;
-}
-
-static int msm_lpm_send_sleep_data(struct msm_rpm_request *handle,
-					uint32_t key, uint8_t *value)
-{
-	int ret = 0;
-	int msg_id;
-
-	if (!handle)
-		return ret;
-
-	ret = msm_rpm_add_kvp_data_noirq(handle, key, value, MAX_RS_SIZE);
-
-	if (ret < 0) {
-		pr_err("%s: Error adding kvp data key %u, size %d\n",
-				__func__, key, MAX_RS_SIZE);
-		return ret;
-	}
-
-	msg_id = msm_rpm_send_request_noirq(handle);
-	if (!msg_id) {
-		pr_err("%s: Error sending RPM request key %u, handle 0x%x\n",
-				__func__, key, (unsigned int)handle);
-		ret = -EIO;
-		return ret;
-	}
-
-	ret = msm_rpm_wait_for_ack_noirq(msg_id);
-	if (ret < 0) {
-		pr_err("%s: Couldn't get ACK from RPM for Msg %d Error %d",
-				__func__, msg_id, ret);
-		return ret;
-	}
-	if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
-		pr_info("Rs key %u, value %u, size %d\n", key,
-				*(unsigned int *)value, MAX_RS_SIZE);
-	return ret;
-}
-
-/* RPM Notifier */
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
-					unsigned long action,
-					void *rpm_notif)
-{
-	int i;
-	struct msm_lpm_resource *rs = NULL;
-	struct msm_rpm_notifier_data *rpm_notifier_cb =
-			(struct msm_rpm_notifier_data *)rpm_notif;
-
-	if (!msm_lpm_get_rpm_notif)
-		return NOTIFY_DONE;
-
-	if (!(rpm_nb && rpm_notif))
-		return NOTIFY_BAD;
-
-	for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
-		rs = msm_lpm_resources[i];
-		if (rs && rs->valid && rs->notify)
-			rs->notify(rpm_notifier_cb);
-	}
-
-	return NOTIFY_OK;
-}
-
-/* SYSFS */
-static ssize_t msm_lpm_resource_attr_show(
-	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-{
-	struct kernel_param kp;
-	unsigned long flags;
-	unsigned int temp;
-	int rc;
-
-	spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
-	temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
-	spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
-	kp.arg = &temp;
-	rc = param_get_uint(buf, &kp);
-
-	if (rc > 0) {
-		strlcat(buf, "\n", PAGE_SIZE);
-		rc++;
-	}
-
-	return rc;
-}
-
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
-	struct kobj_attribute *attr, const char *buf, size_t count)
-{
-	struct kernel_param kp;
-	unsigned long flags;
-	unsigned int temp;
-	int rc;
-
-	kp.arg = &temp;
-	rc = param_set_uint(buf, &kp);
-	if (rc)
-		return rc;
-
-	spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
-	GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
-
-	if (IS_RPM_CTL(GET_RS_FROM_ATTR(attr))) {
-		struct msm_lpm_resource *rs = GET_RS_FROM_ATTR(attr);
-		rs->flush(false);
-	}
-
-	spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
-	return count;
-}
-
-/* lpm resource handling functions */
-/* Common */
-static void msm_lpm_notify_common(struct msm_rpm_notifier_data *cb,
-				struct msm_lpm_resource *rs)
-{
-	if ((cb->rsc_type == rs->rs_data.type) &&
-		(cb->rsc_id == rs->rs_data.id) &&
-		(cb->key == rs->rs_data.key)) {
-
-		BUG_ON(cb->size > MAX_RS_SIZE);
-
-		if (rs->valid) {
-			if (cb->value) {
-				memcpy(&rs->rs_data.value, cb->value, cb->size);
-				msm_rpm_add_kvp_data_noirq(rs->rs_data.handle,
-						cb->key, cb->value, cb->size);
-			}
-			else
-				rs->rs_data.value = rs->rs_data.default_value;
-
-			if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
-				pr_info("Notification received Rs %s value %u\n",
-						rs->name, rs->rs_data.value);
-		}
-	}
-}
-
-/* L2 */
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits)
-{
-	uint32_t l2;
-	bool ret = false;
-	struct msm_lpm_resource *rs = &msm_lpm_l2;
-
-	if (rs->valid) {
-		uint32_t l2_buf = rs->rs_data.value;
-
-		if (rs->enable_low_power == 1)
-			l2 = MSM_LPM_L2_CACHE_GDHS;
-		else if (rs->enable_low_power == 2)
-			l2 = MSM_LPM_L2_CACHE_HSFS_OPEN;
-		else
-			l2 = MSM_LPM_L2_CACHE_ACTIVE ;
-
-		if (l2_buf > l2)
-			l2 = l2_buf;
-		ret = (l2 > limits->l2_cache);
-
-		if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
-			pr_info("%s: l2 buf %u, l2 %u, limits %u\n",
-				__func__, l2_buf, l2, limits->l2_cache);
-	}
-	return ret;
-}
-
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_l2;
-
-	if (rs->valid)
-		rs->sleep_value = limits->l2_cache;
-	trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_set_l2_mode(int sleep_mode)
-{
-	int lpm, rc;
-
-	msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
-
-	switch (sleep_mode) {
-	case MSM_LPM_L2_CACHE_HSFS_OPEN:
-		lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
-		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
-		break;
-	case MSM_LPM_L2_CACHE_GDHS:
-		lpm = MSM_SPM_L2_MODE_GDHS;
-		msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
-		break;
-	case MSM_LPM_L2_CACHE_RETENTION:
-		lpm = MSM_SPM_L2_MODE_RETENTION;
-		break;
-	default:
-	case MSM_LPM_L2_CACHE_ACTIVE:
-		lpm = MSM_SPM_L2_MODE_DISABLED;
-		break;
-	}
-
-	rc = msm_spm_l2_set_low_power_mode(lpm, true);
-
-	if (rc < 0)
-		pr_err("%s: Failed to set L2 low power mode %d",
-			__func__, lpm);
-
-	if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
-		pr_info("%s: Requesting low power mode %d\n",
-				__func__, lpm);
-}
-
-static int msm_lpm_init_value_l2(struct device_node *node,
-					char *key, uint32_t *default_value)
-{
-	return msm_lpm_get_l2_cache_value(node, key, default_value);
-}
-
-static void msm_lpm_flush_l2(int notify_rpm)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_l2;
-
-	msm_lpm_set_l2_mode(rs->sleep_value);
-}
-
-int msm_lpm_get_l2_cache_value(struct device_node *node,
-			char *key, uint32_t *l2_val)
-{
-	int i;
-	struct lpm_lookup_table l2_mode_lookup[] = {
-		{MSM_LPM_L2_CACHE_HSFS_OPEN, "l2_cache_pc"},
-		{MSM_LPM_L2_CACHE_GDHS, "l2_cache_gdhs"},
-		{MSM_LPM_L2_CACHE_RETENTION, "l2_cache_retention"},
-		{MSM_LPM_L2_CACHE_ACTIVE, "l2_cache_active"}
-	};
-	const char *l2_str;
-	int ret;
-
-	ret = of_property_read_string(node, key, &l2_str);
-	if (!ret) {
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
-			if (!strncmp(l2_str, l2_mode_lookup[i].mode_name,
-				MAX_STR_LEN)) {
-				*l2_val = l2_mode_lookup[i].modes;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	return ret;
-}
-
-/* RPM CTL */
-static void msm_lpm_flush_rpm_ctl(int notify_rpm)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
-	msm_lpm_send_sleep_data(rs->rs_data.handle,
-				rs->rs_data.key,
-				(uint8_t *)&rs->sleep_value);
-}
-
-/*VDD Dig*/
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits)
-{
-	bool ret = true;
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
-	if (rs->valid) {
-		uint32_t vdd_buf = rs->rs_data.value;
-		uint32_t vdd_dig = rs->enable_low_power ? rs->enable_low_power :
-					rs->rs_data.default_value;
-
-		if (vdd_buf > vdd_dig)
-			vdd_dig = vdd_buf;
-
-		ret = (vdd_dig > limits->vdd_dig_upper_bound);
-
-		if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_DIG)
-			pr_info("%s:buf %d vdd dig %d limits%d\n",
-				__func__, vdd_buf, vdd_dig,
-				limits->vdd_dig_upper_bound);
-	}
-	return ret;
-}
-
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
-					char *key, uint32_t *default_value)
-{
-	return of_property_read_u32(node, key, default_value);
-}
-
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
-	if (rs->valid) {
-		uint32_t vdd_buf = rs->rs_data.value;
-		if (limits->vdd_dig_lower_bound > vdd_buf)
-			rs->sleep_value = limits->vdd_dig_lower_bound;
-		else
-			rs->sleep_value = vdd_buf;
-	}
-	trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_dig(int notify_rpm)
-{
-	if (notify_rpm) {
-		struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-		msm_lpm_send_sleep_data(rs->rs_data.handle,
-					rs->rs_data.key,
-					(uint8_t *)&rs->sleep_value);
-	}
-}
-
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
-					*rpm_notifier_cb)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-	msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-/*VDD Mem*/
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits)
-{
-	bool ret = true;
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
-	if (rs->valid) {
-		uint32_t vdd_buf = rs->rs_data.value;
-		uint32_t vdd_mem = rs->enable_low_power ? rs->enable_low_power :
-					rs->rs_data.default_value;
-
-		if (vdd_buf > vdd_mem)
-			vdd_mem = vdd_buf;
-
-		ret = (vdd_mem > limits->vdd_mem_upper_bound);
-
-		if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_MEM)
-			pr_info("%s:buf %d vdd mem %d limits%d\n",
-				__func__, vdd_buf, vdd_mem,
-				limits->vdd_mem_upper_bound);
-	}
-	return ret;
-}
-
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
-	if (rs->valid) {
-		uint32_t vdd_buf = rs->rs_data.value;
-		if (limits->vdd_mem_lower_bound > vdd_buf)
-			rs->sleep_value = limits->vdd_mem_lower_bound;
-		else
-			rs->sleep_value = vdd_buf;
-	}
-	trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_mem(int notify_rpm)
-{
-	if (notify_rpm) {
-		struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-		msm_lpm_send_sleep_data(rs->rs_data.handle,
-					rs->rs_data.key,
-					(uint8_t *)&rs->sleep_value);
-	}
-}
-
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
-					*rpm_notifier_cb)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-	msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
-					char *key, uint32_t *default_value)
-{
-	return of_property_read_u32(node, key, default_value);
-}
-
-/*PXO*/
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
-{
-	bool ret = true;
-	struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
-	if (rs->valid) {
-		uint32_t pxo_buf = rs->rs_data.value;
-		uint32_t pxo = rs->enable_low_power ? MSM_LPM_PXO_OFF :
-					rs->rs_data.default_value;
-
-		if (pxo_buf > pxo)
-			pxo = pxo_buf;
-
-		ret = (pxo > limits->pxo);
-
-		if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
-			pr_info("%s:pxo buf %d pxo %d limits pxo %d\n",
-					__func__, pxo_buf, pxo, limits->pxo);
-	}
-	return ret;
-}
-
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
-	if (rs->valid) {
-		uint32_t pxo_buf = rs->rs_data.value;
-		if (limits->pxo > pxo_buf)
-			rs->sleep_value = limits->pxo;
-		else
-			rs->sleep_value = pxo_buf;
-
-		if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
-			pr_info("%s: pxo buf %d sleep value %d\n",
-					__func__, pxo_buf, rs->sleep_value);
-	}
-	trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_pxo(int notify_rpm)
-{
-	if (notify_rpm) {
-		struct msm_lpm_resource *rs = &msm_lpm_pxo;
-		msm_lpm_send_sleep_data(rs->rs_data.handle,
-					rs->rs_data.key,
-					(uint8_t *)&rs->sleep_value);
-	}
-}
-
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
-					*rpm_notifier_cb)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_pxo;
-	msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_pxo(struct device_node *node,
-				char *key, uint32_t *default_value)
-{
-	return msm_lpm_get_xo_value(node, key, default_value);
-}
-
-static inline bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
-{
-	return (limits->pxo == MSM_LPM_PXO_OFF);
-}
-
-int msm_lpm_get_xo_value(struct device_node *node,
-			char *key, uint32_t *xo_val)
-{
-	int  i;
-	struct lpm_lookup_table pxo_mode_lookup[] = {
-		{MSM_LPM_PXO_OFF, "xo_off"},
-		{MSM_LPM_PXO_ON, "xo_on"}
-	};
-	const char *xo_str;
-	int ret;
-
-	ret = of_property_read_string(node, key, &xo_str);
-	if (!ret) {
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(pxo_mode_lookup); i++) {
-			if (!strncmp(xo_str, pxo_mode_lookup[i].mode_name,
-				MAX_STR_LEN)) {
-				*xo_val = pxo_mode_lookup[i].modes;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	return ret;
-}
-
-/* LPM levels interface */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
-	int i;
-	struct msm_lpm_resource *rs;
-	bool beyond_limit = false;
-
-	for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
-		rs = msm_lpm_resources[i];
-		if (rs->beyond_limits && rs->beyond_limits(limits)) {
-			beyond_limit = true;
-			if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_LVLS)
-				pr_info("%s: %s beyond limit", __func__,
-						rs->name);
-			break;
-		}
-	}
-
-	return beyond_limit;
-}
-
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
-				bool from_idle, bool notify_rpm)
-{
-	int ret = 0;
-	int i;
-	struct msm_lpm_resource *rs = NULL;
-
-	for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
-		rs = msm_lpm_resources[i];
-		if (rs->aggregate)
-			rs->aggregate(limits);
-	}
-
-	msm_lpm_get_rpm_notif = false;
-	for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
-		rs = msm_lpm_resources[i];
-		if (rs->valid && rs->flush)
-			rs->flush(notify_rpm);
-	}
-	msm_lpm_get_rpm_notif = true;
-
-	if (notify_rpm)
-		msm_mpm_enter_sleep(sclk_count, from_idle);
-
-	return ret;
-}
-
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
-		bool from_idle, bool notify_rpm, bool collapsed)
-{
-	if (msm_lpm_use_mpm(limits))
-		msm_mpm_exit_sleep(from_idle);
-
-	if (msm_lpm_l2.valid)
-		msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
-}
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
-		unsigned long action, void *hcpu)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_l2;
-	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		rs->rs_data.value = rs->rs_data.default_value;
-		break;
-	case CPU_ONLINE_FROZEN:
-	case CPU_ONLINE:
-		if (num_online_cpus() > 1)
-			rs->rs_data.value = rs->rs_data.default_value;
-		break;
-	case CPU_DEAD_FROZEN:
-	case CPU_DEAD:
-		if (num_online_cpus() == 1)
-			rs->rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-/* RPM CTL */
-static int __devinit msm_lpm_init_rpm_ctl(void)
-{
-	struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
-
-	rs->rs_data.handle = msm_rpm_create_request(
-				MSM_RPM_CTX_ACTIVE_SET,
-				rs->rs_data.type,
-				rs->rs_data.id, 1);
-	if (!rs->rs_data.handle)
-		return -EIO;
-
-	rs->valid = true;
-	return 0;
-}
-
-static int __devinit msm_lpm_resource_sysfs_add(void)
-{
-	struct kobject *module_kobj = NULL;
-	struct kobject *low_power_kobj = NULL;
-	struct kobject *mode_kobj = NULL;
-	int rc = 0;
-
-	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
-	if (!module_kobj) {
-		pr_err("%s: cannot find kobject for module %s\n",
-			__func__, KBUILD_MODNAME);
-		rc = -ENOENT;
-		goto resource_sysfs_add_exit;
-	}
-
-	low_power_kobj = kobject_create_and_add(
-				"enable_low_power", module_kobj);
-	if (!low_power_kobj) {
-		pr_err("%s: cannot create kobject\n", __func__);
-		rc = -ENOMEM;
-		goto resource_sysfs_add_exit;
-	}
-
-	mode_kobj = kobject_create_and_add(
-				"mode", module_kobj);
-	if (!mode_kobj) {
-		pr_err("%s: cannot create kobject\n", __func__);
-		rc = -ENOMEM;
-		goto resource_sysfs_add_exit;
-	}
-
-	rc = sysfs_create_group(low_power_kobj, &msm_lpm_attribute_group);
-	if (rc) {
-		pr_err("%s: cannot create kobject attribute group\n", __func__);
-		goto resource_sysfs_add_exit;
-	}
-
-	rc = sysfs_create_group(mode_kobj, &msm_lpm_rpm_ctl_attr_group);
-	if (rc) {
-		pr_err("%s: cannot create kobject attribute group\n", __func__);
-		goto resource_sysfs_add_exit;
-	}
-
-resource_sysfs_add_exit:
-	if (rc) {
-		if (low_power_kobj)
-			sysfs_remove_group(low_power_kobj,
-					&msm_lpm_attribute_group);
-		kobject_del(low_power_kobj);
-		kobject_del(mode_kobj);
-	}
-
-	return rc;
-}
-
-late_initcall(msm_lpm_resource_sysfs_add);
-
-static int __devinit msm_lpmrs_probe(struct platform_device *pdev)
-{
-	struct device_node *node = NULL;
-	char *key = NULL;
-	int ret = 0;
-
-	for_each_child_of_node(pdev->dev.of_node, node) {
-		struct msm_lpm_resource *rs = NULL;
-		const char *val;
-		int i;
-		bool local_resource;
-
-		key = "qcom,name";
-		ret = of_property_read_string(node, key, &val);
-		if (ret) {
-			pr_err("Cannot read string\n");
-			goto fail;
-		}
-
-		for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
-			char *lpmrs_name = msm_lpm_resources[i]->name;
-			if (!msm_lpm_resources[i]->valid &&
-				!strncmp(val, lpmrs_name, strnlen(lpmrs_name,
-							MAX_RS_NAME))) {
-				rs = msm_lpm_resources[i];
-				break;
-			}
-		}
-
-		if (!rs) {
-			pr_err("LPM resource not found\n");
-			continue;
-		}
-
-		key = "qcom,init-value";
-		ret = rs->init_value(node, key, &rs->rs_data.default_value);
-		if (ret) {
-			pr_err("%s():Failed to read %s\n", __func__, key);
-			goto fail;
-		}
-
-		rs->rs_data.value = rs->rs_data.default_value;
-
-		key = "qcom,local-resource-type";
-		local_resource = of_property_read_bool(node, key);
-
-		if (!local_resource) {
-			key = "qcom,type";
-			ret = of_property_read_u32(node, key,
-					&rs->rs_data.type);
-			if (ret) {
-				pr_err("Failed to read type\n");
-				goto fail;
-			}
-
-			key = "qcom,id";
-			ret = of_property_read_u32(node, key, &rs->rs_data.id);
-			if (ret) {
-				pr_err("Failed to read id\n");
-				goto fail;
-			}
-
-			key = "qcom,key";
-			ret = of_property_read_u32(node, key, &rs->rs_data.key);
-			if (ret) {
-				pr_err("Failed to read key\n");
-				goto fail;
-			}
-
-			rs->rs_data.handle = msm_lpm_create_rpm_request(
-						rs->rs_data.type,
-						rs->rs_data.id);
-
-			if (!rs->rs_data.handle) {
-				pr_err("%s: Failed to allocate handle for %s\n",
-						__func__, rs->name);
-				ret = -1;
-				goto fail;
-			}
-			/* fall through */
-		}
-
-		rs->valid = true;
-	}
-	msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
-	msm_lpm_init_rpm_ctl();
-
-	if (msm_lpm_l2.valid) {
-		register_hotcpu_notifier(&msm_lpm_cpu_nblk);
-		/* For UP mode, set the default to HSFS OPEN*/
-		if (num_possible_cpus() == 1) {
-			msm_lpm_l2.rs_data.default_value =
-					MSM_LPM_L2_CACHE_HSFS_OPEN;
-			msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
-		}
-		msm_pm_set_l2_flush_flag(0);
-	} else
-		msm_pm_set_l2_flush_flag(1);
-
-fail:
-	return ret;
-}
-
-static struct of_device_id msm_lpmrs_match_table[] = {
-	{.compatible = "qcom,lpm-resources"},
-	{},
-};
-
-static struct platform_driver msm_lpmrs_driver = {
-	.probe = msm_lpmrs_probe,
-	.driver = {
-		.name = "lpm-resources",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_lpmrs_match_table,
-	},
-};
-
-int __init msm_lpmrs_module_init(void)
-{
-	return platform_driver_register(&msm_lpmrs_driver);
-}
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
deleted file mode 100644
index 105cfe6..0000000
--- a/arch/arm/mach-msm/lpm_resources.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
-#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
-
-#include "pm.h"
-#include "test-lpm.h"
-
-enum {
-	MSM_LPM_PXO_OFF,
-	MSM_LPM_PXO_ON
-};
-
-enum {
-	MSM_LPM_L2_CACHE_HSFS_OPEN,
-	MSM_LPM_L2_CACHE_GDHS,
-	MSM_LPM_L2_CACHE_RETENTION,
-	MSM_LPM_L2_CACHE_ACTIVE,
-};
-
-struct msm_rpmrs_limits {
-	uint32_t pxo;
-	uint32_t l2_cache;
-	uint32_t vdd_mem_upper_bound;
-	uint32_t vdd_mem_lower_bound;
-	uint32_t vdd_dig_upper_bound;
-	uint32_t vdd_dig_lower_bound;
-	bool irqs_detectable;
-	bool gpio_detectable;
-
-	uint32_t latency_us[NR_CPUS];
-	uint32_t power[NR_CPUS];
-};
-
-struct msm_rpmrs_level {
-	enum msm_pm_sleep_mode sleep_mode;
-	struct msm_rpmrs_limits rs_limits;
-	bool available;
-	uint32_t latency_us;
-	uint32_t steady_state_power;
-	uint32_t energy_overhead;
-	uint32_t time_overhead_us;
-};
-
-enum {
-	MSM_LPM_STATE_ENTER = 0,
-	MSM_LPM_STATE_EXIT = 1,
-};
-
-#define MSM_PM(field) MSM_LPM_##field
-
-/**
- * msm_pm_get_pxo() -  get the limits for pxo
- * @limits:            pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource pxo on
- * 8974
- */
-
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_l2_cache() -  get the limits for l2 cache
- * @limits:            pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource l2 cache
- * on 8974
- */
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_mem() -  get the limits for pxo
- * @limits:            pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource vdd mem
- * on 8974
- */
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_dig() -  get the limits for vdd dig
- * @limits:            pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource on 8974
- */
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpm_get_xo_value() - get the enum value for xo
- * @node		pointer to the device node
- * @key			pxo property key
- * @xo_val		xo enum value
- */
-int msm_lpm_get_xo_value(struct device_node *node,
-			char *key, uint32_t *xo_val);
-
-/**
- * msm_lpm_get_l2_cache_value() - get the enum value for l2 cache
- * @node                pointer to the device node
- * @key                 l2 cache property key
- * @l2_val              l2 mode enum value
- */
-int msm_lpm_get_l2_cache_value(struct device_node *node,
-				char *key, uint32_t *l2_val);
-
-/**
- * struct msm_lpm_sleep_data - abstraction to get sleep data
- * @limits:	pointer to the msm_rpmrs_limits structure
- * @kernel_sleep:	kernel sleep time as decided by the power calculation
- *			algorithm
- *
- * This structure is an abstraction to get the limits and kernel sleep time
- * during enter sleep.
- */
-
-struct msm_lpm_sleep_data {
-	struct msm_rpmrs_limits *limits;
-	uint32_t kernel_sleep;
-};
-
-/**
- * msm_lpm_register_notifier() - register for notifications
- * @cpu:               cpu to debug
- * @level_iter:        low power level index to debug
- * @nb:       notifier block to callback on notifications
- * @is_latency_measure: is it latency measure
- *
- * This function sets the permitted level to the index of the
- * level under test and registers notifier for callback.
- */
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
-		struct notifier_block *nb, bool is_latency_measure);
-
-/**
- * msm_lpm_unregister_notifier() - unregister from notifications
- * @cpu:               cpu to debug
- * @nb:       notifier block to callback on notifications
- *
- * This function sets the permitted level to a value one more than
- * available levels count which indicates that all levels are
- * permitted and it also unregisters notifier for callback.
- */
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
-
-#ifdef CONFIG_MSM_RPM_SMD
-
-/**
- * msm_lpm_level_beyond_limit() - Check if the resources in a low power level
- * is beyond the limits of the driver votes received for those resources.This
- * function is used by lpm_levels to eliminate any low power level that cannot
- * be entered.
- *
- * @limits: pointer to the resource limits of a low power level.
- *
- * returns true if the resource limits are beyond driver resource votes.
- * false otherwise.
- */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpmrs_enter_sleep() - Enter sleep flushes the sleep votes of low power
- * resources to the RPM driver, also configure the MPM if needed depending
- * on the low power mode being entered. L2 low power mode is also set in
- * this function.
-
- * @sclk_count: wakeup counter for RPM.
- * @limits: pointer to the resource limits of the low power mode being entered.
- * @from_idle: bool to determine if this call being made as a part of
- *             idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- *
- * returns 0 on success.
- */
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
-	bool from_idle, bool notify_rpm);
-
-/**
- * msm_lpmrs_exit_sleep() - Exit sleep, reset the MPM and L2 mode.
- * @ limits: pointer to resource limits of the most recent low power mode.
- * @from_idle: bool to determine if this call being made as a part of
- *             idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- * @collapsed: bool that informs if the Krait was power collapsed.
- */
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
-	bool from_idle, bool notify_rpm, bool collapsed);
-/**
- * msm_lpmrs_module_init() - Init function that parses the device tree to
- * get the low power resource attributes and registers with RPM driver for
- * callback notification.
- *
- * returns 0 on success.
- */
-int __init msm_lpmrs_module_init(void);
-
-#else
-static inline bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
-	return true;
-}
-
-static inline int msm_lpmrs_enter_sleep(uint32_t sclk_count,
-	struct msm_rpmrs_limits *limits, bool from_idle, bool notify_rpm)
-{
-	return 0;
-}
-
-static inline void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
-	bool from_idle, bool notify_rpm, bool collapsed)
-{
-	return;
-}
-
-static inline int __init msm_lpmrs_module_init(void)
-{
-	return 0;
-}
-#endif /* CONFIG_MSM_RPM_SMD */
-
-#endif
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index dbd5d67..a0746f9 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -27,10 +27,17 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
 #include <asm/hardware/gic.h>
 #include <asm/arch_timer.h>
 #include <mach/gpio.h>
 #include <mach/mpm.h>
+#include <mach/clk.h>
+#include <mach/rpm-regulator-smd.h>
 
 enum {
 	MSM_MPM_GIC_IRQ_DOMAIN,
@@ -75,6 +82,12 @@
 #define ARCH_TIMER_HZ (19200000)
 static struct msm_mpm_device_data msm_mpm_dev_data;
 
+static struct clk *xo_clk;
+static bool xo_enabled;
+static struct workqueue_struct *msm_mpm_wq;
+static struct work_struct msm_mpm_work;
+static struct completion wake_wq;
+
 enum mpm_reg_offsets {
 	MSM_MPM_REG_WAKEUP,
 	MSM_MPM_REG_ENABLE,
@@ -257,6 +270,8 @@
 		else
 			__clear_bit(d->hwirq, irq_apps);
 
+		if (!wakeset && (msm_mpm_initialized & MSM_MPM_DEVICE_PROBED))
+			complete(&wake_wq);
 	}
 
 	return 0;
@@ -543,6 +558,54 @@
 		}
 	}
 }
+static void msm_mpm_sys_low_power_modes(bool allow)
+{
+	if (allow) {
+		if (xo_enabled) {
+			clk_disable_unprepare(xo_clk);
+			xo_enabled = false;
+		}
+	} else {
+		if (!xo_enabled) {
+			/* If we cannot enable XO clock then we want to flag it,
+			 * than having to deal with not being able to wakeup
+			 * from a non-monitorable interrupt
+			 */
+			BUG_ON(clk_prepare_enable(xo_clk));
+			xo_enabled = true;
+		}
+	}
+}
+
+void msm_mpm_suspend_prepare(void)
+{
+	bool allow = msm_mpm_irqs_detectable(false) &&
+		msm_mpm_gpio_irqs_detectable(false);
+	msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_prepare);
+
+void msm_mpm_suspend_wake(void)
+{
+	bool allow = msm_mpm_irqs_detectable(true) &&
+		msm_mpm_gpio_irqs_detectable(true);
+	msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_wake);
+
+static void msm_mpm_work_fn(struct work_struct *work)
+{
+	unsigned long flags;
+	while (1) {
+		bool allow;
+		wait_for_completion(&wake_wq);
+		spin_lock_irqsave(&msm_mpm_lock, flags);
+		allow = msm_mpm_irqs_detectable(true) &&
+				msm_mpm_gpio_irqs_detectable(true);
+		spin_unlock_irqrestore(&msm_mpm_lock, flags);
+		msm_mpm_sys_low_power_modes(allow);
+	}
+}
 
 static int __devinit msm_mpm_dev_probe(struct platform_device *pdev)
 {
@@ -555,6 +618,13 @@
 		return 0;
 	}
 
+	xo_clk = devm_clk_get(&pdev->dev, "xo");
+
+	if (IS_ERR(xo_clk)) {
+		pr_err("%s(): Cannot get clk resource for XO\n", __func__);
+		return PTR_ERR(xo_clk);
+	}
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vmpm");
 	if (!res) {
 		pr_err("%s(): Missing RPM memory resource\n", __func__);
@@ -610,10 +680,27 @@
 		return ret;
 
 	}
+
+	init_completion(&wake_wq);
+
+	INIT_WORK(&msm_mpm_work, msm_mpm_work_fn);
+	msm_mpm_wq = create_singlethread_workqueue("mpm");
+
+	if (msm_mpm_wq)
+		queue_work(msm_mpm_wq, &msm_mpm_work);
+	else  {
+		pr_warn("%s(): Failed to create wq. So voting against XO off",
+				__func__);
+		/* Throw a BUG. Otherwise, its possible that system allows
+		 * XO shutdown when there are non-monitored interrupts are
+		 * pending and cause errors at a later point in time.
+		 */
+		BUG_ON(clk_prepare_enable(xo_clk));
+		xo_enabled = true;
+	}
+
 	msm_mpm_initialized |= MSM_MPM_DEVICE_PROBED;
-
 	return 0;
-
 }
 
 static inline int __init mpm_irq_domain_linear_size(struct irq_domain *d)
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 8bceb42..da5e67a 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -40,6 +40,7 @@
 #include <mach/trace_msm_low_power.h>
 #include <mach/msm-krait-l2-accessors.h>
 #include <mach/msm_bus.h>
+#include <mach/mpm.h>
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
 #include <asm/pgtable.h>
@@ -1132,9 +1133,22 @@
 		pm_sleep_ops = *ops;
 }
 
+static int msm_suspend_prepare(void)
+{
+	msm_mpm_suspend_prepare();
+	return 0;
+}
+
+static void msm_suspend_wake(void)
+{
+	msm_mpm_suspend_wake();
+}
+
 static const struct platform_suspend_ops msm_pm_ops = {
 	.enter = msm_pm_enter,
 	.valid = suspend_valid_only_mem,
+	.prepare_late = msm_suspend_prepare,
+	.wake = msm_suspend_wake,
 };
 
 static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index e62af21..1d12b07 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -21,6 +21,7 @@
 #include <linux/uaccess.h>
 #include <linux/user.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <asm/cp15.h>
 #include <asm/cputype.h>
@@ -656,23 +657,23 @@
 }
 
 #ifdef CONFIG_PROC_FS
-static int proc_read_status(char *page, char **start, off_t off, int count,
-			    int *eof, void *data)
+static int vfp_bounce_show(struct seq_file *m, void *v)
 {
-	char *p = page;
-	int len;
-
-	p += snprintf(p, PAGE_SIZE, "%llu\n", atomic64_read(&vfp_bounce_count));
-
-	len = (p - page) - off;
-	if (len < 0)
-		len = 0;
-
-	*eof = (len <= count) ? 1 : 0;
-	*start = page + off;
-
-	return len;
+	seq_printf(m, "%llu\n", atomic64_read(&vfp_bounce_count));
+	return 0;
 }
+
+static int vfp_bounce_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, vfp_bounce_show, NULL);
+}
+
+static const struct file_operations vfp_bounce_fops = {
+	.open		= vfp_bounce_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 #endif
 
 /*
@@ -755,11 +756,9 @@
 	}
 
 #ifdef CONFIG_PROC_FS
-	procfs_entry = create_proc_entry("cpu/vfp_bounce", S_IRUGO, NULL);
-
-	if (procfs_entry)
-		procfs_entry->read_proc = proc_read_status;
-	else
+	procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL,
+			&vfp_bounce_fops);
+	if (!procfs_entry)
 		pr_err("Failed to create procfs node for VFP bounce reporting\n");
 #endif
 
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 132df90..6efab5b 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -65,6 +65,7 @@
 #define CSR_QDSSPWRREQIGNORE	(0x060)
 #define CSR_QDSSSPARE		(0x064)
 #define CSR_IPCAT		(0x068)
+#define CSR_BYTECNTVAL		(0x06C)
 
 #define BLKSIZE_256		0
 #define BLKSIZE_512		1
@@ -159,6 +160,19 @@
 }
 EXPORT_SYMBOL(coresight_csr_hwctrl_set);
 
+void coresight_csr_set_byte_cntr(uint32_t count)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+
+	CSR_UNLOCK(drvdata);
+
+	csr_writel(drvdata, count, CSR_BYTECNTVAL);
+	mb();
+
+	CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
+
 static int __devinit csr_probe(struct platform_device *pdev)
 {
 	int ret;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index b570252..3ad1f34 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -48,12 +48,14 @@
 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);
+extern void coresight_csr_set_byte_cntr(uint32_t);
 #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; }
+static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
 #endif
 #ifdef CONFIG_CORESIGHT_ETM
 extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 4186abe..c501700 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -30,6 +30,10 @@
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <linux/coresight-cti.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
 #include <linux/usb/usb_qdss.h>
 #include <mach/memory.h>
 #include <mach/sps.h>
@@ -135,6 +139,8 @@
 	struct device		*dev;
 	struct coresight_device	*csdev;
 	struct miscdevice	miscdev;
+	struct cdev		byte_cntr_dev;
+	struct class		*byte_cntr_class;
 	struct clk		*clk;
 	spinlock_t		spinlock;
 	bool			reset_flush_race;
@@ -157,6 +163,19 @@
 	bool			enable;
 	enum tmc_config_type	config_type;
 	uint32_t		trigger_cntr;
+	int			byte_cntr_irq;
+	atomic_t		byte_cntr_irq_cnt;
+	uint32_t		byte_cntr_value;
+	struct mutex		byte_cntr_read_lock;
+	struct mutex		byte_cntr_lock;
+	uint32_t		byte_cntr_block_size;
+	bool			byte_cntr_overflow;
+	bool			byte_cntr_present;
+	bool			byte_cntr_enable;
+	uint32_t		byte_cntr_overflow_cnt;
+	bool			byte_cntr_read_active;
+	wait_queue_head_t	wq;
+	char			*byte_cntr_node;
 };
 
 static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -368,6 +387,52 @@
 	mutex_unlock(&drvdata->usb_lock);
 }
 
+static uint32_t tmc_etr_get_write_ptr(struct tmc_drvdata *drvdata)
+{
+	uint32_t rwp = 0;
+
+	TMC_UNLOCK(drvdata);
+
+	rwp = tmc_readl(drvdata, TMC_RWP);
+
+	TMC_LOCK(drvdata);
+
+	return rwp;
+}
+
+static void tmc_etr_byte_cntr_start(struct tmc_drvdata *drvdata)
+{
+	if (!drvdata->byte_cntr_present)
+		return;
+
+	mutex_lock(&drvdata->byte_cntr_lock);
+	atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
+	drvdata->byte_cntr_overflow = false;
+	drvdata->byte_cntr_read_active = false;
+	drvdata->byte_cntr_enable = true;
+	if (drvdata->byte_cntr_value != 0)
+		drvdata->byte_cntr_overflow_cnt = drvdata->size /
+						 (drvdata->byte_cntr_value * 8);
+	else
+		drvdata->byte_cntr_overflow_cnt = 0;
+	coresight_csr_set_byte_cntr(drvdata->byte_cntr_value);
+	mutex_unlock(&drvdata->byte_cntr_lock);
+}
+
+static void tmc_etr_byte_cntr_stop(struct tmc_drvdata *drvdata)
+{
+	if (!drvdata->byte_cntr_present)
+		return;
+
+	mutex_lock(&drvdata->byte_cntr_lock);
+	coresight_csr_set_byte_cntr(0);
+	drvdata->byte_cntr_value = 0;
+	drvdata->byte_cntr_enable = false;
+	mutex_unlock(&drvdata->byte_cntr_lock);
+
+	wake_up(&drvdata->wq);
+}
+
 static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
 {
 	/* Zero out the memory to help with debug */
@@ -438,10 +503,14 @@
 		coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
 		coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
-		    !drvdata->reset_flush_race) {
-			coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
-			coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+			tmc_etr_byte_cntr_start(drvdata);
+			if (!drvdata->reset_flush_race) {
+				coresight_cti_map_trigout(drvdata->cti_flush,
+							  3, 0);
+				coresight_cti_map_trigin(drvdata->cti_reset,
+							 2, 0);
+			}
 		} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
 			drvdata->usbch = usb_qdss_open("qdss", drvdata,
 						       usb_notifier);
@@ -674,10 +743,14 @@
 		coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
 		coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
-		    !drvdata->reset_flush_race) {
-			coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
-			coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+			tmc_etr_byte_cntr_stop(drvdata);
+			if (!drvdata->reset_flush_race) {
+				coresight_cti_unmap_trigin(drvdata->cti_reset,
+							   2, 0);
+				coresight_cti_unmap_trigout(drvdata->cti_flush,
+							    3, 0);
+			}
 		} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
 			tmc_etr_bam_disable(drvdata);
 			usb_qdss_close(drvdata->usbch);
@@ -929,6 +1002,161 @@
 	.llseek		= no_llseek,
 };
 
+static int tmc_etr_byte_cntr_open(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = container_of(inode->i_cdev,
+						   struct tmc_drvdata,
+						   byte_cntr_dev);
+
+	if (drvdata->out_mode != TMC_ETR_OUT_MODE_MEM ||
+	    !drvdata->byte_cntr_enable)
+		return -EPERM;
+
+	if (!mutex_trylock(&drvdata->byte_cntr_read_lock))
+		return -EPERM;
+
+	file->private_data = drvdata;
+	nonseekable_open(inode, file);
+	drvdata->byte_cntr_block_size = drvdata->byte_cntr_value * 8;
+	drvdata->byte_cntr_read_active = true;
+	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static void tmc_etr_read_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+			       size_t bytes, size_t *len)
+{
+	if (*len >= bytes) {
+		atomic_dec(&drvdata->byte_cntr_irq_cnt);
+		*len = bytes;
+	} else {
+		if (((uint32_t)*ppos % bytes) + *len > bytes)
+				*len = bytes - ((uint32_t)*ppos % bytes);
+		if ((*len + (uint32_t)*ppos) % bytes == 0)
+			atomic_dec(&drvdata->byte_cntr_irq_cnt);
+	}
+}
+
+static size_t tmc_etr_flush_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+				  size_t bytes)
+{
+	uint32_t rwp = 0;
+	size_t len = bytes;
+
+	rwp = tmc_etr_get_write_ptr(drvdata);
+	if (rwp >= (drvdata->paddr + *ppos)) {
+		if (len > (rwp - drvdata->paddr - *ppos))
+			len = rwp - drvdata->paddr - *ppos;
+	}
+	return len;
+}
+
+static ssize_t tmc_etr_byte_cntr_read(struct file *file, char __user *data,
+				  size_t len, loff_t *ppos)
+{
+	struct tmc_drvdata *drvdata = file->private_data;
+	char *bufp = drvdata->vaddr + *ppos;
+	size_t bytes = drvdata->byte_cntr_block_size;
+	int ret = 0;
+
+	if (!data)
+		return -EINVAL;
+	if (drvdata->byte_cntr_overflow)
+		return -EIO;
+
+	mutex_lock(&drvdata->byte_cntr_lock);
+	/* In case the byte counter is enabled and disabled multiple times
+	 * prevent unexpected data from being given to the user
+	 */
+	if (!drvdata->byte_cntr_read_active)
+		goto read_err0;
+
+	if (!drvdata->byte_cntr_enable) {
+		if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+			/* Read the last 'block' of data which might be needed
+			 * to be read partially. If already read, return 0
+			 */
+			len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+			if (!len)
+				goto read_err0;
+		} else {
+			/* Keep reading until you reach the last block of data
+			 */
+			tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+		}
+	} else {
+		if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+			mutex_unlock(&drvdata->byte_cntr_lock);
+			if (wait_event_interruptible(drvdata->wq,
+			    (atomic_read(&drvdata->byte_cntr_irq_cnt) > 0) ||
+			    !drvdata->byte_cntr_enable)) {
+				ret = -ERESTARTSYS;
+				goto read_err1;
+			}
+			mutex_lock(&drvdata->byte_cntr_lock);
+			if (!drvdata->byte_cntr_read_active) {
+				ret = 0;
+				goto read_err0;
+			}
+		}
+		if (drvdata->byte_cntr_overflow) {
+			ret = -EIO;
+			goto read_err0;
+		}
+		if (!drvdata->byte_cntr_enable &&
+		    !atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+			len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+			if (!len) {
+				ret = 0;
+				goto read_err0;
+			}
+		} else {
+			tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+		}
+	}
+	if (copy_to_user(data, bufp, len)) {
+		mutex_unlock(&drvdata->byte_cntr_lock);
+		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+		ret = -EFAULT;
+		goto read_err1;
+	}
+	mutex_unlock(&drvdata->byte_cntr_lock);
+
+	if (*ppos + len >= drvdata->size)
+		*ppos = 0;
+	else
+		*ppos += len;
+
+	dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+		__func__, len, (int) (drvdata->size - *ppos));
+	return len;
+
+read_err0:
+	mutex_unlock(&drvdata->byte_cntr_lock);
+read_err1:
+	return ret;
+}
+
+static int tmc_etr_byte_cntr_release(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = file->private_data;
+
+	mutex_lock(&drvdata->byte_cntr_lock);
+	drvdata->byte_cntr_read_active = false;
+	mutex_unlock(&drvdata->byte_cntr_lock);
+	mutex_unlock(&drvdata->byte_cntr_read_lock);
+	dev_dbg(drvdata->dev, "%s: released\n", __func__);
+	return 0;
+}
+
+static const struct file_operations byte_cntr_fops = {
+	.owner		= THIS_MODULE,
+	.open		= tmc_etr_byte_cntr_open,
+	.read		= tmc_etr_byte_cntr_read,
+	.release	= tmc_etr_byte_cntr_release,
+	.llseek		= no_llseek,
+};
+
 static ssize_t tmc_show_trigger_cntr(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
@@ -1044,6 +1272,41 @@
 static DEVICE_ATTR(out_mode, S_IRUGO | S_IWUSR, tmc_etr_show_out_mode,
 		   tmc_etr_store_out_mode);
 
+static ssize_t tmc_etr_show_byte_cntr_value(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->byte_cntr_value;
+
+	if (!drvdata->byte_cntr_present)
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_byte_cntr_value(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->byte_cntr_present || drvdata->byte_cntr_enable)
+		return -EPERM;
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if ((drvdata->size / 8) < val)
+		return -EINVAL;
+	if (drvdata->size % (val * 8) != 0)
+		return -EINVAL;
+
+	drvdata->byte_cntr_value = val;
+	return size;
+}
+static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
+		   tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
+
 static struct attribute *tmc_attrs[] = {
 	&dev_attr_trigger_cntr.attr,
 	NULL,
@@ -1055,6 +1318,7 @@
 
 static struct attribute *tmc_etr_attrs[] = {
 	&dev_attr_out_mode.attr,
+	&dev_attr_byte_cntr_value.attr,
 	NULL,
 };
 
@@ -1118,6 +1382,113 @@
 	sps_deregister_bam_device(bamdata->handle);
 }
 
+static irqreturn_t tmc_etr_byte_cntr_irq(int irq, void *data)
+{
+	struct tmc_drvdata *drvdata = data;
+
+	atomic_inc(&drvdata->byte_cntr_irq_cnt);
+	if (atomic_read(&drvdata->byte_cntr_irq_cnt) >
+			drvdata->byte_cntr_overflow_cnt) {
+		dev_err(drvdata->dev, "Byte counter overflow\n");
+		drvdata->byte_cntr_overflow = true;
+	}
+	wake_up(&drvdata->wq);
+	return IRQ_HANDLED;
+}
+
+static int tmc_etr_byte_cntr_dev_register(struct tmc_drvdata *drvdata)
+{
+	int ret;
+	struct device *device;
+	dev_t dev;
+
+	ret = alloc_chrdev_region(&dev, 0, 1, drvdata->byte_cntr_node);
+	if (ret)
+		goto dev_err0;
+	cdev_init(&drvdata->byte_cntr_dev, &byte_cntr_fops);
+	drvdata->byte_cntr_dev.owner = THIS_MODULE;
+	drvdata->byte_cntr_dev.ops = &byte_cntr_fops;
+	ret = cdev_add(&drvdata->byte_cntr_dev, dev, 1);
+	if (ret)
+		goto dev_err1;
+	drvdata->byte_cntr_class = class_create(THIS_MODULE,
+						drvdata->byte_cntr_node);
+	if (!drvdata->byte_cntr_class)
+		goto dev_err2;
+	device = device_create(drvdata->byte_cntr_class, NULL,
+			       drvdata->byte_cntr_dev.dev, drvdata,
+			       drvdata->byte_cntr_node);
+	if (IS_ERR(device)) {
+		ret = PTR_ERR(device);
+		goto dev_err3;
+	}
+	return 0;
+dev_err3:
+	class_destroy(drvdata->byte_cntr_class);
+dev_err2:
+	cdev_del(&drvdata->byte_cntr_dev);
+dev_err1:
+	unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+dev_err0:
+	return ret;
+}
+
+static void tmc_etr_byte_cntr_dev_deregister(struct tmc_drvdata *drvdata)
+{
+	device_destroy(drvdata->byte_cntr_class, drvdata->byte_cntr_dev.dev);
+	class_destroy(drvdata->byte_cntr_class);
+	cdev_del(&drvdata->byte_cntr_dev);
+	unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+}
+
+static int tmc_etr_byte_cntr_init(struct platform_device *pdev,
+				  struct tmc_drvdata *drvdata)
+{
+	int ret = 0;
+	size_t node_size = strlen("-stream") + 1;
+	char *node_name = (char *)((struct coresight_platform_data *)
+			(pdev->dev.platform_data))->name;
+
+	if (!drvdata->byte_cntr_present) {
+		dev_info(&pdev->dev, "Byte Counter feature absent\n");
+		return 0;
+	}
+
+	drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
+							"byte-cntr-irq");
+	if (drvdata->byte_cntr_irq < 0) {
+		dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
+		return 0;
+	}
+	ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
+			tmc_etr_byte_cntr_irq,
+			IRQF_TRIGGER_RISING | IRQF_SHARED,
+			node_name, drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "Request irq failed\n");
+		return ret;
+	}
+	init_waitqueue_head(&drvdata->wq);
+	node_size += strlen(node_name);
+	drvdata->byte_cntr_node = devm_kzalloc(&pdev->dev,
+				node_size, GFP_KERNEL);
+	strlcpy(drvdata->byte_cntr_node, node_name, node_size);
+	strlcat(drvdata->byte_cntr_node, "-stream", node_size);
+	ret = tmc_etr_byte_cntr_dev_register(drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "Byte cntr node not registered\n");
+		return ret;
+	}
+	dev_info(&pdev->dev, "Byte Counter feature enabled\n");
+	return 0;
+}
+
+static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
+{
+	if (drvdata->byte_cntr_present)
+		tmc_etr_byte_cntr_dev_deregister(drvdata);
+}
+
 static int __devinit tmc_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -1162,6 +1533,9 @@
 	spin_lock_init(&drvdata->spinlock);
 	mutex_init(&drvdata->read_lock);
 	mutex_init(&drvdata->usb_lock);
+	mutex_init(&drvdata->byte_cntr_lock);
+	mutex_init(&drvdata->byte_cntr_read_lock);
+	atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
 
 	drvdata->clk = devm_clk_get(dev, "core_clk");
 	if (IS_ERR(drvdata->clk))
@@ -1207,10 +1581,16 @@
 		memset(drvdata->vaddr, 0, drvdata->size);
 		drvdata->buf = drvdata->vaddr;
 		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
-
-		ret = tmc_etr_bam_init(pdev, drvdata);
+		if (pdev->dev.of_node)
+			drvdata->byte_cntr_present = !of_property_read_bool
+						     (pdev->dev.of_node,
+						     "qcom,byte-cntr-absent");
+		ret = tmc_etr_byte_cntr_init(pdev, drvdata);
 		if (ret)
 			goto err0;
+		ret = tmc_etr_bam_init(pdev, drvdata);
+		if (ret)
+			goto err1;
 	} else {
 		baddr = devm_kzalloc(dev, PAGE_SIZE + drvdata->size,
 				     GFP_KERNEL);
@@ -1277,7 +1657,7 @@
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
-		goto err1;
+		goto err2;
 	}
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1290,7 +1670,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err1;
+			goto err2;
 		}
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1303,7 +1683,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err1;
+			goto err2;
 		}
 	} else {
 		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
@@ -1317,7 +1697,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err1;
+			goto err2;
 		}
 	}
 
@@ -1327,14 +1707,16 @@
 	drvdata->miscdev.fops = &tmc_fops;
 	ret = misc_register(&drvdata->miscdev);
 	if (ret)
-		goto err2;
+		goto err3;
 
 	dev_info(dev, "TMC initialized\n");
 	return 0;
-err2:
+err3:
 	coresight_unregister(drvdata->csdev);
-err1:
+err2:
 	tmc_etr_bam_exit(drvdata);
+err1:
+	tmc_etr_byte_cntr_exit(drvdata);
 err0:
 	free_contiguous_memory_by_paddr(drvdata->paddr);
 	return ret;
@@ -1344,6 +1726,7 @@
 {
 	struct tmc_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	tmc_etr_byte_cntr_exit(drvdata);
 	misc_deregister(&drvdata->miscdev);
 	coresight_unregister(drvdata->csdev);
 	tmc_etr_bam_exit(drvdata);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 76c6350..4c05978 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -188,12 +188,7 @@
 	min_rev = (rev & CRYPTO_CORE_MINOR_REV_MASK) >> CRYPTO_CORE_MINOR_REV;
 	step_rev = (rev & CRYPTO_CORE_STEP_REV_MASK) >> CRYPTO_CORE_STEP_REV;
 
-	if ((maj_rev != 0x05) || (min_rev > 0x02) || (step_rev > 0x02)) {
-		pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
-			pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
-		return -EIO;
-	};
-	if ((min_rev > 0)  && (step_rev != 0)) {
+	if (maj_rev != 0x05) {
 		pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
 			pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
 		return -EIO;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5415f4e..b725200 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1996,7 +1996,7 @@
 		if (atomic_read(&data->st_enabled) == 0)
 			break;
 
-		pm_runtime_put(&data->client->adapter->dev);
+		pm_runtime_put(data->client->adapter->dev.parent);
 		atomic_set(&data->st_enabled, 0);
 		complete(&data->st_completion);
 		mxt_interrupt(data->client->irq, data);
@@ -2015,8 +2015,9 @@
 		}
 		INIT_COMPLETION(data->st_completion);
 		INIT_COMPLETION(data->st_powerdown);
-		atomic_set(&data->st_pending_irqs, 0);
 		atomic_set(&data->st_enabled, 1);
+		synchronize_irq(data->client->irq);
+		atomic_set(&data->st_pending_irqs, 0);
 		break;
 	default:
 		dev_err(&data->client->dev, "unsupported value: %lu\n", value);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ba0be2b..908d0d7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1056,6 +1056,8 @@
 
 	rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
 			"synaptics,i2c-pull-up");
+	rmi4_pdata->power_down_enable = of_property_read_bool(np,
+			"synaptics,power-down");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
 
@@ -2003,7 +2005,7 @@
 
 error_reg_en_vcc_i2c:
 	if (rmi4_data->board->i2c_pull_up)
-		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
 error_reg_opt_i2c:
 	regulator_disable(rmi4_data->vdd);
 error_reg_en_vdd:
@@ -2592,29 +2594,53 @@
 						bool on)
 {
 	int retval;
+	int load_ua;
 
 	if (on == false)
 		goto regulator_hpm;
 
-	retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+	load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+	retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
-			"Regulator vcc_ana set_opt failed rc=%d\n",
+			"Regulator vdd_ana set_opt failed rc=%d\n",
 			retval);
 		goto fail_regulator_lpm;
 	}
 
-	if (rmi4_data->board->i2c_pull_up) {
-		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
-			RMI4_I2C_LPM_LOAD_UA);
-		if (retval < 0) {
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_disable(rmi4_data->vdd);
+		if (retval) {
 			dev_err(&rmi4_data->i2c_client->dev,
-				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				"Regulator vdd disable failed rc=%d\n",
 				retval);
 			goto fail_regulator_lpm;
 		}
 	}
 
+	if (rmi4_data->board->i2c_pull_up) {
+		load_ua = rmi4_data->board->power_down_enable ?
+			0 : RMI4_I2C_LPM_LOAD_UA;
+		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+			load_ua);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vcc_i2c set_opt failed " \
+				"rc=%d\n", retval);
+			goto fail_regulator_lpm;
+		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_disable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c disable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_lpm;
+			}
+		}
+	}
+
 	return 0;
 
 regulator_hpm:
@@ -2628,6 +2654,16 @@
 		goto fail_regulator_hpm;
 	}
 
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_enable(rmi4_data->vdd);
+		if (retval) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vdd enable failed rc=%d\n",
+				retval);
+			goto fail_regulator_hpm;
+		}
+	}
+
 	if (rmi4_data->board->i2c_pull_up) {
 		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
 			RMI4_I2C_LOAD_UA);
@@ -2637,6 +2673,26 @@
 				retval);
 			goto fail_regulator_hpm;
 		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_enable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c enable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_hpm;
+			}
+		}
+	}
+
+	if (rmi4_data->board->power_down_enable) {
+		retval = synaptics_rmi4_reset_device(rmi4_data);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to issue reset command, rc = %d\n",
+					__func__, retval);
+			return retval;
+		}
 	}
 
 	return 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8b0f6f1..a4eb274 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1036,7 +1036,7 @@
 }
 #endif
 
-void msm_cpp_do_timeout_work(struct work_struct *work)
+static void msm_cpp_do_timeout_work(struct work_struct *work)
 {
 	int ret;
 	uint32_t i = 0;
@@ -1046,6 +1046,11 @@
 
 	pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
 		del_timer_idx, jiffies);
+	if (!work || !this_frame) {
+		pr_err("Invalid work:%p, this_frame:%p, del_idx:%d\n",
+			work, this_frame, del_timer_idx);
+		return;
+	}
 	pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
 		this_frame->identity, this_frame->frame_id);
 	cpp_timers[del_timer_idx].used = 0;
@@ -1304,7 +1309,8 @@
 		(cpp_frame_msg[12] & 0x3FF);
 
 	fw_version_1_2_x = 0;
-	if (cpp_dev->hw_info.cpp_hw_version == 0x10010000)
+	if ((cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_0) ||
+		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1))
 		fw_version_1_2_x = 2;
 
 	for (i = 0; i < num_stripes; i++) {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 0a70d37..796bede 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -21,6 +21,14 @@
 #include <media/v4l2-subdev.h>
 #include "msm_sd.h"
 
+/* hw version info:
+  31:28  Major version
+  27:16  Minor version
+  15:0   Revision bits
+**/
+#define CPP_HW_VERSION_1_1_0  0x10010000
+#define CPP_HW_VERSION_1_1_1  0x10010001
+
 #define MAX_ACTIVE_CPP_INSTANCE 8
 #define MAX_CPP_PROCESSING_FRAME 2
 #define MAX_CPP_V4l2_EVENTS 30
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 44105ad..a63ee61 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1230,7 +1230,7 @@
 			hfi_msg_sys_session_abort_done_packet*) msg_hdr);
 		break;
 	default:
-		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+		dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1c43f1e..b6d031a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -477,14 +477,14 @@
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"Failed to initialize vb2 queue on capture port\n");
-		goto fail_init;
+		goto fail_bufq_capture;
 	}
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
 			session_type);
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"Failed to initialize vb2 queue on capture port\n");
-		goto fail_init;
+		goto fail_bufq_output;
 	}
 	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
 	if (rc) {
@@ -502,6 +502,14 @@
 	mutex_unlock(&core->lock);
 	return inst;
 fail_init:
+	vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+fail_bufq_output:
+	vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+	if (session_type == MSM_VIDC_DECODER)
+		msm_vdec_ctrl_deinit(inst);
+	else if (session_type == MSM_VIDC_ENCODER)
+		msm_venc_ctrl_deinit(inst);
 	msm_smem_delete_client(inst->mem_client);
 fail_mem_client:
 	kfree(inst);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 8121471..9cd199b 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -296,24 +296,13 @@
 static long set_default_properties(struct venc_inst *inst)
 {
 	struct v4l2_control ctrl = {0};
-	int rc;
 
 	/* Set the IDR period as 1.  The venus core doesn't give
 	 * the sps/pps for I-frames, only IDR. */
 	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
 	ctrl.value = 1;
-	rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
-	if (rc)
-		WFD_MSG_WARN("Failed to set IDR period\n");
 
-	/* Set the default rc mode to VBR/VFR, client can change later */
-	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
-	ctrl.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
-	rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
-	if (rc)
-		WFD_MSG_WARN("Failed to set rc mode\n");
-
-	return 0;
+	return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
 }
 
 static int subscribe_events(struct venc_inst *inst)
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 28f9e80..7934234 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2420,9 +2420,11 @@
 		FMDERR("AF list size received more than available size");
 		return;
 	}
-	memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
+	memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET],
+					ev.af_size * sizeof(int));
 	iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
-	iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
+	iris_q_evt_data(radio, (char *)&ev, (7 + ev.af_size * sizeof(int)),
+							IRIS_BUF_AF_LIST);
 }
 
 static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9527249..654dbcb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1496,9 +1496,11 @@
 	int vdd_bit = -1;
 	u8 ctrl;
 
+	mutex_lock(&host->ios_mutex);
 	if (host->flags & SDHCI_DEVICE_DEAD) {
 		if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
 			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+		mutex_unlock(&host->ios_mutex);
 		return;
 	}
 
@@ -1508,6 +1510,7 @@
 	spin_lock_irqsave(&host->lock, flags);
 	if (!host->clock) {
 		spin_unlock_irqrestore(&host->lock, flags);
+		mutex_unlock(&host->ios_mutex);
 		return;
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -1664,6 +1667,7 @@
 		sdhci_set_clock(host, ios->clock);
 
 	mmiowb();
+	mutex_unlock(&host->ios_mutex);
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -2900,6 +2904,7 @@
 	host->mmc = mmc;
 
 	spin_lock_init(&host->lock);
+	mutex_init(&host->ios_mutex);
 
 	return host;
 }
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 9e9a4ea..e832716 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -27,7 +27,6 @@
 #include <linux/regulator/consumer.h>
 #include "nfc-nci.h"
 
-
 struct qca199x_platform_data {
 	unsigned int irq_gpio;
 	unsigned int dis_gpio;
@@ -62,6 +61,7 @@
 	bool irq_enabled;
 	spinlock_t irq_enabled_lock;
 	unsigned int count_irq;
+	enum	nfcc_state	state;
 };
 
 /*
@@ -69,6 +69,12 @@
  * IOCTL NFC_KERNEL_LOGGING_MODE.
  */
 static int logging_level;
+/*
+ * FTM-RAW-I2C RD/WR MODE
+ */
+static struct	devicemode	device_mode;
+static int	ftm_raw_write_mode;
+static int	ftm_werr_code;
 
 static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
 {
@@ -104,7 +110,6 @@
 	struct qca199x_dev *qca199x_dev = dev_id;
 	unsigned long flags;
 
-
 	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
 	qca199x_dev->count_irq++;
 	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
@@ -119,7 +124,6 @@
 	unsigned int mask = 0;
 	unsigned long flags;
 
-
 	poll_wait(filp, &qca199x_dev->read_wq, wait);
 
 	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
@@ -129,17 +133,33 @@
 	}
 	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
 
-
 	return mask;
 }
 
+/*
+ * ONLY for FTM-RAW-I2C Mode
+ * Required to instigate a read, which comes from DT layer. This means we need
+ * to spoof an interrupt and send a wake up event.
+ */
+void ftm_raw_trigger_read(struct qca199x_dev *qca199x_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+	qca199x_dev->count_irq++;
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+	wake_up(&qca199x_dev->read_wq);
+}
+
 static ssize_t nfc_read(struct file *filp, char __user *buf,
 					size_t count, loff_t *offset)
 {
 	struct qca199x_dev *qca199x_dev = filp->private_data;
-	unsigned char tmp[MAX_BUFFER_SIZE];
+	unsigned char tmp[MAX_BUFFER_SIZE], rd_byte;
 	unsigned char len[PAYLOAD_HEADER_LENGTH];
 	int total, length, ret;
+	int ftm_rerr_code;
+	enum ehandler_mode dmode;
 
 	total = 0;
 	length = 0;
@@ -147,6 +167,36 @@
 		count = MAX_BUFFER_SIZE;
 
 	mutex_lock(&qca199x_dev->read_mutex);
+	dmode = device_mode.handle_flavour;
+	/* FTM-RAW-I2C RD/WR MODE - Special Case */
+	if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+		(dmode == SOLICITED_FTM_RAW_MODE)) {
+		/* READ */
+		if ((ftm_raw_write_mode == 0) && (ftm_werr_code == 0)) {
+			ftm_rerr_code = i2c_master_recv(qca199x_dev->client,
+						&rd_byte, 1);
+			if (ftm_rerr_code == 0x1)
+				ftm_rerr_code = 0;
+			tmp[0] = (unsigned char)ftm_rerr_code;
+			tmp[1] = rd_byte;
+			total  = 2;
+			ret = copy_to_user(buf, tmp, total);
+		}
+		/* WRITE */
+		else if ((ftm_raw_write_mode == 1) || (ftm_werr_code != 0)) {
+			tmp[0] = (unsigned char)ftm_werr_code;
+			total = 1;
+			ret = copy_to_user(buf, tmp, total);
+		} else {
+			/* Invalid case */
+			total = 0;
+			ret = copy_to_user(buf, tmp, total);
+		}
+		mutex_unlock(&qca199x_dev->read_mutex);
+		goto done;
+	}
+
+	/* NORMAL NCI Behaviour */
 	/* Read the header */
 	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
 	if (ret != PAYLOAD_HEADER_LENGTH)
@@ -174,7 +224,7 @@
 err:
 	if (ret < 0)
 		mutex_unlock(&qca199x_dev->read_mutex);
-
+done:
 	return total;
 }
 
@@ -183,7 +233,8 @@
 {
 	struct qca199x_dev *qca199x_dev = filp->private_data;
 	char tmp[MAX_BUFFER_SIZE];
-	int ret;
+	int ret = 0;
+	enum ehandler_mode dmode;
 
 	if (count > MAX_BUFFER_SIZE) {
 		dev_err(&qca199x_dev->client->dev, "out of memory\n");
@@ -195,10 +246,39 @@
 		return -EFAULT;
 	}
 	mutex_lock(&qca199x_dev->read_mutex);
-	ret = i2c_master_send(qca199x_dev->client, tmp, count);
+	dmode = device_mode.handle_flavour;
+	/* FTM-DIRECT-I2C RD/WR MODE */
+	/* This is a special FTM-i2c mode case,where tester is not using NCI */
+	if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+		(dmode == SOLICITED_FTM_RAW_MODE)) {
+		/* Read From Register */
+		if (count == 1) {
+			ftm_raw_write_mode = 0;
+			ret = i2c_master_send(qca199x_dev->client, tmp, count);
+			if (ret == 1)
+				ftm_werr_code = 0;
+			else
+				ftm_werr_code = ret;
+			ftm_raw_trigger_read(qca199x_dev);
+		}
+		/* Write to Register */
+		if (count == 2) {
+			ftm_raw_write_mode = 1;
+			ret = i2c_master_send(qca199x_dev->client, tmp, count);
+			if (ret == 2)
+				ftm_werr_code = 0;
+			else
+				ftm_werr_code = ret;
+			ftm_raw_trigger_read(qca199x_dev);
+		}
+	} else {
+		/* NORMAL NCI behaviour - NB :
+		We can be in FTM mode here also */
+		ret = i2c_master_send(qca199x_dev->client, tmp, count);
+	}
 	if (ret != count) {
 		dev_err(&qca199x_dev->client->dev,
-			"NFC: failed to write %d\n", ret);
+		"NFC: failed to write %d\n", ret);
 		ret = -EIO;
 	}
 	mutex_unlock(&qca199x_dev->read_mutex);
@@ -225,7 +305,7 @@
 /*
  * Wake/Sleep Mode
  */
-int nfcc_wake(int level, struct nfc_info *info)
+int nfcc_wake(int level, struct file *filp)
 {
 	int r = 0;
 	unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
@@ -233,32 +313,32 @@
 	unsigned char raw_nci_wake[]  = {0x10, 0x0F};
 	unsigned short	slave_addr	=	0xE;
 	unsigned short	curr_addr;
+	struct qca199x_dev *qca199x_dev = filp->private_data;
 
-	struct i2c_client *client = info->i2c_dev;
-
-	dev_dbg(&client->dev, "nfcc_wake: %s: info: %p\n", __func__, info);
+	dev_dbg(&qca199x_dev->client->dev, "nfcc_wake: %s: info: %p\n",
+			__func__, qca199x_dev);
 
 	if (level == NFCC_SLEEP) {
-		r = nfc_i2c_write(client, &raw_nci_sleep[0],
+		r = i2c_master_send(qca199x_dev->client, &raw_nci_sleep[0],
 						sizeof(raw_nci_sleep));
 
+		r = sizeof(raw_nci_sleep);
 		if (r != sizeof(raw_nci_sleep))
 			return -EMSGSIZE;
-		info->state = NFCC_STATE_NORMAL_SLEEP;
+		qca199x_dev->state = NFCC_STATE_NORMAL_SLEEP;
 	} else {
-		curr_addr = client->addr;
-		client->addr = slave_addr;
-		r = nfc_i2c_write(client, &raw_nci_wake[0],
+		curr_addr = qca199x_dev->client->addr;
+		qca199x_dev->client->addr = slave_addr;
+		r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
 						sizeof(raw_nci_wake));
 		/* Restore original NFCC slave I2C address */
-		client->addr = curr_addr;
-
-		if (r != sizeof(raw_nci_sleep))
+		qca199x_dev->client->addr = curr_addr;
+		r = sizeof(raw_nci_wake);
+		if (r != sizeof(raw_nci_wake))
 			return -EMSGSIZE;
-
-		info->state = NFCC_STATE_NORMAL_WAKE;
+		qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
 	}
-	msleep(20);
+
 	return r;
 }
 
@@ -284,41 +364,35 @@
 {
 	int r = 0;
 	struct qca199x_dev *qca199x_dev = filp->private_data;
-	struct nfc_info *info = container_of(filp->private_data,
-					       struct nfc_info, miscdev);
-
-	struct i2c_client *client = info->i2c_dev;
-
-	r = gpio_request(qca199x_dev->dis_gpio, "nfc_reset_gpio");
-	if (r) {
-		dev_err(&client->dev, "unable to request gpio [%d]\n",
-				qca199x_dev->dis_gpio);
-			goto err_req;
-	}
-	gpio_set_value(qca199x_dev->dis_gpio, 0);
-	r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
-	if (r) {
-		dev_err(&client->dev, "unable to set direction for gpio [%d]\n",
-				qca199x_dev->irq_gpio);
-			goto err_req;
-	}
 
 	if (arg == 0) {
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
-		msleep(20);
+		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+		if (r) {
+			dev_err(&qca199x_dev->client->dev,
+					"unable to set direction for gpio [%d]\n",
+					qca199x_dev->dis_gpio);
+			goto err_req;
+		}
+		gpio_set_value(qca199x_dev->dis_gpio, 0);
 	} else if (arg == 1) {
+		gpio_set_value(qca199x_dev->dis_gpio, 0);
+		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+		if (r) {
+			dev_err(&qca199x_dev->client->dev,
+					"unable to set direction for gpio [%d]\n",
+					qca199x_dev->dis_gpio);
+			goto err_req;
+		}
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
-		msleep(20);
 	} else if (arg == 2) {
 		msleep(20);
 	} else if (arg == 3) {
 		msleep(20);
 	} else if (arg == 4) {
-		nfcc_wake(NFCC_WAKE, info);
-		msleep(20);
+		nfcc_wake(NFCC_WAKE, filp);
 	} else if (arg == 5) {
-		nfcc_wake(NFCC_SLEEP, info);
-		msleep(20);
+		nfcc_wake(NFCC_SLEEP, filp);
 	} else {
 		r = -ENOIOCTLCMD;
 	}
@@ -327,6 +401,63 @@
 	return r;
 }
 
+
+/*
+ * Inside nfc_ioctl_nfcc_mode
+ *
+ * @brief   nfc_ioctl_nfcc_mode
+ *
+ * (arg = 0) ; NORMAL_MODE - Standard mode, unsolicited read behaviour
+ * (arg = 1) ; SOLICITED_MODE - As above but reads are solicited from User Land
+ * (arg = 2) ; UNSOLICITED_FTM_RAW MODE - NORMAL_MODE but messages from FTM and
+ *             not NCI Host.
+ * (arg = 2) ; SOLICITED_FTM_RAW_MODE - As SOLICITED_MODE but messages from FTM
+ *             and not NCI Host.
+ *
+ *
+ *
+ */
+int nfc_ioctl_nfcc_mode(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	static unsigned short nci_addr;
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	struct qca199x_platform_data *platform_data;
+
+	platform_data = qca199x_dev->client->dev.platform_data;
+
+	if (arg == 0) {
+		device_mode.handle_flavour = UNSOLICITED_MODE;
+		qca199x_dev->client->addr = NCI_I2C_SLAVE;
+		/* enable interrupts again */
+		qca199x_enable_irq(qca199x_dev);
+	} else if (arg == 1) {
+		device_mode.handle_flavour = SOLICITED_MODE;
+		qca199x_dev->client->addr = qca199x_dev->client->addr;
+		/* enable interrupts again */
+		qca199x_enable_irq(qca199x_dev);
+	} else if (arg == 2) {
+		device_mode.handle_flavour = UNSOLICITED_FTM_RAW_MODE;
+		nci_addr = qca199x_dev->client->addr;
+		/* replace with new client slave address*/
+		qca199x_dev->client->addr = 0xE;
+		/* We also need to disable interrupts */
+		qca199x_disable_irq(qca199x_dev);
+	} else if (arg == 3) {
+		device_mode.handle_flavour = SOLICITED_FTM_RAW_MODE;
+		nci_addr = qca199x_dev->client->addr;
+		/* replace with new client slave address*/
+		qca199x_dev->client->addr = 0xE;
+		/* We also need to disable interrupts */
+		qca199x_disable_irq(qca199x_dev);
+	} else {
+		device_mode.handle_flavour = UNSOLICITED_MODE;
+		qca199x_dev->client->addr = NCI_I2C_SLAVE;
+	}
+	return retval;
+}
+
 /*
  * Inside nfc_ioctl_kernel_logging
  *
@@ -371,6 +502,7 @@
 		nfc_ioctl_power_states(pfile, cmd, arg);
 		break;
 	case NFCC_MODE:
+		nfc_ioctl_nfcc_mode(pfile, cmd, arg);
 		break;
 	case NFC_KERNEL_LOGGING_MODE:
 		nfc_ioctl_kernel_logging(arg, pfile);
@@ -447,66 +579,75 @@
 	unsigned char raw_s73[]			= {0x73, 0x02};
 	unsigned char raw_slave1_rd		= {0x0};
 	unsigned char raw_1P8_PAD_CFG_CLK_REQ[]	= {0xA5, 0x1};
-	unsigned char buf[4];
+	unsigned char raw_1P8_PAD_CFG_PWR_REQ[]	= {0xA7, 0x1};
+	unsigned char buf = 0;
 
-	/* Set I2C address to enable configuration of QCA1990 */
 	client->addr = curr_addr;
-	RAW(s73, 0x02);
+	r = i2c_master_send(client, &buf, 1);
+	buf = 0;
+	r = i2c_master_recv(client, &buf, 1);
+	if (0x10 != (0x10 & buf)) {
+		RAW(s73, 0x02);
 
-	r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
-	usleep(1000);
-	RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+		r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+		usleep(1000);
+		RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
 
-	r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+		r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
 						sizeof(raw_1p8_CONTROL_011));
-	usleep(1000);
-	RAW(1P8_CONTROL_010, (0x8));
-	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-					sizeof(raw_1P8_CONTROL_010));
-
-	usleep(10000);  /* 10ms wait */
-	RAW(1P8_CONTROL_010, (0xC));
-	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-					sizeof(raw_1P8_CONTROL_010));
-	usleep(100);  /* 100uS wait */
-	RAW(1P8_X0_0B0, (FREQ_SEL_19));
-	r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0));
-	usleep(1000);
-
-	/* PWR_EN = 1 */
-	RAW(1P8_CONTROL_010, (0xd));
-	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+		usleep(1000);
+		RAW(1P8_CONTROL_010, (0x8));
+		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
 						sizeof(raw_1P8_CONTROL_010));
-	usleep(20000);  /* 20ms wait */
-	/* LS_EN = 1 */
-	RAW(1P8_CONTROL_010, 0xF);
-	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-						sizeof(raw_1P8_CONTROL_010));
-	usleep(20000);  /* 20ms wait */
 
-	/* Enable the PMIC clock */
-	RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
-	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+		usleep(10000);  /* 10ms wait */
+		RAW(1P8_CONTROL_010, (0xC));
+		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+					sizeof(raw_1P8_CONTROL_010));
+		usleep(100);  /* 100uS wait */
+		RAW(1P8_X0_0B0, (FREQ_SEL_19));
+		r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+						sizeof(raw_1P8_X0_0B0));
+		usleep(1000);
+
+		/* PWR_EN = 1 */
+		RAW(1P8_CONTROL_010, (0xd));
+		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+						sizeof(raw_1P8_CONTROL_010));
+		usleep(20000);  /* 20ms wait */
+		/* LS_EN = 1 */
+		RAW(1P8_CONTROL_010, 0xF);
+		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+						sizeof(raw_1P8_CONTROL_010));
+		usleep(20000);  /* 20ms wait */
+
+		/* Enable the PMIC clock */
+		RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+		r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
 					  sizeof(raw_1P8_PAD_CFG_CLK_REQ));
-	usleep(1000);
+		usleep(1000);
 
-	RAW(slave2, 0x10);
-	r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
-	usleep(1000);
-	{
-		r = i2c_master_send(client, buf, 1);
-		memset(buf, 0xAA, sizeof(buf));
-		r = i2c_master_recv(client, buf, 1);
+		RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+		r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+					  sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+		usleep(1000);
+
+		RAW(slave2, 0x10);
+		r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+		usleep(1000);
+
+		RAW(slave1, NCI_I2C_SLAVE);
+		r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+		usleep(1000);
+
+		/* QCA199x NFCC CPU should now boot... */
+		r = i2c_master_recv(client, &raw_slave1_rd, 1);
+		/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+		client->addr = NCI_I2C_SLAVE;
+		r = 0;
+	} else {
+		r = 1;
 	}
-	RAW(slave1, NCI_I2C_SLAVE);
-	r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
-	usleep(1000);
-
-	/* QCA199x NFCC CPU should now boot... */
-	r = i2c_master_recv(client, &raw_slave1_rd, 1);
-	/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
-	client->addr = NCI_I2C_SLAVE;
-
 	return r;
 }
 
@@ -623,6 +764,9 @@
 		dev_err(&client->dev, "dis gpio not provided\n");
 		goto err_irq;
 	}
+	gpio_set_value(qca199x_dev->dis_gpio, 1);
+	msleep(20);
+	gpio_set_value(qca199x_dev->dis_gpio, 0);
 
 	nfc_clk  = clk_get(&client->dev, "ref_clk");
 
@@ -640,7 +784,7 @@
 		r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
 		if (r) {
 			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->irq_gpio);
+						platform_data->ven_gpio);
 			goto err_ven_gpio;
 		}
 		r = gpio_direction_input(platform_data->ven_gpio);
@@ -648,7 +792,7 @@
 
 			dev_err(&client->dev,
 			"unable to set direction for gpio [%d]\n",
-						platform_data->irq_gpio);
+						platform_data->ven_gpio);
 			goto err_ven_gpio;
 		}
 
@@ -681,7 +825,12 @@
 	/* request irq.  The irq is set whenever the chip has data available
 	* for reading.  It is cleared when all data has been read.
 	*/
-	nfcc_initialise(client, platform_data->reg);
+	device_mode.handle_flavour = UNSOLICITED_MODE;
+	r = nfcc_initialise(client, platform_data->reg);
+	if (r) {
+		dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n");
+		goto err_nfcc_init_failed;
+	}
 
 	qca199x_dev->irq_enabled = true;
 	r = request_irq(client->irq, qca199x_dev_irq_handler,
@@ -697,6 +846,7 @@
 		 __func__);
 	return 0;
 
+err_nfcc_init_failed:
 err_request_irq_failed:
 	misc_deregister(&qca199x_dev->qca199x_device);
 err_misc_register:
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 4398df7..c3cabc2 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -30,8 +30,10 @@
 };
 
 enum ehandler_mode {
-	UNSOLICITED_READ_MODE = 0,
-	SOLICITED_READ_MODE
+	UNSOLICITED_MODE = 0,
+	SOLICITED_MODE,
+	UNSOLICITED_FTM_RAW_MODE,
+	SOLICITED_FTM_RAW_MODE
 };
 
 enum ekernel_logging_mode {
@@ -43,9 +45,9 @@
 	LEVEL_5
 };
 
-struct DeviceMode {
+struct devicemode {
 	enum ehandler_mode	handle_flavour;
-} tDeviceMode;
+} tdevicemode;
 
 #define NFC_DRIVER_NAME			"nfc-nci"
 #define NFC_I2C_DRIVER_NAME		"NCI NFC I2C Interface",
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index c8e5163..e36806f 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1186,6 +1186,7 @@
 	int ret;
 	struct smux_lch_t *ch;
 	int enable_powerdown = 0;
+	int tx_ready = 0;
 
 	lcid = pkt->hdr.lcid;
 	ch = &smux_lch[lcid];
@@ -1203,7 +1204,7 @@
 		if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
 			schedule_notify(lcid, SMUX_CONNECTED, NULL);
 			if (!(list_empty(&ch->tx_queue)))
-				list_channel(ch);
+				tx_ready = 1;
 		}
 		ret = 0;
 	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
@@ -1226,6 +1227,9 @@
 		spin_unlock(&smux.tx_lock_lha2);
 	}
 
+	if (tx_ready)
+		list_channel(ch);
+
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 96f0f8c..f2de17d 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -857,6 +857,26 @@
 	return ret;
 }
 
+static int msm_dsi_cont_on(struct mdss_panel_data *pdata)
+{
+	struct mdss_panel_info *pinfo;
+	int ret = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	pinfo = &pdata->panel_info;
+	ret = msm_dsi_regulator_enable();
+	if (ret) {
+		pr_err("%s: DSI power on failed\n", __func__);
+		return ret;
+	}
+
+	msm_dsi_ahb_ctrl(1);
+	msm_dsi_prepare_clocks();
+	msm_dsi_clk_enable();
+	return 0;
+}
+
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
 {
 	struct dsi_interface intf;
@@ -925,6 +945,7 @@
 	dsi_host_private->dis_dev = pdev->dev;
 	intf.on = msm_dsi_on;
 	intf.off = msm_dsi_off;
+	intf.cont_on = msm_dsi_cont_on;
 	intf.op_mode_config = msm_dsi_op_mode_config;
 	intf.tx = msm_dsi_cmds_tx;
 	intf.rx = msm_dsi_cmds_rx;
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 5c164e4..022d911 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -163,7 +163,20 @@
 
 	pr_debug("%s: enable = %d\n", __func__, enable);
 
-	if (enable) {
+	if (enable == 2) {
+		dsi_panel_power(1);
+		gpio_request(panel_private->rst_gpio, "panel_reset");
+		if (gpio_is_valid(panel_private->disp_en_gpio)) {
+			gpio_request(panel_private->disp_en_gpio,
+					"panel_enable");
+		}
+		if (gpio_is_valid(panel_private->video_mode_gpio)) {
+			gpio_request(panel_private->video_mode_gpio,
+					"panel_video_mdoe");
+		}
+		if (gpio_is_valid(panel_private->te_gpio))
+			gpio_request(panel_private->te_gpio, "panel_te");
+	} else if (enable == 1) {
 		dsi_panel_power(1);
 		gpio_request(panel_private->rst_gpio, "panel_reset");
 		gpio_set_value(panel_private->rst_gpio, 1);
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 1a9059c..686ec01 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -82,6 +82,25 @@
 	return rc;
 }
 
+static int dsi_splash_on(struct mdss_panel_data *pdata)
+{
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (panel_common_data->reset)
+		panel_common_data->reset(pdata, 2);
+
+	if (dsi_intf.cont_on)
+		rc = dsi_intf.cont_on(pdata);
+
+	if (rc) {
+		pr_err("mdss_dsi_on DSI failed %d\n", rc);
+		return rc;
+	}
+	return rc;
+}
+
 static int dsi_event_handler(struct mdss_panel_data *pdata,
 				int event, void *arg)
 {
@@ -105,6 +124,9 @@
 	case MDSS_EVENT_PANEL_OFF:
 		rc = dsi_panel_handler(pdata, 0);
 		break;
+	case MDSS_EVENT_CONT_SPLASH_BEGIN:
+		rc = dsi_splash_on(pdata);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 54b772b..96dd390 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -198,6 +198,7 @@
 struct dsi_interface {
 	int (*on)(struct mdss_panel_data *pdata);
 	int (*off)(struct mdss_panel_data *pdata);
+	int (*cont_on)(struct mdss_panel_data *pdata);
 	void (*op_mode_config)(int mode, struct mdss_panel_data *pdata);
 	int (*tx)(struct mdss_panel_data *pdata,
 		struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 66418db..f6f722e 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -959,6 +959,21 @@
 	return rc;
 }
 
+int mdp3_iommu_is_attached(int client)
+{
+	struct mdp3_iommu_ctx_map *context_map;
+	int context = MDP3_IOMMU_CTX_DMA_0;
+
+	if (!mdp3_res->iommu_contexts)
+		return 0;
+
+	if (client == MDP3_CLIENT_PPP)
+		context = MDP3_IOMMU_CTX_PPP_0;
+
+	context_map = mdp3_res->iommu_contexts + context;
+	return context_map->attached;
+}
+
 static int mdp3_init(struct msm_fb_data_type *mfd)
 {
 	int rc;
@@ -982,6 +997,66 @@
 		return xres * bpp;
 }
 
+void mdp3_fbmem_clear(void)
+{
+	if (mdp3_res->ion_handle && mdp3_res->virt) {
+		pr_debug("mdp3_fbmem_clear\n");
+		memset(mdp3_res->virt, 0, mdp3_res->size);
+	}
+}
+
+static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
+{
+	int ret = 0;
+
+	if (mdp3_res->ion_handle) {
+		pr_debug("memory already alloc\n");
+		*virt = mdp3_res->virt;
+		*phys = mdp3_res->phys;
+		return 0;
+	}
+
+	mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
+					SZ_1M,
+					ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+
+	if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
+		*virt = ion_map_kernel(mdp3_res->ion_client,
+					mdp3_res->ion_handle);
+		if (IS_ERR(*virt)) {
+			pr_err("map kernel error\n");
+			goto ion_map_kernel_err;
+		}
+
+		ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
+				phys, &size);
+		if (ret) {
+			pr_err("%s ion_phys error\n", __func__);
+			goto ion_map_phys_err;
+		}
+
+		mdp3_res->virt = *virt;
+		mdp3_res->phys = *phys;
+		mdp3_res->size = size;
+	} else {
+		pr_err("%s ion alloc fail\n", __func__);
+		mdp3_res->ion_handle = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+
+ion_map_phys_err:
+	ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
+ion_map_kernel_err:
+	ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
+	mdp3_res->ion_handle = NULL;
+	mdp3_res->virt = NULL;
+	mdp3_res->phys = 0;
+	mdp3_res->size = 0;
+	return -ENOMEM;
+}
+
 static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
 {
 	int ret = -ENOMEM, dom;
@@ -999,28 +1074,10 @@
 		return 0;
 	}
 
-	mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
-					SZ_1M,
-					ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-
-	if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
-		virt = ion_map_kernel(mdp3_res->ion_client,
-					mdp3_res->ion_handle);
-		if (IS_ERR(virt)) {
-			pr_err("%s map kernel error\n", __func__);
-			goto ion_map_kernel_err;
-		}
-
-		ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
-				&phys, &size);
-		if (ret) {
-			pr_err("%s ion_phys error\n", __func__);
-			goto ion_map_phys_err;
-		}
-	} else {
-		pr_err("%s ion alloc fail\n", __func__);
-		mdp3_res->ion_handle = NULL;
-		return -ENOMEM;
+	ret = mdp3_alloc(size, &virt, &phys);
+	if (ret) {
+		pr_err("fail to allocate fb memory\n");
+		return ret;
 	}
 
 	dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
@@ -1031,10 +1088,10 @@
 
 	if (ret) {
 		pr_err("%s map IOMMU error\n", __func__);
-		goto ion_map_phys_err;
+		goto ion_map_iommu_err;
 	}
 
-	pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+	pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
 			size, virt, phys, mfd->index);
 
 	mfd->fbi->screen_base = virt;
@@ -1042,17 +1099,19 @@
 	mfd->fbi->fix.smem_len = size;
 	return 0;
 
-ion_map_phys_err:
+ion_map_iommu_err:
 	ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-ion_map_kernel_err:
 	ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
 	mdp3_res->ion_handle = NULL;
+	mdp3_res->virt = NULL;
+	mdp3_res->phys = 0;
+	mdp3_res->size = 0;
 	return -ENOMEM;
 }
 
 void mdp3_fbmem_free(struct msm_fb_data_type *mfd)
 {
-	pr_info("mdp3_fbmem_free\n");
+	pr_debug("mdp3_fbmem_free\n");
 	if (mdp3_res->ion_handle) {
 		int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
 
@@ -1061,6 +1120,9 @@
 				dom, 0);
 		ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
 		mdp3_res->ion_handle = NULL;
+		mdp3_res->virt = NULL;
+		mdp3_res->phys = 0;
+		mdp3_res->size = 0;
 		mfd->fbi->screen_base = 0;
 		mfd->fbi->fix.smem_start = 0;
 		mfd->fbi->fix.smem_len = 0;
@@ -1103,6 +1165,130 @@
 	return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
 }
 
+int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
+{
+	unsigned long splash_phys, phys;
+	void *splash_virt, *virt;
+	u32 height, width, rgb_size, stride;
+	size_t size;
+	int rc;
+
+	rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
+	stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
+	stride = stride & 0x3FFF;
+	splash_phys = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
+
+	height = (rgb_size >> 16) & 0xffff;
+	width  = rgb_size & 0xffff;
+	size = PAGE_ALIGN(height * stride * 2);
+	pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
+		height, width, size);
+
+	rc = mdp3_alloc(size, &virt, &phys);
+	if (rc) {
+		pr_err("fail to allocate memory for continuous splash image\n");
+		return rc;
+	}
+
+	splash_virt = ioremap(splash_phys, stride * height);
+	memcpy(virt, splash_virt, stride * height);
+	iounmap(splash_virt);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, phys);
+
+	return 0;
+}
+
+static int mdp3_is_display_on(struct mdss_panel_data *pdata)
+{
+	int rc = 0;
+	u32 status;
+
+	mdp3_clk_update(MDP3_CLK_AHB, 1);
+	mdp3_clk_update(MDP3_CLK_CORE, 1);
+
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+		status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
+		rc = status & 0x1;
+	} else {
+		status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
+		rc = status & 01;
+	}
+
+	mdp3_clk_update(MDP3_CLK_AHB, 0);
+	mdp3_clk_update(MDP3_CLK_CORE, 0);
+	return rc;
+}
+
+static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
+{
+	struct mdss_panel_info *panel_info = &pdata->panel_info;
+	int ab, ib, rc;
+
+	pr_debug("mdp3__continuous_splash_on\n");
+
+	rc = mdp3_clk_enable(1);
+	if (rc) {
+		pr_err("fail to enable clk\n");
+		return rc;
+	}
+
+	ab = panel_info->xres * panel_info->yres * 4;
+	ab *= panel_info->mipi.frame_rate;
+	ib = (ab * 3) / 2;
+	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
+	if (rc) {
+		pr_err("fail to request bus bandwidth\n");
+		goto splash_on_err;
+	}
+
+	rc = mdp3_ppp_init();
+	if (rc) {
+		pr_err("ppp init failed\n");
+		goto splash_on_err;
+	}
+
+	rc = mdp3_continuous_splash_copy(pdata);
+	if (rc) {
+		pr_err("fail to copy continuous splash image\n");
+		goto splash_on_err;
+	}
+
+	mdp3_irq_register();
+
+	if (pdata->event_handler) {
+		rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
+					NULL);
+		if (rc) {
+			pr_err("MDSS_EVENT_CONT_SPLASH_BEGIN event fail\n");
+			goto splash_on_err;
+		}
+	}
+
+	if (panel_info->type == MIPI_VIDEO_PANEL)
+		mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
+	else
+		mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+	return 0;
+
+splash_on_err:
+	mdp3_clk_enable(0);
+	return rc;
+}
+
+static int mdp3_panel_register_done(struct mdss_panel_data *pdata)
+{
+	int rc = 0;
+
+	if (pdata->panel_info.cont_splash_enabled) {
+		if (!mdp3_is_display_on(pdata)) {
+			pr_err("continuous splash, but bootloader is not\n");
+			return 0;
+		}
+		rc = mdp3_continuous_splash_on(pdata);
+	}
+	return rc;
+}
+
 static int mdp3_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -1110,6 +1296,7 @@
 	.init_fnc = mdp3_init,
 	.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
 	.fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+	.panel_register_done = mdp3_panel_register_done,
 	.fb_stride = mdp3_fb_stride,
 	};
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index d29e5b6..03416c7 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -111,6 +111,9 @@
 	struct mdp3_iommu_domain_map *domains;
 	struct mdp3_iommu_ctx_map *iommu_contexts;
 	struct ion_handle *ion_handle;
+	void *virt;
+	unsigned long phys;
+	size_t size;
 
 	struct mdp3_dma dma[MDP3_DMA_MAX];
 	struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
@@ -151,7 +154,10 @@
 int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
 int mdp3_iommu_enable(int client);
 int mdp3_iommu_disable(int client);
+int mdp3_iommu_is_attached(int client);
 void mdp3_fbmem_free(struct msm_fb_data_type *mfd);
+void mdp3_fbmem_clear(void);
+
 
 #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 7edf3d2..f77a2b3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -351,7 +351,11 @@
 		cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0;
 	} else
 		return -EINVAL;
-	rc = mdp3_intf_init(intf, &cfg);
+
+	if (intf->config)
+		rc = intf->config(intf, &cfg);
+	else
+		rc = -EINVAL;
 	return rc;
 }
 
@@ -390,7 +394,10 @@
 					(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
 					MDP3_DMA_OUTPUT_COMP_BITS_8;
 
-	rc = mdp3_dma_init(dma, &sourceConfig, &outputConfig);
+	if (dma->dma_config)
+		rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
+	else
+		rc = -EINVAL;
 	return rc;
 }
 
@@ -413,6 +420,11 @@
 		goto on_error;
 	}
 
+	if (mdp3_session->intf->active) {
+		pr_debug("continuous splash screen, initialized already\n");
+		goto on_error;
+	}
+
 	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
 	if (rc) {
 		pr_err("fail to attach MDP DMA SMMU\n");
@@ -461,6 +473,8 @@
 		goto on_error;
 	}
 
+	mdp3_fbmem_clear();
+
 	if (panel->set_backlight)
 		panel->set_backlight(panel, panel->panel_info.bl_max);
 
@@ -671,6 +685,12 @@
 		return -EPERM;
 	}
 
+	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+		pr_debug("continuous splash screen, IOMMU not attached\n");
+		mdp3_ctrl_off(mfd);
+		mdp3_ctrl_on(mfd);
+	}
+
 	mutex_lock(&mdp3_session->lock);
 
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
@@ -715,6 +735,12 @@
 		return;
 	}
 
+	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+		pr_debug("continuous splash screen, IOMMU not attached\n");
+		mdp3_ctrl_off(mfd);
+		mdp3_ctrl_on(mfd);
+	}
+
 	mutex_lock(&mdp3_session->lock);
 	fbi = mfd->fbi;
 
@@ -1217,12 +1243,23 @@
 		goto init_done;
 	}
 
+	rc = mdp3_dma_init(mdp3_session->dma);
+	if (rc) {
+		pr_err("fail to init dma\n");
+		goto init_done;
+	}
+
 	intf_type = mdp3_ctrl_get_intf_type(mfd);
 	mdp3_session->intf = mdp3_get_display_intf(intf_type);
 	if (!mdp3_session->intf) {
 		rc = -ENODEV;
 		goto init_done;
 	}
+	rc = mdp3_intf_init(mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to init interface\n");
+		goto init_done;
+	}
 
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 2e9c787..88eedb9 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -829,19 +829,14 @@
 	return ret;
 }
 
-int mdp3_dma_init(struct mdp3_dma *dma,
-		struct mdp3_dma_source *source_config,
-		struct mdp3_dma_output_config *output_config)
+int mdp3_dma_init(struct mdp3_dma *dma)
 {
 	int ret = 0;
 
 	pr_debug("mdp3_dma_init\n");
 	switch (dma->dma_sel) {
 	case MDP3_DMA_P:
-		ret = mdp3_dmap_config(dma, source_config, output_config);
-		if (ret < 0)
-			return ret;
-
+		dma->dma_config = mdp3_dmap_config;
 		dma->config_cursor = mdp3_dmap_cursor_config;
 		dma->config_ccs = mdp3_dmap_ccs_config;
 		dma->config_histo = mdp3_dmap_histo_config;
@@ -855,10 +850,7 @@
 		dma->stop = mdp3_dma_stop;
 		break;
 	case MDP3_DMA_S:
-		ret = mdp3_dmas_config(dma, source_config, output_config);
-		if (ret < 0)
-			return ret;
-
+		dma->dma_config = mdp3_dmas_config;
 		dma->config_cursor = NULL;
 		dma->config_ccs = NULL;
 		dma->config_histo = NULL;
@@ -1029,10 +1021,9 @@
 	return 0;
 }
 
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+int mdp3_intf_init(struct mdp3_intf *intf)
 {
-	int ret = 0;
-	switch (cfg->type) {
+	switch (intf->cfg.type) {
 	case MDP3_DMA_OUTPUT_SEL_LCDC:
 		intf->config = lcdc_config;
 		intf->start = lcdc_start;
@@ -1052,16 +1043,5 @@
 	default:
 		return -EINVAL;
 	}
-
-	intf->active = false;
-	if (intf->config)
-		ret = intf->config(intf, cfg);
-
-	if (ret) {
-		pr_err("MDP interface initialization failed\n");
-		return ret;
-	}
-
-	intf->cfg = *cfg;
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index c652818..e4a28dc 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -250,6 +250,10 @@
 	int histo_state;
 	struct mdp3_dma_histogram_data histo_data;
 
+	int (*dma_config)(struct mdp3_dma *dma,
+			struct mdp3_dma_source *source_config,
+			struct mdp3_dma_output_config *output_config);
+
 	int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
 
 	int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -323,11 +327,9 @@
 	int (*stop)(struct mdp3_intf *intf);
 };
 
-int mdp3_dma_init(struct mdp3_dma *dma,
-		struct mdp3_dma_source *source_config,
-		struct mdp3_dma_output_config *output_config);
+int mdp3_dma_init(struct mdp3_dma *dma);
 
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg);
+int mdp3_intf_init(struct mdp3_intf *intf);
 
 void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e682e69..5f5084d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -44,6 +44,14 @@
 
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
 {
+	if (ctrl->shared_pdata.broadcast_enable)
+		if (ctrl->panel_data.panel_info.pdest
+					== DISPLAY_1) {
+			pr_debug("%s: Broadcast mode enabled.\n",
+				 __func__);
+			left_ctrl_pdata = ctrl;
+		}
+
 	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
 		mdss_dsi0_hw.ptr = (void *)(ctrl);
 		ctrl->dsi_hw = &mdss_dsi0_hw;
@@ -861,13 +869,6 @@
 	else
 		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x14000000);
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if (pdata->panel_info.pdest == DISPLAY_1) {
-			pr_debug("%s: Broadcast mode enabled.\n",
-				 __func__);
-			left_ctrl_pdata = ctrl_pdata;
-		}
-
 	data = 0;
 	if (pinfo->te_sel)
 		data |= BIT(31);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ce6b805..ac87cbd 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -111,7 +111,7 @@
 		return ret;
 	}
 
-	if (notify > NOTIFY_UPDATE_STOP)
+	if (notify > NOTIFY_UPDATE_POWER_OFF)
 		return -EINVAL;
 
 	if (notify == NOTIFY_UPDATE_START) {
@@ -119,12 +119,19 @@
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->update.comp, 4 * HZ);
 		to_user = mfd->update.value;
-	} else {
+	} else if (notify == NOTIFY_UPDATE_STOP) {
 		INIT_COMPLETION(mfd->no_update.comp);
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->no_update.comp, 4 * HZ);
 		to_user = mfd->no_update.value;
+	} else {
+		if (mfd->panel_power_on) {
+			INIT_COMPLETION(mfd->power_off_comp);
+			ret = wait_for_completion_interruptible_timeout(
+						&mfd->power_off_comp, 1 * HZ);
+		}
 	}
+
 	if (ret == 0)
 		ret = -ETIMEDOUT;
 	else if (ret > 0)
@@ -649,6 +656,9 @@
 	if (!op_enable)
 		return -EPERM;
 
+	if (mfd->dcm_state == DCM_ENTER)
+		return -EPERM;
+
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
 		if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
@@ -690,6 +700,7 @@
 			else
 				mdss_fb_release_fences(mfd);
 			mfd->op_enable = true;
+			complete(&mfd->power_off_comp);
 		}
 		break;
 	}
@@ -1019,6 +1030,7 @@
 
 	mfd->ref_cnt = 0;
 	mfd->panel_power_on = false;
+	mfd->dcm_state = DCM_UNINIT;
 
 	mdss_fb_parse_dt_split(mfd);
 
@@ -1037,6 +1049,7 @@
 	mfd->no_update.timer.data = (unsigned long)mfd;
 	init_completion(&mfd->update.comp);
 	init_completion(&mfd->no_update.comp);
+	init_completion(&mfd->power_off_comp);
 	init_completion(&mfd->commit_comp);
 	init_completion(&mfd->power_set_comp);
 	INIT_WORK(&mfd->commit_work, mdss_fb_commit_wq_handler);
@@ -1522,6 +1535,58 @@
 	return 0;
 }
 
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
+{
+	int ret = -EINVAL;
+
+	if (req_state == mfd->dcm_state) {
+		pr_warn("Already in correct DCM state");
+		ret = 0;
+	}
+
+	switch (req_state) {
+	case DCM_UNBLANK:
+		if (mfd->dcm_state == DCM_UNINIT &&
+			!mfd->panel_power_on && mfd->mdp.on_fnc) {
+			ret = mfd->mdp.on_fnc(mfd);
+			if (ret == 0) {
+				mfd->panel_power_on = true;
+				mfd->dcm_state = DCM_UNBLANK;
+			}
+		}
+		break;
+	case DCM_ENTER:
+		if (mfd->dcm_state == DCM_UNBLANK) {
+			/* Keep unblank path available for only
+			DCM operation */
+			mfd->panel_power_on = false;
+			mfd->dcm_state = DCM_ENTER;
+			ret = 0;
+		}
+		break;
+	case DCM_EXIT:
+		if (mfd->dcm_state == DCM_ENTER) {
+			/* Release the unblank path for exit */
+			mfd->panel_power_on = true;
+			mfd->dcm_state = DCM_EXIT;
+			ret = 0;
+		}
+		break;
+	case DCM_BLANK:
+		if ((mfd->dcm_state == DCM_EXIT ||
+			mfd->dcm_state == DCM_UNBLANK) &&
+			mfd->panel_power_on && mfd->mdp.off_fnc) {
+			ret = mfd->mdp.off_fnc(mfd);
+			if (ret == 0) {
+				mfd->panel_power_on = false;
+				mfd->dcm_state = DCM_UNINIT;
+			}
+		}
+		break;
+	}
+	return ret;
+}
+
 static int mdss_fb_cursor(struct fb_info *info, void __user *p)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 12f3d68..030fd67 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -124,6 +124,7 @@
 
 	struct disp_info_notify update;
 	struct disp_info_notify no_update;
+	struct completion power_off_comp;
 
 	struct msm_mdp_interface mdp;
 
@@ -145,6 +146,8 @@
 	void *msm_fb_backup;
 	struct completion power_set_comp;
 	u32 is_power_setting;
+
+	u32 dcm_state;
 };
 
 struct msm_fb_backup_type {
@@ -177,4 +180,5 @@
 void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
 void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
 int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c4f274f..4032b91 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1601,6 +1601,13 @@
 	if (ret)
 		return ret;
 
+	/* Supprt only MDP register read/write and
+	exit_dcm in DCM state*/
+	if (mfd->dcm_state == DCM_ENTER &&
+			(mdp_pp.op != mdp_op_calib_buffer &&
+			mdp_pp.op != mdp_op_calib_dcm_state))
+		return -EPERM;
+
 	switch (mdp_pp.op) {
 	case mdp_op_pa_cfg:
 		ret = mdss_mdp_pa_config(mdp5_data->ctl,
@@ -1681,6 +1688,9 @@
 				(struct mdp_calib_config_buffer *)
 				 &mdp_pp.data.calib_buffer, &copyback);
 		break;
+	case mdp_op_calib_dcm_state:
+		ret = mdss_fb_dcm(mfd, mdp_pp.data.calib_dcm.dcm_state);
+		break;
 	default:
 		pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
 								mdp_pp.op);
@@ -1986,7 +1996,8 @@
 
 	if (!mfd->panel_info->cont_splash_enabled) {
 		rc = mdss_mdp_overlay_start(mfd);
-		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
+		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL) &&
+			(mfd->panel_info->type != WRITEBACK_PANEL))
 			rc = mdss_mdp_overlay_kickoff(mfd);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 624046d..3f75053 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -162,6 +162,9 @@
 	int i;
 	int rc = 0, rot_mode = 0;
 	u32 nlines;
+	u16 width;
+
+	width = pipe->src.w >> pipe->horz_deci;
 
 	if (pipe->bwc_mode) {
 		rc = mdss_mdp_get_rau_strides(pipe->src.w, pipe->src.h,
@@ -172,11 +175,11 @@
 			ps.ystride[0], ps.ystride[1]);
 	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
 		ps.num_planes = 2;
-		ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
+		ps.ystride[0] = width;
 		ps.ystride[1] = ps.ystride[0];
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
-			pipe->src.w, pipe->src.h, &ps, 0);
+			width, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 
@@ -184,7 +187,7 @@
 			rot_mode = 1;
 		else if (ps.num_planes == 1)
 			ps.ystride[0] = MAX_BPP *
-				max(pipe->mixer->width, pipe->src.w);
+				max(pipe->mixer->width, width);
 	}
 
 	nlines = pipe->bwc_mode ? 1 : 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 9ae41df..0c74137 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -601,6 +601,12 @@
 	case MDP_ARGB_8888:
 		dst_format = WB_FORMAT_ARGB_8888;
 		break;
+	case MDP_BGRA_8888:
+		dst_format = WB_FORMAT_BGRA_8888;
+		break;
+	case MDP_BGRX_8888:
+		dst_format = WB_FORMAT_BGRX_8888;
+		break;
 	case MDP_Y_CBCR_H2V2_VENUS:
 		dst_format = WB_FORMAT_NV12;
 		break;
@@ -633,6 +639,12 @@
 	case WB_FORMAT_ARGB_8888:
 		ctl->dst_format = MDP_ARGB_8888;
 		break;
+	case WB_FORMAT_BGRA_8888:
+		ctl->dst_format = MDP_BGRA_8888;
+		break;
+	case WB_FORMAT_BGRX_8888:
+		ctl->dst_format = MDP_BGRX_8888;
+		break;
 	case WB_FORMAT_NV12:
 		ctl->dst_format = MDP_Y_CBCR_H2V2_VENUS;
 		break;
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 72961c3..cd141a4 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -96,4 +96,10 @@
 }
 
 #endif	/* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif  /* CONFIG_PANIC_ON_DATA_CORRUPTION */
 #endif	/* _LINUX_BUG_H */
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 73016d6..d121695 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,8 +35,11 @@
  * struct synaptics_rmi4_platform_data - rmi4 platform data
  * @x_flip: x flip flag
  * @y_flip: y flip flag
+ * @i2c_pull_up: pull up i2c bus with regulator
+ * @power_down_enable: enable complete regulator shutdown in suspend
  * @irq_gpio: attention interrupt gpio
  * @irq_flags: flags used by the irq
+ * @reset_flags: flags used by reset line
  * @reset_gpio: reset gpio
  * @panel_x: panel maximum values on the x
  * @panel_y: panel maximum values on the y
@@ -47,6 +50,7 @@
 	bool x_flip;
 	bool y_flip;
 	bool i2c_pull_up;
+	bool power_down_enable;
 	unsigned irq_gpio;
 	u32 irq_flags;
 	u32 reset_flags;
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 72e31b2..94d8245 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -241,6 +241,7 @@
 
 	struct sdhci_next next_data;
 	ktime_t data_start_time;
+	struct mutex ios_mutex;
 
 	unsigned long private[0] ____cacheline_aligned;
 };
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index c3ff9de..2455212 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -87,6 +87,7 @@
 enum {
 	NOTIFY_UPDATE_START,
 	NOTIFY_UPDATE_STOP,
+	NOTIFY_UPDATE_POWER_OFF,
 };
 
 enum {
@@ -612,6 +613,19 @@
 	uint32_t *buffer;
 };
 
+struct mdp_calib_dcm_state {
+	uint32_t ops;
+	uint32_t dcm_state;
+};
+
+enum {
+	DCM_UNINIT,
+	DCM_UNBLANK,
+	DCM_ENTER,
+	DCM_EXIT,
+	DCM_BLANK,
+};
+
 #define MDSS_MAX_BL_BRIGHTNESS 255
 #define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
 
@@ -704,6 +718,7 @@
 	mdp_op_ad_input,
 	mdp_op_calib_mode,
 	mdp_op_calib_buffer,
+	mdp_op_calib_dcm_state,
 	mdp_op_max,
 };
 
@@ -713,6 +728,8 @@
 	WB_FORMAT_RGB_888,
 	WB_FORMAT_xRGB_8888,
 	WB_FORMAT_ARGB_8888,
+	WB_FORMAT_BGRA_8888,
+	WB_FORMAT_BGRX_8888,
 	WB_FORMAT_ARGB_8888_INPUT_ALPHA /* Need to support */
 };
 
@@ -732,6 +749,7 @@
 		struct mdss_calib_cfg mdss_calib_cfg;
 		struct mdss_ad_input ad_input;
 		struct mdp_calib_config_buffer calib_buffer;
+		struct mdp_calib_dcm_state calib_dcm;
 	} data;
 };
 
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index f1a6e9e..90fd57d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,6 +41,7 @@
 #include <linux/debug_locks.h>
 #include <linux/lockdep.h>
 #include <linux/idr.h>
+#include <linux/bug.h>
 
 #include "workqueue_sched.h"
 
@@ -1878,6 +1879,7 @@
 		printk(KERN_ERR "    last function: ");
 		print_symbol("%s\n", (unsigned long)f);
 		debug_show_held_locks(current);
+		BUG_ON(PANIC_CORRUPTION);
 		dump_stack();
 	}
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 097d70f..b9060a1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1290,6 +1290,13 @@
 
 	  If unsure, say N.
 
+config PANIC_ON_DATA_CORRUPTION
+	bool "Cause a Kernel Panic When Data Corruption is detected"
+	help
+	 Select this option to upgrade warnings for potentially
+	 recoverable data corruption scenarios to system-halting panics,
+	 for easier detection and debug.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 982b850..6a039a6 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -10,6 +10,7 @@
 #include <linux/list.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
@@ -30,6 +31,10 @@
 		"list_add corruption. prev->next should be "
 		"next (%p), but was %p. (prev=%p).\n",
 		next, prev->next, prev);
+
+	BUG_ON(((prev->next != next) || (next->prev != prev)) &&
+		PANIC_CORRUPTION);
+
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
@@ -55,8 +60,10 @@
 		"but was %p\n", entry, prev->next) ||
 	    WARN(next->prev != entry,
 		"list_del corruption. next->prev should be %p, "
-		"but was %p\n", entry, next->prev))
+		"but was %p\n", entry, next->prev)) {
+		BUG_ON(PANIC_CORRUPTION);
 		return;
+	}
 
 	__list_del(prev, next);
 }
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index f2aa5de..ac516f4 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -12,6 +12,7 @@
 #include <linux/debug_locks.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/bug.h>
 
 void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
 			  struct lock_class_key *key)
@@ -64,6 +65,7 @@
 		owner ? owner->comm : "<none>",
 		owner ? task_pid_nr(owner) : -1,
 		lock->owner_cpu);
+	BUG_ON(PANIC_CORRUPTION);
 	dump_stack();
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index d02713a..b2dca68 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -627,6 +627,8 @@
 		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
 	else if (val == MSM_FRONTEND_DAI_VOICE2)
 		session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+	else if (val == MSM_FRONTEND_DAI_QCHAT)
+		session_id = voc_get_session_id(QCHAT_SESSION_NAME);
 	else
 		session_id = voc_get_session_id(VOIP_SESSION_NAME);
 
@@ -1914,6 +1916,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1932,6 +1937,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
@@ -1950,6 +1958,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1971,6 +1982,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1992,6 +2006,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -2013,6 +2030,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -2034,6 +2054,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -2055,6 +2078,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -2073,6 +2099,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -2094,6 +2123,9 @@
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -2243,6 +2275,33 @@
 	msm_routing_put_voice_stub_mixer),
 };
 
+static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_QCHAT", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_QCHAT",
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0,
+	msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX_QCHAT", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("MI2S_TX_QCHAT", MSM_BACKEND_DAI_MI2S_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX_QCHAT", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -2831,6 +2890,8 @@
 	/* LSM */
 	SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
 			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
 	/* Backend AIF */
 	/* Stream name equals to backend dai link stream name
 	*/
@@ -3065,6 +3126,9 @@
 	SND_SOC_DAPM_MIXER("PRI_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
 	primary_mi2s_rx_port_mixer_controls,
 	ARRAY_SIZE(primary_mi2s_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
+	SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
+	ARRAY_SIZE(tx_qchat_mixer_controls)),
 	/* Virtual Pins to force backends ON atm */
 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
 	SND_SOC_DAPM_INPUT("BE_IN"),
@@ -3266,6 +3330,7 @@
 	{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 
 	{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3273,6 +3338,7 @@
 	{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
 
 	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3280,6 +3346,7 @@
 	{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
 
 	{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3287,6 +3354,7 @@
 	{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
 
 	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3295,6 +3363,7 @@
 	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SLIM_0_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
 
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3302,6 +3371,7 @@
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
 
 	{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3309,6 +3379,7 @@
 	{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
 
 	{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3317,6 +3388,7 @@
 	{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
 
 	{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3324,6 +3396,7 @@
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SEC_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
 
 	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3331,6 +3404,7 @@
 	{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
 	{"HDMI", NULL, "HDMI_DL_HL"},
 
@@ -3339,6 +3413,7 @@
 	{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 
 	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
@@ -3398,6 +3473,16 @@
 	{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
 	{"LSM_UL_HL", NULL, "LSM1 MUX"},
 
+	{"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
+	{"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
+	{"QCHAT_Tx Mixer", "INTERNAL_BT_SCO_TX_QCHAT", "INT_BT_SCO_TX"},
+	{"QCHAT_Tx Mixer", "AFE_PCM_TX_QCHAT", "PCM_TX"},
+	{"QCHAT_Tx Mixer", "AUX_PCM_TX_QCHAT", "AUX_PCM_TX"},
+	{"QCHAT_Tx Mixer", "SEC_AUX_PCM_TX_QCHAT", "SEC_AUX_PCM_TX"},
+	{"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"},
+	{"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"},
+	{"QCHAT_UL", NULL, "QCHAT_Tx Mixer"},
+
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4ce0db5..10be150 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -81,6 +81,7 @@
 	MSM_FRONTEND_DAI_DTMF_RX,
 	MSM_FRONTEND_DAI_LSM1,
 	MSM_FRONTEND_DAI_VOICE2,
+	MSM_FRONTEND_DAI_QCHAT,
 	MSM_FRONTEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 053375e..7aea1a5 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -51,7 +51,7 @@
 
 	.fifo_size =            0,
 };
-static int is_volte(struct msm_voice *pvolte)
+static bool is_volte(struct msm_voice *pvolte)
 {
 	if (pvolte == &voice_info[VOLTE_SESSION_INDEX])
 		return true;
@@ -59,7 +59,7 @@
 		return false;
 }
 
-static int is_voice2(struct msm_voice *pvoice2)
+static bool is_voice2(struct msm_voice *pvoice2)
 {
 	if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
 		return true;
@@ -67,6 +67,14 @@
 		return false;
 }
 
+static bool is_qchat(struct msm_voice *pqchat)
+{
+	if (pqchat == &voice_info[QCHAT_SESSION_INDEX])
+		return true;
+	else
+		return false;
+}
+
 static uint32_t get_session_id(struct msm_voice *pvoc)
 {
 	uint32_t session_id = 0;
@@ -75,6 +83,8 @@
 		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
 	else if (is_voice2(pvoc))
 		session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+	else if (is_qchat(pvoc))
+		session_id = voc_get_session_id(QCHAT_SESSION_NAME);
 	else
 		session_id = voc_get_session_id(VOICE_SESSION_NAME);
 
@@ -120,6 +130,10 @@
 		voice = &voice_info[VOICE2_SESSION_INDEX];
 		pr_debug("%s: Open Voice2 Substream Id=%s\n",
 			 __func__, substream->pcm->id);
+	} else if (!strncmp("QCHAT", substream->pcm->id, 5)) {
+		voice = &voice_info[QCHAT_SESSION_INDEX];
+		pr_debug("%s: Open QCHAT Substream Id=%s\n",
+			 __func__, substream->pcm->id);
 	} else {
 		voice = &voice_info[VOICE_SESSION_INDEX];
 		pr_debug("%s: Open VOICE Substream Id=%s\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index 5425c46..f199be6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -17,6 +17,7 @@
 	VOICE_SESSION_INDEX,
 	VOLTE_SESSION_INDEX,
 	VOICE2_SESSION_INDEX,
+	QCHAT_SESSION_INDEX,
 	VOICE_SESSION_INDEX_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 147530c..a21bff0 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -208,6 +208,9 @@
 	} else if (session_id ==
 			common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
 		session_name = VOLTE_SESSION_NAME;
+	} else if (session_id ==
+			common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
+		session_name = QCHAT_SESSION_NAME;
 	} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
 		session_name = VOIP_SESSION_NAME;
 	}
@@ -227,6 +230,9 @@
 		else if (!strncmp(name, "VoLTE session", 13))
 			session_id =
 			common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+		else if (!strncmp(name, "QCHAT session", 13))
+			session_id =
+			common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
 		else
 			session_id = common.voice[VOC_PATH_FULL].session_id;
 
@@ -258,6 +264,10 @@
 		v = &common.voice[VOC_PATH_FULL];
 		break;
 
+	case QCHAT_SESSION_VSID:
+		v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
+		break;
+
 	case ALL_SESSION_VSID:
 		break;
 
@@ -294,6 +304,10 @@
 		idx = VOC_PATH_FULL;
 		break;
 
+	case QCHAT_SESSION_VSID:
+		idx = VOC_PATH_QCHAT_PASSIVE;
+		break;
+
 	case ALL_SESSION_VSID:
 		idx = MAX_VOC_SESSIONS - 1;
 		break;
@@ -313,11 +327,6 @@
 				NULL : &common.voice[idx]);
 }
 
-static bool is_voice_session(u32 session_id)
-{
-	return (session_id == common.voice[VOC_PATH_PASSIVE].session_id);
-}
-
 static bool is_voip_session(u32 session_id)
 {
 	return (session_id == common.voice[VOC_PATH_FULL].session_id);
@@ -333,6 +342,11 @@
 	return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
 }
 
+static bool is_qchat_session(u32 session_id)
+{
+	return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
+}
+
 static bool is_voc_state_active(int voc_state)
 {
 	if ((voc_state == VOC_RUN) ||
@@ -369,6 +383,7 @@
 	common.voice[VOC_PATH_VOLTE_PASSIVE].session_id = VOLTE_SESSION_VSID;
 	common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
 	common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
+	common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
 }
 
 static int voice_apr_register(void)
@@ -493,10 +508,8 @@
 		pr_err("%s: apr_mvm is NULL.\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s: VoLTE command to MVM\n", __func__);
-	if (is_volte_session(v->session_id) ||
-		is_voice_session(v->session_id) ||
-		is_voice2_session(v->session_id)) {
+	pr_debug("%s: Send Dual Control command to MVM\n", __func__);
+	if (!is_voip_session(v->session_id)) {
 		mvm_handle = voice_get_mvm_handle(v);
 		mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
 						APR_MSG_TYPE_SEQ_CMD,
@@ -570,9 +583,7 @@
 	/* send cmd to create mvm session and wait for response */
 
 	if (!mvm_handle) {
-		if (is_voice_session(v->session_id) ||
-			is_volte_session(v->session_id) ||
-			is_voice2_session(v->session_id)) {
+		if (!is_voip_session(v->session_id)) {
 			mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
 						APR_MSG_TYPE_SEQ_CMD,
 						APR_HDR_LEN(APR_HDR_SIZE),
@@ -597,6 +608,10 @@
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				VOICE2_SESSION_VSID_STR,
 				sizeof(mvm_session_cmd.mvm_session.name));
+			} else if (is_qchat_session(v->session_id)) {
+				strlcpy(mvm_session_cmd.mvm_session.name,
+				QCHAT_SESSION_VSID_STR,
+				sizeof(mvm_session_cmd.mvm_session.name));
 			} else {
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				"default modem voice",
@@ -659,9 +674,7 @@
 	}
 	/* send cmd to create cvs session */
 	if (!cvs_handle) {
-		if (is_voice_session(v->session_id) ||
-			is_volte_session(v->session_id) ||
-			is_voice2_session(v->session_id)) {
+		if (!is_voip_session(v->session_id)) {
 			pr_debug("%s: creating CVS passive session\n",
 				 __func__);
 
@@ -687,6 +700,10 @@
 				strlcpy(cvs_session_cmd.cvs_session.name,
 				VOICE2_SESSION_VSID_STR,
 				sizeof(cvs_session_cmd.cvs_session.name));
+			} else if (is_qchat_session(v->session_id)) {
+				strlcpy(cvs_session_cmd.cvs_session.name,
+				QCHAT_SESSION_VSID_STR,
+				sizeof(cvs_session_cmd.cvs_session.name));
 			} else {
 			strlcpy(cvs_session_cmd.cvs_session.name,
 				"default modem voice",
@@ -875,7 +892,9 @@
 		}
 	}
 
-	if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+	if (is_voip_session(v->session_id) ||
+	    is_qchat_session(v->session_id) ||
+	    v->voc_state == VOC_ERROR) {
 		/* Destroy CVS. */
 		pr_debug("%s: CVS destroy session\n", __func__);
 
@@ -4536,6 +4555,11 @@
 			v = voice_get_session(session_id);
 			if (v != NULL)
 				v->voc_state = VOC_ERROR;
+
+			session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+			v = voice_get_session(session_id);
+			if (v != NULL)
+				v->voc_state = VOC_ERROR;
 		} else {
 			pr_debug("%s: Reset event received in Voice service\n",
 				__func__);
@@ -4679,6 +4703,11 @@
 			v = voice_get_session(session_id);
 			if (v != NULL)
 				v->voc_state = VOC_ERROR;
+
+			session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+			v = voice_get_session(session_id);
+			if (v != NULL)
+				v->voc_state = VOC_ERROR;
 		} else {
 			pr_debug("%s: Reset event received in Voice service\n",
 				 __func__);
@@ -4951,6 +4980,11 @@
 			v = voice_get_session(session_id);
 			if (v != NULL)
 				v->voc_state = VOC_ERROR;
+
+			session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+			v = voice_get_session(session_id);
+			if (v != NULL)
+				v->voc_state = VOC_ERROR;
 		} else {
 			pr_debug("%s: Reset event received in Voice service\n",
 				 __func__);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index b3a98e2..9e2cfd7 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1309,7 +1309,7 @@
 	void *buf;
 };
 
-#define MAX_VOC_SESSIONS 4
+#define MAX_VOC_SESSIONS 5
 
 struct common_data {
 	/* these default values are for all devices */
@@ -1372,18 +1372,22 @@
 #define VOC_PATH_FULL 1
 #define VOC_PATH_VOLTE_PASSIVE 2
 #define VOC_PATH_VOICE2_PASSIVE 3
+#define VOC_PATH_QCHAT_PASSIVE 4
 
 #define MAX_SESSION_NAME_LEN 32
 #define VOICE_SESSION_NAME  "Voice session"
 #define VOIP_SESSION_NAME   "VoIP session"
 #define VOLTE_SESSION_NAME  "VoLTE session"
 #define VOICE2_SESSION_NAME "Voice2 session"
+#define QCHAT_SESSION_NAME  "QCHAT session"
 
 #define VOICE2_SESSION_VSID_STR "10DC1000"
+#define QCHAT_SESSION_VSID_STR "10803000"
 #define VOICE_SESSION_VSID  0x10C01000
 #define VOICE2_SESSION_VSID 0x10DC1000
 #define VOLTE_SESSION_VSID  0x10C02000
 #define VOIP_SESSION_VSID   0x10004000
+#define QCHAT_SESSION_VSID  0x10803000
 #define ALL_SESSION_VSID    0xFFFFFFFF
 #define VSID_MAX            ALL_SESSION_VSID