Merge "ASoC: msm: Add NULL checks before pointer dereferencing"
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 0519aef..c30515c 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -32,6 +32,7 @@
 			 component
 - coresight-child-ports : list of input port numbers of the children
 - coresight-default-sink : represents the default compile time CoreSight sink
+- coresight-ctis : list of ctis that this component interacts with
 - qcom,pc-save : program counter save implemented
 - qcom,blk-size : block size for tmc-etr to usb transfers
 - qcom,round-robin : indicates if per core etms are allowed round-robin access
@@ -118,3 +119,24 @@
 		qcom,pc-save;
 		qcom,round-robin;
 	};
+
+4. Miscellaneous
+	cti0: cti@fc308000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc308000 0x1000>;
+		reg-names = "cti0-base";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-cti0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti1: cti@fc309000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc309000 0x1000>;
+		reg-names = "cti1-base";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-cti1";
+		coresight-nr-inports = <0>;
+	};
diff --git a/Documentation/devicetree/bindings/platform/msm/ssm.txt b/Documentation/devicetree/bindings/platform/msm/ssm.txt
new file mode 100644
index 0000000..8fb3356
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/ssm.txt
@@ -0,0 +1,30 @@
+* Qualcomm Secure Service Module (SSM)
+
+SSM provides an interface for OEM driver to communicate with Modem and
+trustzone.
+
+This module provides following features:
+ - Keyexchange between Modem and trustzone for encryption/Decryption
+ of mode information
+ - Interface to third party driver to send mode updates to modem
+ - Interface for loading the trustzone application
+
+Required properties:
+- compatible:		Must be "qcom,ssm"
+
+Optional properties:
+- qcom,channel-name:	Name of the SMD channel used for communication
+			between MODEM and SSM driver.
+- qcom,need-keyexhg	This property controls initial key exchange
+			between APPS(application processor) and MODEM.
+			If not mentioned the initial key exchange is
+			not required.
+			If this property is mentioned then it is mandatory
+			for modem to perform initial key exchange with APPS.
+
+Example:
+	qcom,ssm {
+		compatible = "qcom,ssm";
+		qcom,channel-name = "SSM_RTR";
+		qcom,need-keyexhg;
+	}
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index c1d8664..54f603d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -632,7 +632,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <1>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -643,7 +643,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -654,7 +654,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <4>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -665,7 +665,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -676,7 +676,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -687,7 +687,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -698,7 +698,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -709,7 +709,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 
@@ -720,7 +720,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
 		};
@@ -770,7 +770,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 				qcom,btm-channel-number = <0x48>;
 			};
@@ -782,7 +782,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <1>;
-				qcom,hw-settle-time = <0xf>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 				qcom,btm-channel-number = <0x68>;
 			};
@@ -794,7 +794,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 				qcom,btm-channel-number = <0x70>;
 			};
@@ -806,7 +806,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 				qcom,btm-channel-number = <0x78>;
 			};
@@ -818,7 +818,7 @@
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <0>;
+				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 				qcom,btm-channel-number = <0x80>;
 			};
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index d23d324..9387bbd 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -28,6 +28,14 @@
 	qcom,iommu-secure-id = <0xFFFFFFFF>;
 };
 
+&venus_ns {
+	   qcom,iommu-ctx-sids = <0 1 2 3 4 5 7>;
+};
+
+&venus_cp {
+	   qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
+};
+
 &kgsl_iommu {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b5f2dd0..3533d19 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -541,8 +541,8 @@
 		      <0xfc4b8000 0x1000>;
 		reg-names = "tsens_physical", "tsens_eeprom_physical";
 		interrupts = <0 184 0>;
-		qcom,sensors = <7>;
-		qcom,slope = <3200 3200 3200 3200 3200 3200 3200>;
+		qcom,sensors = <6>;
+		qcom,slope = <3200 3200 3200 3200 3200 3200>;
 		qcom,calib-mode = "fuse_map2";
 	};
 
@@ -670,7 +670,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <1>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 
@@ -692,7 +692,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 91de30e..5df8f10 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -23,6 +23,7 @@
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	tpiu: tpiu@fc318000 {
@@ -60,6 +61,7 @@
 		coresight-child-list = <&replicator>;
 		coresight-child-ports = <0>;
 		coresight-default-sink;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	funnel_merg: funnel@fc31b000 {
@@ -217,4 +219,144 @@
 
 		qcom,blk-size = <3>;
 	};
+
+	cti0: cti@fc308000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc308000 0x1000>;
+		reg-names = "cti0-base";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-cti0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti1: cti@fc309000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc309000 0x1000>;
+		reg-names = "cti1-base";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-cti1";
+		coresight-nr-inports = <0>;
+	};
+
+	cti2: cti@fc30a000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30a000 0x1000>;
+		reg-names = "cti2-base";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-cti2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti3: cti@fc30b000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30b000 0x1000>;
+		reg-names = "cti3-base";
+
+		coresight-id = <18>;
+		coresight-name = "coresight-cti3";
+		coresight-nr-inports = <0>;
+	};
+
+	cti4: cti@fc30c000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30c000 0x1000>;
+		reg-names = "cti4-base";
+
+		coresight-id = <19>;
+		coresight-name = "coresight-cti4";
+		coresight-nr-inports = <0>;
+	};
+
+	cti5: cti@fc30d000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30d000 0x1000>;
+		reg-names = "cti5-base";
+
+		coresight-id = <20>;
+		coresight-name = "coresight-cti5";
+		coresight-nr-inports = <0>;
+	};
+
+	cti6: cti@fc30e000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30e000 0x1000>;
+		reg-names = "cti6-base";
+
+		coresight-id = <21>;
+		coresight-name = "coresight-cti6";
+		coresight-nr-inports = <0>;
+	};
+
+	cti7: cti@fc30f000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30f000 0x1000>;
+		reg-names = "cti7-base";
+
+		coresight-id = <22>;
+		coresight-name = "coresight-cti7";
+		coresight-nr-inports = <0>;
+	};
+
+	cti8: cti@fc310000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc310000 0x1000>;
+		reg-names = "cti8-base";
+
+		coresight-id = <23>;
+		coresight-name = "coresight-cti8";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_l2: cti@fc340000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc340000 0x1000>;
+		reg-names = "cti-l2-base";
+
+		coresight-id = <24>;
+		coresight-name = "coresight-cti-l2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu0: cti@fc341000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc341000 0x1000>;
+		reg-names = "cti-cpu0-base";
+
+		coresight-id = <25>;
+		coresight-name = "coresight-cti-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu1: cti@fc342000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc342000 0x1000>;
+		reg-names = "cti-cpu1-base";
+
+		coresight-id = <26>;
+		coresight-name = "coresight-cti-cpu1";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu2: cti@fc343000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc343000 0x1000>;
+		reg-names = "cti-cpu2-base";
+
+		coresight-id = <27>;
+		coresight-name = "coresight-cti-cpu2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu3: cti@fc344000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc344000 0x1000>;
+		reg-names = "cti-cpu3-base";
+
+		coresight-id = <28>;
+		coresight-name = "coresight-cti-cpu3";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974-v1-pm.dtsi
rename to arch/arm/boot/dts/msm8974-pm.dtsi
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index f4f387f..37b2c45 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -18,7 +18,6 @@
 
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v1-iommu.dtsi"
-/include/ "msm8974-v1-pm.dtsi"
 
 / {
 	android_usb@fc42b0c8 {
@@ -46,6 +45,11 @@
 	qcom,i2c-src-freq = <19200000>;
 };
 
+/* CoreSight */
+&tmc_etr {
+	qcom,reset-flush-race;
+};
+
 &msm_vidc {
 	qcom,vidc-cp-map = <0x1000000 0x3f000000>;
 	qcom,vidc-ns-map = <0x40000000 0x40000000>;
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
deleted file mode 100644
index 0ed55ff..0000000
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ /dev/null
@@ -1,426 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/include/ "skeleton.dtsi"
-
-/ {
-	qcom,spm@f9089000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xf9089000 0x1000>;
-		qcom,core-id = <0>;
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
-		qcom,saw2-avs-ctl = <0>;
-		qcom,saw2-avs-hysteresis = <0>;
-		qcom,saw2-avs-limit = <0>;
-		qcom,saw2-avs-dly= <0>;
-		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x1>;
-		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-	};
-
-	qcom,spm@f9099000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xf9099000 0x1000>;
-		qcom,core-id = <1>;
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
-		qcom,saw2-avs-ctl = <0>;
-		qcom,saw2-avs-hysteresis = <0>;
-		qcom,saw2-avs-limit = <0>;
-		qcom,saw2-avs-dly= <0>;
-		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x1>;
-		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-	};
-
-	qcom,spm@f90a9000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xf90a9000 0x1000>;
-		qcom,core-id = <2>;
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
-		qcom,saw2-avs-ctl = <0>;
-		qcom,saw2-avs-hysteresis = <0>;
-		qcom,saw2-avs-limit = <0>;
-		qcom,saw2-avs-dly= <0>;
-		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x1>;
-		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-	};
-
-	qcom,spm@f90b9000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xf90b9000 0x1000>;
-		qcom,core-id = <3>;
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
-		qcom,saw2-avs-ctl = <0>;
-		qcom,saw2-avs-hysteresis = <0>;
-		qcom,saw2-avs-limit = <0>;
-		qcom,saw2-avs-dly= <0>;
-		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x1>;
-		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
-				E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
-	};
-
-	qcom,spm@f9012000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xf9012000 0x1000>;
-		qcom,core-id = <0xffff>; /* L2/APCS SAW */
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x14>;
-		qcom,saw2-avs-ctl = <0>;
-		qcom,saw2-avs-hysteresis = <0>;
-		qcom,saw2-avs-limit = <0>;
-		qcom,saw2-avs-dly= <0>;
-		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x1>;
-		qcom,saw2-pmic-data0 = <0x02030080>;
-		qcom,saw2-pmic-data1 = <0x00030000>;
-		qcom,vctl-timeout-us = <50>;
-		qcom,vctl-port = <0x0>;
-		qcom,phase-port = <0x1>;
-		qcom,pfm-port = <0x2>;
-		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 42 07 78 80 44 22 50
-				3b 60 02 32 50 0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 42 07 01 b0 78
-				80 12 44 50 3b 60 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,resource-type = <0>;
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x02>;
-			qcom,key = <0x6e726f63>;	/* "corn" */
-			qcom,init-value = <5>;		/* Super Turbo */
-		};
-
-		qcom,lpm-resources@1 {
-			reg = <0x1>;
-			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
-			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,resource-type = <0>;
-			qcom,type = <0x306b6c63>;	/* "clk0" */
-			qcom,id = <0x00>;
-			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
-		};
-
-		qcom,lpm-resources@3 {
-			reg = <0x3>;
-			qcom,name = "l2";
-			qcom,resource-type = <1>;
-			qcom,init-value = <2>;		/* Retention */
-		};
-	};
-
-	qcom,lpm-levels {
-		compatible = "qcom,lpm-levels";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <2>;          /* Retention */
-			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.gpios-detectable;
-			qcom,latency-us = <1>;
-			qcom,ss-power = <784>;
-			qcom,energy-overhead = <190000>;
-			qcom,time-overhead = <100>;
-		};
-
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <2>;          /* Retention */
-			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.gpios-detectable;
-			qcom,latency-us = <75>;
-			qcom,ss-power = <735>;
-			qcom,energy-overhead = <77341>;
-			qcom,time-overhead = <105>;
-		};
-
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <2>;          /* Retention */
-			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.gpios-detectable;
-			qcom,latency-us = <95>;
-			qcom,ss-power = <725>;
-			qcom,energy-overhead = <99500>;
-			qcom,time-overhead = <130>;
-		};
-
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* 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.gpios-detectable;
-			qcom,latency-us = <2000>;
-			qcom,ss-power = <138>;
-			qcom,energy-overhead = <1208400>;
-			qcom,time-overhead = <3200>;
-		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
-			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.gpios-detectable;
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <110>;
-			qcom,energy-overhead = <1250300>;
-			qcom,time-overhead = <3500>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* 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= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* GDHS */
-			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@7 {
-			reg = <0x7>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
-			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 {
-		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
-	};
-
-	qcom,mpm@fc4281d0 {
-		compatible = "qcom,mpm-v2";
-		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
-		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
-		reg-names = "vmpm", "ipc";
-		interrupts = <0 171 1>;
-
-		qcom,ipc-bit-offset = <1>;
-
-		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
-			<53 104>, /* mdss_irq */
-			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
-			<0xff 57>,  /* mss_to_apps_irq(0) */
-			<0xff 58>,  /* mss_to_apps_irq(1) */
-			<0xff 59>,  /* mss_to_apps_irq(2) */
-			<0xff 60>,  /* mss_to_apps_irq(3) */
-			<0xff 173>, /* o_wcss_apss_smd_hi */
-			<0xff 174>, /* o_wcss_apss_smd_med */
-			<0xff 175>, /* o_wcss_apss_smd_low */
-			<0xff 176>, /* o_wcss_apss_smsm_irq */
-			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
-			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
-
-			<0xff 188>, /* lpass_irq_out_apcs(0) */
-			<0xff 189>, /* lpass_irq_out_apcs(1) */
-			<0xff 190>, /* lpass_irq_out_apcs(2) */
-			<0xff 191>, /* lpass_irq_out_apcs(3) */
-			<0xff 192>, /* lpass_irq_out_apcs(4) */
-			<0xff 193>, /* lpass_irq_out_apcs(5) */
-			<0xff 194>, /* lpass_irq_out_apcs(6) */
-			<0xff 195>, /* lpass_irq_out_apcs(7) */
-			<0xff 196>, /* lpass_irq_out_apcs(8) */
-			<0xff 197>, /* lpass_irq_out_apcs(9) */
-			<0xff 200>, /* rpm_ipc(4) */
-			<0xff 201>, /* rpm_ipc(5) */
-			<0xff 202>, /* rpm_ipc(6) */
-			<0xff 203>, /* rpm_ipc(7) */
-			<0xff 204>, /* rpm_ipc(24) */
-			<0xff 205>, /* rpm_ipc(25) */
-			<0xff 206>, /* rpm_ipc(26) */
-			<0xff 207>, /* rpm_ipc(27) */
-			<0xff 240>; /* summary_irq_kpss */
-
-		qcom,gpio-parent = <&msmgpio>;
-		qcom,gpio-map = <3  102>,
-			<4  1 >,
-			<5  5 >,
-			<6  9 >,
-			<7  18>,
-			<8  20>,
-			<9  24>,
-			<10  27>,
-			<11  28>,
-			<12  34>,
-			<13  35>,
-			<14  37>,
-			<15  42>,
-			<16  44>,
-			<17  46>,
-			<18  50>,
-			<19  54>,
-			<20  59>,
-			<21  61>,
-			<22  62>,
-			<23  64>,
-			<24  65>,
-			<25  66>,
-			<26  67>,
-			<27  68>,
-			<28  71>,
-			<29  72>,
-			<30  73>,
-			<31  74>,
-			<32  75>,
-			<33  77>,
-			<34  79>,
-			<35  80>,
-			<36  82>,
-			<37  86>,
-			<38  92>,
-			<39  93>,
-			<40  95>;
-	};
-
-	qcom,pm-8x60@fe805664 {
-		compatible = "qcom,pm-8x60";
-		reg = <0xfe805664 0x40>;
-		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
-		qcom,use-sync-timer;
-		qcom,saw-turns-off-pll;
-	};
-
-	qcom,rpm-log@fc19dc00 {
-		compatible = "qcom,rpm-log";
-		reg = <0xfc19dc00 0x4000>;
-		qcom,rpm-addr-phys = <0xfc000000>;
-		qcom,offset-version = <4>;
-		qcom,offset-page-buffer-addr = <36>;
-		qcom,offset-log-len = <40>;
-		qcom,offset-log-len-mask = <44>;
-		qcom,offset-page-indices = <56>;
-	};
-
-	qcom,rpm-stats@0xfc19dbd0{
-		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
-		reg-names = "phys_addr_base";
-		qcom,sleep-stats-version = <2>;
-	};
-};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index a1afda1..f0b7f3f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -18,7 +18,6 @@
 
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v2-iommu.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
 
 / {
 	android_usb@fe8050c8 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b342fd8..68f1082 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msm8974-pm.dtsi"
 /include/ "msm8974-camera.dtsi"
 /include/ "msm8974-coresight.dtsi"
 /include/ "msm-gdsc.dtsi"
@@ -1225,6 +1226,11 @@
 	qcom,bcl {
 		compatible = "qcom,bcl";
 	};
+
+	qcom,ssm {
+		compatible = "qcom,ssm";
+		qcom,channel-name = "SSM_RTR";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 6a52361..0af8fa5 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -23,6 +23,7 @@
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	tpiu: tpiu@fc318000 {
@@ -60,6 +61,7 @@
 		coresight-child-list = <&replicator>;
 		coresight-child-ports = <0>;
 		coresight-default-sink;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	funnel_merg: funnel@fc31b000 {
@@ -141,4 +143,104 @@
 
 		qcom,blk-size = <1>;
 	};
+
+	cti0: cti@fc308000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc308000 0x1000>;
+		reg-names = "cti0-base";
+
+		coresight-id = <10>;
+		coresight-name = "coresight-cti0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti1: cti@fc309000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc309000 0x1000>;
+		reg-names = "cti1-base";
+
+		coresight-id = <11>;
+		coresight-name = "coresight-cti1";
+		coresight-nr-inports = <0>;
+	};
+
+	cti2: cti@fc30a000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30a000 0x1000>;
+		reg-names = "cti2-base";
+
+		coresight-id = <12>;
+		coresight-name = "coresight-cti2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti3: cti@fc30b000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30b000 0x1000>;
+		reg-names = "cti3-base";
+
+		coresight-id = <13>;
+		coresight-name = "coresight-cti3";
+		coresight-nr-inports = <0>;
+	};
+
+	cti4: cti@fc30c000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30c000 0x1000>;
+		reg-names = "cti4-base";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-cti4";
+		coresight-nr-inports = <0>;
+	};
+
+	cti5: cti@fc30d000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30d000 0x1000>;
+		reg-names = "cti5-base";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-cti5";
+		coresight-nr-inports = <0>;
+	};
+
+	cti6: cti@fc30e000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30e000 0x1000>;
+		reg-names = "cti6-base";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-cti6";
+		coresight-nr-inports = <0>;
+	};
+
+	cti7: cti@fc30f000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc30f000 0x1000>;
+		reg-names = "cti7-base";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-cti7";
+		coresight-nr-inports = <0>;
+	};
+
+	cti8: cti@fc310000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc310000 0x1000>;
+		reg-names = "cti8-base";
+
+		coresight-id = <18>;
+		coresight-name = "coresight-cti8";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu: cti@fc333000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc333000 0x1000>;
+		reg-names = "cti-cpu-base";
+
+		coresight-id = <19>;
+		coresight-name = "coresight-cti-cpu";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 9247826..e9ca053 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -735,7 +735,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 
@@ -746,7 +746,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 
@@ -757,7 +757,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 
@@ -768,7 +768,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 
@@ -779,7 +779,7 @@
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
 		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <0>;
+		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
 };
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 896055d..bc0b939 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -77,6 +77,7 @@
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
 CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -180,6 +181,9 @@
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index ecf43bb..9a1f872 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -247,6 +247,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_IPA=y
+CONFIG_ECM_IPA=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=y
 CONFIG_CORESIGHT_TPIU=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e35a806..32e9391 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -411,6 +411,7 @@
 	select CPU_FREQ_GOV_USERSPACE
 	select CPU_FREQ_GOV_ONDEMAND
 	select MSM_PIL
+	select MSM_RUN_QUEUE_STATS
 
 config ARCH_MSM8226
 	bool "MSM8226"
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index beb064b..9ed71da 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2887,6 +2887,7 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
+	&msm8064_cpu_slp_status,
 };
 
 static struct platform_device
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 25ba1aa..fbcc6f1 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,6 +2473,7 @@
 	&msm8930_iommu_domain_device,
 	&msm_tsens_device,
 	&msm8930_cache_dump_device,
+	&msm8930_cpu_slp_status,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 95f618a..819ccc5 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,6 +2955,7 @@
 	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
 	&msm_tsens_device,
+	&msm8960_cpu_slp_status,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index b7693ae..aee0fd1 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5323,6 +5323,20 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.etm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.etm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc340000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc341000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -5338,6 +5352,20 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc340000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc341000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
 
 	CLK_LOOKUP("l2_m_clk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_m_clk",	krait0_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 2bfb323..06a83b6 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2271,6 +2271,16 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -2282,6 +2292,16 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
 
 };
 
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 10ee1e3..b7707d7 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -41,6 +41,7 @@
 #include <mach/msm_rtb.h>
 #include <linux/msm_ion.h>
 #include "clock.h"
+#include "pm.h"
 #include "devices.h"
 #include "footswitch.h"
 #include "msm_watchdog.h"
@@ -141,6 +142,19 @@
 	},
 };
 
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+struct platform_device msm8064_cpu_slp_status = {
+	.name		= "cpu_slp_status",
+	.id		= -1,
+	.dev = {
+		.platform_data = &msm_pm_slp_sts_data,
+	},
+};
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 6fe8ccb..2f8f547 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -53,6 +53,20 @@
 	.retention_calls_tz = true,
 };
 
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+
+struct platform_device msm8930_cpu_slp_status = {
+	.name		= "cpu_slp_status",
+	.id		= -1,
+	.dev = {
+		.platform_data = &msm_pm_slp_sts_data,
+	},
+};
+
 struct platform_device msm8930_pm_8x60 = {
 	.name		= "pm-8x60",
 	.id		= -1,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 6a344be..2bd9dfe 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1703,6 +1703,19 @@
 	.id		= -1,
 };
 
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+struct platform_device msm8960_cpu_slp_status = {
+	.name		= "cpu_slp_status",
+	.id		= -1,
+	.dev = {
+		.platform_data = &msm_pm_slp_sts_data,
+	},
+};
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 53eca3e..327c11d 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -124,6 +124,10 @@
 extern struct platform_device msm_device_hsusb_host2;
 extern struct platform_device msm_device_hsic_host;
 
+extern struct platform_device msm8960_cpu_slp_status;
+extern struct platform_device msm8064_cpu_slp_status;
+extern struct platform_device msm8930_cpu_slp_status;
+
 extern struct platform_device msm_device_otg;
 extern struct platform_device msm_android_usb_device;
 extern struct platform_device msm_android_usb_hsic_device;
diff --git a/arch/arm/mach-msm/include/mach/ecm_ipa.h b/arch/arm/mach-msm/include/mach/ecm_ipa.h
new file mode 100644
index 0000000..008a659
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ecm_ipa.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ECM_IPA_H_
+#define _ECM_IPA_H_
+
+#include <mach/ipa.h>
+
+/*
+ * @priv: private data given upon ipa_connect
+ * @evt: event enum, should be IPA_WRITE_DONE
+ * @data: for tx path the data field is the sent socket buffer.
+ */
+typedef void (*ecm_ipa_callback)(void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data);
+
+
+#ifdef CONFIG_ECM_IPA
+
+int ecm_ipa_init(ecm_ipa_callback * ecm_ipa_rx_dp_notify,
+		ecm_ipa_callback * ecm_ipa_tx_dp_notify,
+		void **priv);
+
+int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+		void *priv);
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+		void *priv);
+
+int ecm_ipa_disconnect(void *priv);
+
+void ecm_ipa_cleanup(void *priv);
+
+#else /* CONFIG_ECM_IPA*/
+
+static inline int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
+		ecm_ipa_callback *ecm_ipa_tx_dp_notify,
+		void **priv)
+{
+	return 0;
+}
+
+static inline int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+		void *priv)
+{
+	return 0;
+}
+
+static inline int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+		void *priv)
+{
+	return 0;
+}
+
+static inline int ecm_ipa_disconnect(void *priv)
+{
+	return 0;
+}
+
+static inline void ecm_ipa_cleanup(void *priv)
+{
+
+}
+#endif /* CONFIG_ECM_IPA*/
+
+#endif /* _ECM_IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 26a055d..564c523 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -354,6 +354,90 @@
 	IPA_BRIDGE_TYPE_MAX
 };
 
+/**
+ * enum ipa_rm_resource_name - IPA RM clients identification names
+ *
+ * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
+ * when adding new entry to this enum.
+ */
+enum ipa_rm_resource_name {
+	IPA_RM_RESOURCE_PROD = 0,
+	IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
+	IPA_RM_RESOURCE_A2_PROD,
+	IPA_RM_RESOURCE_USB_PROD,
+	IPA_RM_RESOURCE_HSIC_PROD,
+	IPA_RM_RESOURCE_STD_ECM_PROD,
+	IPA_RM_RESOURCE_WWAN_0_PROD,
+	IPA_RM_RESOURCE_WWAN_1_PROD,
+	IPA_RM_RESOURCE_WWAN_2_PROD,
+	IPA_RM_RESOURCE_WWAN_3_PROD,
+	IPA_RM_RESOURCE_WWAN_4_PROD,
+	IPA_RM_RESOURCE_WWAN_5_PROD,
+	IPA_RM_RESOURCE_WWAN_6_PROD,
+	IPA_RM_RESOURCE_WWAN_7_PROD,
+	IPA_RM_RESOURCE_WLAN_PROD,
+	IPA_RM_RESOURCE_PROD_MAX,
+
+	IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
+	IPA_RM_RESOURCE_USB_CONS,
+	IPA_RM_RESOURCE_HSIC_CONS,
+	IPA_RM_RESOURCE_MAX
+};
+
+/**
+ * enum ipa_rm_event - IPA RM events
+ *
+ * Indicate the resource state change
+ */
+enum ipa_rm_event {
+	IPA_RM_RESOURCE_GRANTED,
+	IPA_RM_RESOURCE_RELEASED
+};
+
+typedef void (*ipa_rm_notify_cb)(void *user_data,
+		enum ipa_rm_event event,
+		unsigned long data);
+/**
+ * struct ipa_rm_register_params - information needed to
+ *      register IPA RM client with IPA RM
+ *
+ * @user_data: IPA RM client provided information
+ *		to be passed to notify_cb callback below
+ * @notify_cb: callback which is called by resource
+ *		to notify the IPA RM client about its state
+ *		change IPA RM client is expected to perform non
+ *		blocking operations only in notify_cb and
+ *		release notification context as soon as
+ *		possible.
+ */
+struct ipa_rm_register_params {
+	void *user_data;
+	ipa_rm_notify_cb notify_cb;
+};
+
+/**
+ * struct ipa_rm_create_params - information needed to initialize
+ *				the resource
+ * @name: resource name
+ * @reg_params: register parameters, contains are ignored
+ *		for consumer resource NULL should be provided
+ *		for consumer resource
+ * @request_resource: function which should be called to request resource,
+ *			NULL should be provided for producer resource
+ * @release_resource: function which should be called to release resource,
+ *			NULL should be provided for producer resource
+ *
+ * IPA RM client is expected to perform non blocking operations only
+ * in request_resource and release_resource functions and
+ * release notification context as soon as possible.
+ */
+struct ipa_rm_create_params {
+	enum ipa_rm_resource_name name;
+	struct ipa_rm_register_params reg_params;
+	int (*request_resource)(void);
+	int (*release_resource)(void);
+};
+
 #ifdef CONFIG_IPA
 
 /*
@@ -489,6 +573,41 @@
 
 int ipa_teardown_sys_pipe(u32 clnt_hdl);
 
+/*
+ * Resource manager
+ */
+int ipa_rm_create_resource(struct ipa_rm_create_params *create_params);
+
+int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+			enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+			enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_request_resource(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_release_resource(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_notify_completion(enum ipa_rm_event event,
+		enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_init(enum ipa_rm_resource_name resource_name,
+				 unsigned long msecs);
+
+int ipa_rm_inactivity_timer_destroy(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_request_resource(
+				enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_release_resource(
+				enum ipa_rm_resource_name resource_name);
+
 #else /* CONFIG_IPA */
 
 /*
@@ -778,6 +897,84 @@
 	return -EPERM;
 }
 
+/*
+ * Resource manager
+ */
+static inline int ipa_rm_create_resource(
+		struct ipa_rm_create_params *create_params)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_add_dependency(
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_name depends_on_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_delete_dependency(
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_name depends_on_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_request_resource(
+		enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_release_resource(
+		enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_notify_completion(enum ipa_rm_event event,
+		enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_init(
+		enum ipa_rm_resource_name resource_name,
+			unsigned long msecs)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_destroy(
+		enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_request_resource(
+				enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_release_resource(
+				enum ipa_rm_resource_name resource_name)
+{
+	return -EPERM;
+}
+
 #endif /* CONFIG_IPA*/
 
 #endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index ec9fdb0..b675c00 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -113,7 +113,7 @@
  * @ilctxt: Debug Log Context created using ipc_log_context_create()
  * @fmt:    Data specified using format specifiers
  */
-int ipc_log_string(void *ilctxt, const char *fmt, ...);
+int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3);
 
 /*
  * Print a string to decode context.
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 90cb49e..806581d 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/memory.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -507,11 +507,10 @@
  */
 void adjust_meminfo(unsigned long start, unsigned long size)
 {
-	int i, j;
+	int i;
 
-	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
-		struct membank *bank = &meminfo.bank[j];
-		*bank = meminfo.bank[i];
+	for (i = 0; i < meminfo.nr_banks; i++) {
+		struct membank *bank = &meminfo.bank[i];
 
 		if (((start + size) <= (bank->start + bank->size)) &&
 			(start >= bank->start)) {
@@ -519,15 +518,15 @@
 				(meminfo.nr_banks - i) * sizeof(*bank));
 			meminfo.nr_banks++;
 			i++;
-			bank[1].size -= (start + size);
-			bank[1].start = (start + size);
-			bank[1].highmem = 0;
-			j++;
+
 			bank->size = start - bank->start;
+			bank[1].start = (start + size);
+			bank[1].size -= (bank->size + size);
+			bank[1].highmem = 0;
 		}
-		j++;
 	}
 }
+
 unsigned long get_ddr_size(void)
 {
 	unsigned int i;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index affb451..fc9a0fa 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -656,7 +656,8 @@
 void pil_shutdown(struct pil_desc *desc)
 {
 	struct pil_priv *priv = desc->priv;
-	desc->ops->shutdown(desc);
+	if (desc->ops->shutdown)
+		desc->ops->shutdown(desc);
 	if (proxy_timeout_ms == 0 && desc->ops->proxy_unvote)
 		desc->ops->proxy_unvote(desc);
 	else
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1d4ab4..cd6aaf4 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -462,7 +462,7 @@
 
 	if (!drv->is_loadable)
 		return 0;
-	/* MBA doesn't support shutdown */
+	pil_shutdown(&drv->desc);
 	pil_shutdown(&drv->q6->desc);
 	return 0;
 }
@@ -578,7 +578,7 @@
 	if (!drv->is_loadable)
 		return;
 
-	/* MBA doesn't support shutdown */
+	pil_shutdown(&drv->desc);
 	pil_shutdown(&drv->q6->desc);
 }
 
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index af0744c..c77304d 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -65,6 +65,12 @@
 	uint32_t modified_time_us;
 };
 
+struct msm_pm_sleep_status_data {
+	void *base_addr;
+	uint32_t cpu_offset;
+	uint32_t mask;
+};
+
 struct msm_pm_platform_data {
 	u8 idle_supported;   /* Allow device to enter mode during idle */
 	u8 suspend_supported; /* Allow device to enter mode during suspend */
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index 11b1405..ff7ba33 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -327,6 +327,7 @@
 
 	return usc;
 fail:
+	kfree(p_mem_handle);
 	q6usm_us_client_free(usc);
 	return NULL;
 fail_session:
diff --git a/arch/arm/mach-msm/smp2p_debug.c b/arch/arm/mach-msm/smp2p_debug.c
index 1a5c96e..a493cbe 100644
--- a/arch/arm/mach-msm/smp2p_debug.c
+++ b/arch/arm/mach-msm/smp2p_debug.c
@@ -233,7 +233,7 @@
 	if (in_ptr) {
 		in_entries = (struct smp2p_entry_v1 *)((void *)in_ptr +
 				sizeof(struct smp2p_smem));
-		in_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
+		in_valid = SMP2P_GET_ENT_VALID(in_ptr->valid_total_ent);
 	}
 
 	for (entry = 0; out_entries || in_entries; ++entry) {
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 81409b0..5064126 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -61,8 +61,8 @@
  * Users, who want to set the size of global CMA area for their system
  * should use cma= kernel parameter.
  */
-static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M;
-static long size_cmdline = -1;
+static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M;
+static phys_addr_t size_cmdline = -1;
 
 static int __init early_cma(char *p)
 {
@@ -74,7 +74,7 @@
 
 #ifdef CONFIG_CMA_SIZE_PERCENTAGE
 
-static unsigned long __init __maybe_unused cma_early_percent_memory(void)
+static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
 {
 	struct memblock_region *reg;
 	unsigned long total_pages = 0;
@@ -92,7 +92,7 @@
 
 #else
 
-static inline __maybe_unused unsigned long cma_early_percent_memory(void)
+static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
 {
 	return 0;
 }
@@ -110,7 +110,7 @@
  */
 void __init dma_contiguous_reserve(phys_addr_t limit)
 {
-	unsigned long selected_size = 0;
+	phys_addr_t selected_size = 0;
 
 	pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
 
@@ -130,7 +130,7 @@
 
 	if (selected_size) {
 		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
-			 selected_size / SZ_1M);
+			 (unsigned long)selected_size / SZ_1M);
 
 		dma_declare_contiguous(NULL, selected_size, 0, limit);
 	}
@@ -231,11 +231,11 @@
  * called by board specific code when early allocator (memblock or bootmem)
  * is still activate.
  */
-int __init dma_declare_contiguous(struct device *dev, unsigned long size,
+int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
 				  phys_addr_t base, phys_addr_t limit)
 {
 	struct cma_reserved *r = &cma_reserved[cma_reserved_count];
-	unsigned long alignment;
+	phys_addr_t alignment;
 
 	pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
 		 (unsigned long)size, (unsigned long)base,
@@ -251,7 +251,7 @@
 		return -EINVAL;
 
 	/* Sanitise input arguments */
-	alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+	alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
 	base = ALIGN(base, alignment);
 	size = ALIGN(size, alignment);
 	limit &= ~(alignment - 1);
@@ -272,10 +272,6 @@
 		if (!addr) {
 			base = -ENOMEM;
 			goto err;
-		} else if (addr + size > ~(unsigned long)0) {
-			memblock_free(addr, size);
-			base = -EINVAL;
-			goto err;
 		} else {
 			base = addr;
 		}
@@ -289,14 +285,14 @@
 	r->size = size;
 	r->dev = dev;
 	cma_reserved_count++;
-	pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,
+	pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
 		(unsigned long)base);
 
 	/* Architecture specific contiguous memory fixup. */
 	dma_contiguous_early_fixup(base, size);
 	return 0;
 err:
-	pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);
+	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
 	return base;
 }
 
@@ -316,6 +312,7 @@
 {
 	unsigned long mask, pfn, pageno, start = 0;
 	struct cma *cma = dev_get_cma_area(dev);
+	struct page *page = NULL;
 	int ret;
 	int tries = 0;
 
@@ -338,18 +335,17 @@
 	for (;;) {
 		pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
 						    start, count, mask);
-		if (pageno >= cma->count) {
-			ret = -ENOMEM;
-			goto error;
-		}
+		if (pageno >= cma->count)
+			break;
 
 		pfn = cma->base_pfn + pageno;
 		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
 		if (ret == 0) {
 			bitmap_set(cma->bitmap, pageno, count);
+			page = pfn_to_page(pfn);
 			break;
 		} else if (ret != -EBUSY) {
-			goto error;
+			break;
 		}
 		tries++;
 		trace_dma_alloc_contiguous_retry(tries);
@@ -361,12 +357,8 @@
 	}
 
 	mutex_unlock(&cma_mutex);
-
-	pr_debug("%s(): returned %p\n", __func__, pfn_to_page(pfn));
-	return pfn_to_page(pfn);
-error:
-	mutex_unlock(&cma_mutex);
-	return NULL;
+	pr_debug("%s(): returned %p\n", __func__, page);
+	return page;
 }
 
 /**
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index aa55578..616c498 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -45,6 +45,7 @@
 	struct diag_hsic_dev *hsic_struct = container_of(work,
 				struct diag_hsic_dev, diag_read_hsic_work);
 	int index = hsic_struct->id;
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
 	if (!diag_hsic[index].hsic_ch) {
 		pr_err("DIAG in %s: diag_hsic[index].hsic_ch == 0\n", __func__);
@@ -103,7 +104,8 @@
 				diagmem_free(driver, buf_in_hsic,
 						index+POOL_TYPE_HSIC);
 
-				pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
+				if (__ratelimit(&rl))
+					pr_err("diag: Error initiating HSIC read, err: %d\n",
 					err);
 				/*
 				 * An error occurred, discontinue queuing
@@ -132,6 +134,7 @@
 {
 	int err = -2;
 	int index = (int)ctxt;
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
 	if (!diag_hsic[index].hsic_ch) {
 		/*
@@ -164,7 +167,8 @@
 			if (err) {
 				diagmem_free(driver, buf, index +
 							POOL_TYPE_HSIC);
-				pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n",
+				if (__ratelimit(&rl))
+					pr_err("diag: In %s, error calling diag_device_write, err: %d\n",
 					__func__, err);
 			}
 		}
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index c77df95..5e00570 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -24,6 +24,14 @@
 config HAVE_CORESIGHT_SINK
 	bool
 
+config CORESIGHT_CTI
+	bool "CoreSight Cross Trigger Interface driver"
+	help
+	  This driver provides support for Cross Trigger Interface that is
+	  used to input or output i.e. pass cross trigger events from one
+	  hardware component to another. It can also be used to pass
+	  software generated events.
+
 config CORESIGHT_CSR
 	bool "CoreSight Slave Register driver"
 	help
@@ -32,6 +40,7 @@
 
 config CORESIGHT_TMC
 	bool "CoreSight Trace Memory Controller driver"
+	select CORESIGHT_CTI
 	select CORESIGHT_CSR
 	select HAVE_CORESIGHT_SINK
 	help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 8c73794..0595064 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,6 +3,7 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
 obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
 obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
 obj-$(CONFIG_CORESIGHT_TPIU) += coresight-tpiu.o
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
new file mode 100644
index 0000000..e077edf
--- /dev/null
+++ b/drivers/coresight/coresight-cti.c
@@ -0,0 +1,481 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/coresight-cti.h>
+
+#include "coresight-priv.h"
+
+#define cti_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define cti_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define CTI_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	cti_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define CTI_UNLOCK(drvdata)						\
+do {									\
+	cti_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define CTICONTROL		(0x000)
+#define CTIINTACK		(0x010)
+#define CTIAPPSET		(0x014)
+#define CTIAPPCLEAR		(0x018)
+#define CTIAPPPULSE		(0x01C)
+#define CTIINEN(n)		(0x020 + (n * 4))
+#define CTIOUTEN(n)		(0x0A0 + (n * 4))
+#define CTITRIGINSTATUS		(0x130)
+#define CTITRIGOUTSTATUS	(0x134)
+#define CTICHINSTATUS		(0x138)
+#define CTICHOUTSTATUS		(0x13C)
+#define CTIGATE			(0x140)
+#define ASICCTL			(0x144)
+#define ITCHINACK		(0xEDC)
+#define ITTRIGINACK		(0xEE0)
+#define ITCHOUT			(0xEE4)
+#define ITTRIGOUT		(0xEE8)
+#define ITCHOUTACK		(0xEEC)
+#define ITTRIGOUTACK		(0xEF0)
+#define ITCHIN			(0xEF4)
+#define ITTRIGIN		(0xEF8)
+
+#define CTI_MAX_TRIGGERS	(8)
+#define CTI_MAX_CHANNELS	(4)
+
+#define to_cti_drvdata(c) container_of(c, struct cti_drvdata, cti)
+
+struct cti_drvdata {
+	void __iomem			*base;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	struct clk			*clk;
+	struct mutex			mutex;
+	struct coresight_cti		cti;
+	int				refcnt;
+};
+
+static LIST_HEAD(cti_list);
+static DEFINE_MUTEX(cti_lock);
+
+static int cti_verify_bounds(int trig, int ch)
+{
+	if (trig >= CTI_MAX_TRIGGERS)
+		return -EINVAL;
+
+	if (ch >= CTI_MAX_CHANNELS)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int cti_enable(struct cti_drvdata *drvdata)
+{
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	CTI_UNLOCK(drvdata);
+
+	cti_writel(drvdata, 0x1, CTICONTROL);
+
+	CTI_LOCK(drvdata);
+	return 0;
+}
+
+static void __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
+{
+	uint32_t ctien;
+
+	CTI_UNLOCK(drvdata);
+
+	ctien = cti_readl(drvdata, CTIINEN(trig));
+	cti_writel(drvdata, (ctien | 0x1 << ch), CTIINEN(trig));
+
+	CTI_LOCK(drvdata);
+}
+
+int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch)
+{
+	struct cti_drvdata *drvdata;
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(cti))
+		return -EINVAL;
+
+	ret = cti_verify_bounds(trig, ch);
+	if (ret)
+		return ret;
+
+	drvdata = to_cti_drvdata(cti);
+
+	mutex_lock(&drvdata->mutex);
+	if (drvdata->refcnt == 0) {
+		ret = cti_enable(drvdata);
+		if (ret)
+			goto err;
+	}
+	drvdata->refcnt++;
+
+	__cti_map_trigin(drvdata, trig, ch);
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+EXPORT_SYMBOL(coresight_cti_map_trigin);
+
+static void __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
+{
+	uint32_t ctien;
+
+	CTI_UNLOCK(drvdata);
+
+	ctien = cti_readl(drvdata, CTIOUTEN(trig));
+	cti_writel(drvdata, (ctien | 0x1 << ch), CTIOUTEN(trig));
+
+	CTI_LOCK(drvdata);
+}
+
+int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch)
+{
+	struct cti_drvdata *drvdata;
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(cti))
+		return -EINVAL;
+
+	ret = cti_verify_bounds(trig, ch);
+	if (ret)
+		return ret;
+
+	drvdata = to_cti_drvdata(cti);
+
+	mutex_lock(&drvdata->mutex);
+	if (drvdata->refcnt == 0) {
+		ret = cti_enable(drvdata);
+		if (ret)
+			goto err;
+	}
+	drvdata->refcnt++;
+
+	__cti_map_trigout(drvdata, trig, ch);
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+EXPORT_SYMBOL(coresight_cti_map_trigout);
+
+static void cti_disable(struct cti_drvdata *drvdata)
+{
+	CTI_UNLOCK(drvdata);
+
+	cti_writel(drvdata, 0x1, CTICONTROL);
+
+	CTI_LOCK(drvdata);
+}
+
+static void __cti_unmap_trigin(struct cti_drvdata *drvdata, int trig, int ch)
+{
+	uint32_t ctien;
+
+	CTI_UNLOCK(drvdata);
+
+	ctien = cti_readl(drvdata, CTIINEN(trig));
+	cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIINEN(trig));
+
+	CTI_LOCK(drvdata);
+}
+
+void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch)
+{
+	struct cti_drvdata *drvdata;
+
+	if (IS_ERR_OR_NULL(cti))
+		return;
+
+	if (cti_verify_bounds(trig, ch))
+		return;
+
+	drvdata = to_cti_drvdata(cti);
+
+	mutex_lock(&drvdata->mutex);
+	__cti_unmap_trigin(drvdata, trig, ch);
+
+	if (drvdata->refcnt == 1)
+		cti_disable(drvdata);
+	drvdata->refcnt--;
+	mutex_unlock(&drvdata->mutex);
+
+	clk_disable_unprepare(drvdata->clk);
+}
+EXPORT_SYMBOL(coresight_cti_unmap_trigin);
+
+static void __cti_unmap_trigout(struct cti_drvdata *drvdata, int trig, int ch)
+{
+	uint32_t ctien;
+
+	CTI_UNLOCK(drvdata);
+
+	ctien = cti_readl(drvdata, CTIOUTEN(trig));
+	cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIOUTEN(trig));
+
+	CTI_LOCK(drvdata);
+}
+
+void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch)
+{
+	struct cti_drvdata *drvdata;
+
+	if (IS_ERR_OR_NULL(cti))
+		return;
+
+	if (cti_verify_bounds(trig, ch))
+		return;
+
+	drvdata = to_cti_drvdata(cti);
+
+	mutex_lock(&drvdata->mutex);
+	__cti_unmap_trigout(drvdata, trig, ch);
+
+	if (drvdata->refcnt == 1)
+		cti_disable(drvdata);
+	drvdata->refcnt--;
+	mutex_unlock(&drvdata->mutex);
+
+	clk_disable_unprepare(drvdata->clk);
+}
+EXPORT_SYMBOL(coresight_cti_unmap_trigout);
+
+struct coresight_cti *coresight_cti_get(const char *name)
+{
+	struct coresight_cti *cti;
+
+	mutex_lock(&cti_lock);
+	list_for_each_entry(cti, &cti_list, link) {
+		if (!strncmp(cti->name, name, strlen(cti->name) + 1)) {
+			mutex_unlock(&cti_lock);
+			return cti;
+		}
+	}
+	mutex_unlock(&cti_lock);
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(coresight_cti_get);
+
+void coresight_cti_put(struct coresight_cti *cti)
+{
+}
+EXPORT_SYMBOL(coresight_cti_put);
+
+static ssize_t cti_store_map_trigin(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+	int ret;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+
+	ret = coresight_cti_map_trigin(&drvdata->cti, val1, val2);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(map_trigin, S_IWUSR, NULL, cti_store_map_trigin);
+
+static ssize_t cti_store_map_trigout(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+	int ret;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+
+	ret = coresight_cti_map_trigout(&drvdata->cti, val1, val2);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(map_trigout, S_IWUSR, NULL, cti_store_map_trigout);
+
+static ssize_t cti_store_unmap_trigin(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+
+	coresight_cti_unmap_trigin(&drvdata->cti, val1, val2);
+
+	return size;
+}
+static DEVICE_ATTR(unmap_trigin, S_IWUSR, NULL, cti_store_unmap_trigin);
+
+static ssize_t cti_store_unmap_trigout(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+
+	coresight_cti_unmap_trigout(&drvdata->cti, val1, val2);
+
+	return size;
+}
+static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
+
+static struct attribute *cti_attrs[] = {
+	&dev_attr_map_trigin.attr,
+	&dev_attr_map_trigout.attr,
+	&dev_attr_unmap_trigin.attr,
+	&dev_attr_unmap_trigout.attr,
+	NULL,
+};
+
+static struct attribute_group cti_attr_grp = {
+	.attrs = cti_attrs,
+};
+
+static const struct attribute_group *cti_attr_grps[] = {
+	&cti_attr_grp,
+	NULL,
+};
+
+static int __devinit cti_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct cti_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	/* Store the driver data pointer for use in exported functions */
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	mutex_init(&drvdata->mutex);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	mutex_lock(&cti_lock);
+	drvdata->cti.name = ((struct coresight_platform_data *)
+			     (pdev->dev.platform_data))->name;
+	list_add_tail(&drvdata->cti.link, &cti_list);
+	mutex_unlock(&cti_lock);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_NONE;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = cti_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "CTI initialized\n");
+	return 0;
+}
+
+static int __devexit cti_remove(struct platform_device *pdev)
+{
+	struct cti_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id cti_match[] = {
+	{.compatible = "arm,coresight-cti"},
+	{}
+};
+
+static struct platform_driver cti_driver = {
+	.probe          = cti_probe,
+	.remove         = __devexit_p(cti_remove),
+	.driver         = {
+		.name   = "coresight-cti",
+		.owner	= THIS_MODULE,
+		.of_match_table = cti_match,
+	},
+};
+
+static int __init cti_init(void)
+{
+	return platform_driver_register(&cti_driver);
+}
+module_init(cti_init);
+
+static void __exit cti_exit(void)
+{
+	platform_driver_unregister(&cti_driver);
+}
+module_exit(cti_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight CTI driver");
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 10eabca..d9ab7e4 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -29,6 +29,7 @@
 #include <linux/of.h>
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
+#include <linux/coresight-cti.h>
 #include <linux/usb/usb_qdss.h>
 #include <mach/memory.h>
 #include <mach/sps.h>
@@ -136,6 +137,8 @@
 	struct miscdevice	miscdev;
 	struct clk		*clk;
 	spinlock_t		spinlock;
+	struct coresight_cti	*cti_flush;
+	struct coresight_cti	*cti_reset;
 	struct mutex		read_lock;
 	int			read_count;
 	bool			reading;
@@ -372,7 +375,7 @@
 	TMC_UNLOCK(drvdata);
 
 	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
-	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, 0x1133, TMC_FFCR);
 	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
 	__tmc_enable(drvdata);
 
@@ -430,7 +433,10 @@
 		return ret;
 
 	mutex_lock(&drvdata->usb_lock);
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		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_USB) {
 			drvdata->usbch = usb_qdss_open("qdss", drvdata,
 						       usb_notifier);
@@ -440,6 +446,11 @@
 				goto err0;
 			}
 		}
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+			coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
+			coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+		}
 	}
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -632,7 +643,6 @@
 static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
 {
 	unsigned long flags;
-	bool etr_bam_disable = false;
 
 	mutex_lock(&drvdata->usb_lock);
 	spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -645,27 +655,28 @@
 		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
 			__tmc_etr_disable_to_mem(drvdata);
 		else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
-			etr_bam_disable = true;
+			__tmc_etr_disable_to_bam(drvdata);
 	} else {
 		if (mode == TMC_MODE_CIRCULAR_BUFFER)
 			__tmc_etb_disable(drvdata);
 		else
 			__tmc_etf_disable(drvdata);
 	}
-out:
 	drvdata->enable = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	if (etr_bam_disable) {
-		if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-			if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
-				spin_lock_irqsave(&drvdata->spinlock, flags);
-				__tmc_etr_disable_to_bam(drvdata);
-				spin_unlock_irqrestore(&drvdata->spinlock,
-						       flags);
-				tmc_etr_bam_disable(drvdata);
-				usb_qdss_close(drvdata->usbch);
-			}
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		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_USB) {
+			tmc_etr_bam_disable(drvdata);
+			usb_qdss_close(drvdata->usbch);
+		}
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+			coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+			coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
 		}
 	}
 	mutex_unlock(&drvdata->usb_lock);
@@ -673,6 +684,15 @@
 	clk_disable_unprepare(drvdata->clk);
 
 	dev_info(drvdata->dev, "TMC disabled\n");
+	return;
+out:
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	mutex_unlock(&drvdata->usb_lock);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "TMC disabled\n");
 }
 
 static void tmc_disable_sink(struct coresight_device *csdev)
@@ -1091,6 +1111,7 @@
 	static int count;
 	void *baddr;
 	struct msm_client_dump dump;
+	struct coresight_cti_data *ctidata;
 	struct coresight_desc *desc;
 
 	if (pdev->dev.of_node) {
@@ -1209,6 +1230,23 @@
 	}
 	count++;
 
+	if (pdev->dev.of_node) {
+		ctidata = of_get_coresight_cti_data(dev, pdev->dev.of_node);
+		if (IS_ERR(ctidata)) {
+			dev_err(dev, "invalid cti data\n");
+		} else if (ctidata && ctidata->nr_ctis == 2) {
+			drvdata->cti_flush = coresight_cti_get(
+							ctidata->names[0]);
+			if (IS_ERR(drvdata->cti_flush))
+				dev_err(dev, "failed to get flush cti\n");
+
+			drvdata->cti_reset = coresight_cti_get(
+							ctidata->names[1]);
+			if (IS_ERR(drvdata->cti_reset))
+				dev_err(dev, "failed to get reset cti\n");
+		}
+	}
+
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
index a9d0182..1eccd09 100644
--- a/drivers/coresight/of_coresight.c
+++ b/drivers/coresight/of_coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/coresight.h>
+#include <linux/coresight-cti.h>
 
 struct coresight_platform_data *of_get_coresight_platform_data(
 				struct device *dev, struct device_node *node)
@@ -97,3 +98,45 @@
 	return pdata;
 }
 EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
+
+struct coresight_cti_data *of_get_coresight_cti_data(
+				struct device *dev, struct device_node *node)
+{
+	int i, ret;
+	uint32_t ctis_len;
+	struct device_node *child_node;
+	struct coresight_cti_data *ctidata;
+
+	ctidata = devm_kzalloc(dev, sizeof(*ctidata), GFP_KERNEL);
+	if (!ctidata)
+		return ERR_PTR(-ENOMEM);
+
+	if (of_get_property(node, "coresight-ctis", &ctis_len))
+		ctidata->nr_ctis = ctis_len/sizeof(uint32_t);
+	else
+		return ERR_PTR(-EINVAL);
+
+	if (ctidata->nr_ctis) {
+		ctidata->names = devm_kzalloc(dev, ctidata->nr_ctis *
+					      sizeof(*ctidata->names),
+					      GFP_KERNEL);
+		if (!ctidata->names)
+			return ERR_PTR(-ENOMEM);
+
+		for (i = 0; i < ctidata->nr_ctis; i++) {
+			child_node = of_parse_phandle(node, "coresight-ctis",
+						      i);
+			if (!child_node)
+				return ERR_PTR(-EINVAL);
+
+			ret = of_property_read_string(child_node,
+						      "coresight-name",
+						      &ctidata->names[i]);
+			of_node_put(child_node);
+			if (ret)
+				return ERR_PTR(ret);
+		}
+	}
+	return ctidata;
+}
+EXPORT_SYMBOL(of_get_coresight_cti_data);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2f0083a..3e3e3e4 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -103,6 +103,34 @@
 }
 
 /**
+ * cpuidle_enter_state - enter the state and update stats
+ * @dev: cpuidle device for this cpu
+ * @drv: cpuidle driver for this cpu
+ * @next_state: index into drv->states of the state to enter
+ */
+int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
+		int next_state)
+{
+	int entered_state;
+
+	entered_state = cpuidle_enter_ops(dev, drv, next_state);
+
+	if (entered_state >= 0) {
+		/* Update cpuidle counters */
+		/* This can be moved to within driver enter routine
+		 * but that results in multiple copies of same code.
+		 */
+		dev->states_usage[entered_state].time +=
+				(unsigned long long)dev->last_residency;
+		dev->states_usage[entered_state].usage++;
+	} else {
+		dev->last_residency = 0;
+	}
+
+	return entered_state;
+}
+
+/**
  * cpuidle_idle_call - the main idle loop
  *
  * NOTE: no locks or semaphores should be used here
@@ -143,23 +171,11 @@
 	trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
-	entered_state = cpuidle_enter_ops(dev, drv, next_state);
+	entered_state = cpuidle_enter_state(dev, drv, next_state);
 
 	trace_power_end_rcuidle(dev->cpu);
 	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
 
-	if (entered_state >= 0) {
-		/* Update cpuidle counters */
-		/* This can be moved to within driver enter routine
-		 * but that results in multiple copies of same code.
-		 */
-		dev->states_usage[entered_state].time +=
-				(unsigned long long)dev->last_residency;
-		dev->states_usage[entered_state].usage++;
-	} else {
-		dev->last_residency = 0;
-	}
-
 	/* give the governor an opportunity to reflect on the outcome */
 	if (cpuidle_curr_governor->reflect)
 		cpuidle_curr_governor->reflect(dev, entered_state);
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 7db1866..d8a3ccc 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -14,6 +14,8 @@
 extern struct mutex cpuidle_lock;
 extern spinlock_t cpuidle_driver_lock;
 extern int cpuidle_disabled(void);
+extern int cpuidle_enter_state(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int next_state);
 
 /* idle loop */
 extern void cpuidle_install_idle_handler(void);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index bbe97de..a3739a2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2764,6 +2764,11 @@
 };
 
 static struct a3xx_vbif_data a305b_vbif[] = {
+	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x00181818 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x00181818 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000018 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000018 },
+	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303 },
 	{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003 },
 	{0, 0},
 };
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 0c20815..6abfede 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -888,6 +888,17 @@
 	input_sync(input_dev);
 }
 
+static void mxt_release_all(struct mxt_data *data)
+{
+	int id;
+
+	for (id = 0; id < MXT_MAX_FINGER; id++)
+		if (data->finger[id].status)
+			data->finger[id].status = MXT_RELEASE;
+
+	mxt_input_report(data, 0);
+}
+
 static void mxt_input_touchevent(struct mxt_data *data,
 				      struct mxt_message *message, int id)
 {
@@ -899,6 +910,10 @@
 	int area;
 	int pressure;
 
+	if (status & MXT_SUPPRESS) {
+		mxt_release_all(data);
+		return;
+	}
 	/* Check the touch is present on the screen */
 	if (!(status & MXT_DETECT)) {
 		if (status & MXT_RELEASE) {
@@ -973,18 +988,7 @@
 	data->keyarray_old = data->keyarray_new;
 }
 
-static void mxt_release_all(struct mxt_data *data)
-{
-	int id;
-
-	for (id = 0; id < MXT_MAX_FINGER; id++)
-		if (data->finger[id].status)
-			data->finger[id].status = MXT_RELEASE;
-
-	mxt_input_report(data, 0);
-}
-
-static void mxt_handle_touch_supression(struct mxt_data *data, u8 status)
+static void mxt_handle_touch_suppression(struct mxt_data *data, u8 status)
 {
 	dev_dbg(&data->client->dev, "touch suppression\n");
 	/* release all touches */
@@ -1039,7 +1043,7 @@
 
 		id = reportid - data->t9_min_reportid;
 
-		 /* check whether report id is part of T9,T15 or T42*/
+		 /* check whether report id is part of T9, T15 or T42 */
 		if (reportid >= data->t9_min_reportid &&
 					reportid <= data->t9_max_reportid)
 			mxt_input_touchevent(data, &message, id);
@@ -1047,8 +1051,9 @@
 					reportid <= data->t15_max_reportid)
 			mxt_handle_key_array(data, &message);
 		else if (reportid >= data->t42_min_reportid &&
-					reportid <= data->t42_max_reportid)
-			mxt_handle_touch_supression(data, message.message[0]);
+				reportid <= data->t42_max_reportid)
+			mxt_handle_touch_suppression(data,
+					message.message[0]);
 		else
 			mxt_dump_message(dev, &message);
 	} while (reportid != 0xff);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index fa0bf18..f08644f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -369,15 +369,10 @@
 	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
 }
 
-void msm_isp_calculate_framedrop(
-	struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+uint32_t msm_isp_get_framedrop_period(
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern)
 {
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-		(stream_cfg_cmd->axi_stream_handle & 0xFF)];
-	uint32_t framedrop_period = 1;
-	switch (stream_cfg_cmd->frame_skip_pattern) {
+	switch (frame_skip_pattern) {
 	case NO_SKIP:
 	case EVERY_2FRAME:
 	case EVERY_3FRAME:
@@ -386,18 +381,28 @@
 	case EVERY_6FRAME:
 	case EVERY_7FRAME:
 	case EVERY_8FRAME:
-		framedrop_period = stream_cfg_cmd->frame_skip_pattern + 1;
-		break;
+		return frame_skip_pattern + 1;
 	case EVERY_16FRAME:
-		framedrop_period = 16;
+		return 16;
 		break;
 	case EVERY_32FRAME:
-		framedrop_period = 32;
+		return 32;
 		break;
 	default:
-		framedrop_period = 1;
-		break;
+		return 1;
 	}
+	return 1;
+}
+
+void msm_isp_calculate_framedrop(
+	struct msm_vfe_axi_shared_data *axi_data,
+	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+{
+	struct msm_vfe_axi_stream *stream_info =
+		&axi_data->stream_info[
+		(stream_cfg_cmd->axi_stream_handle & 0xFF)];
+	uint32_t framedrop_period = msm_isp_get_framedrop_period(
+	   stream_cfg_cmd->frame_skip_pattern);
 
 	stream_info->framedrop_pattern = 0x1;
 	stream_info->framedrop_period = framedrop_period - 1;
@@ -911,8 +916,16 @@
 				stream_info->bufq_handle,
 				MSM_ISP_BUFFER_FLUSH_DIVERTED);
 		break;
-	case UPDATE_STREAM_FRAMEDROP_PATTERN:
+	case UPDATE_STREAM_FRAMEDROP_PATTERN: {
+		uint32_t framedrop_period =
+			msm_isp_get_framedrop_period(update_cmd->skip_pattern);
+		stream_info->runtime_init_frame_drop = 0;
+		stream_info->framedrop_pattern = 0x1;
+		stream_info->framedrop_period = framedrop_period - 1;
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			cfg_framedrop(vfe_dev, stream_info);
 		break;
+	}
 	default:
 		pr_err("%s: Invalid update type\n", __func__);
 		return -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 7d0f9cb..691edc3 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -94,6 +94,13 @@
 	if (data > 0x1) {
 		unsigned long jiffes = msecs_to_jiffies(500);
 		long lrc = 0;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+		ispif->wait_timeout = 0;
+		init_completion(&ispif->reset_complete);
+		spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
+
 		if (params->vfe_intf == VFE0)
 			msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
 		else
@@ -104,6 +111,11 @@
 		if (lrc < 0 || !lrc) {
 			pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
 			rc = -EIO;
+
+			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+			ispif->wait_timeout = 1;
+			spin_unlock_irqrestore(
+				&ispif->auto_complete_lock, flags);
 		}
 	}
 	return rc;
@@ -114,6 +126,12 @@
 	int rc = 0;
 	long lrc = 0;
 	unsigned long jiffes = msecs_to_jiffies(500);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+	ispif->wait_timeout = 0;
+	init_completion(&ispif->reset_complete);
+	spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
 
 	BUG_ON(!ispif);
 
@@ -125,14 +143,17 @@
 		msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
 			ISPIF_RST_CMD_1_ADDR);
 
-	CDBG("%s: Sending reset\n", __func__);
 	lrc = wait_for_completion_interruptible_timeout(
 		&ispif->reset_complete, jiffes);
+
 	if (lrc < 0 || !lrc) {
 		pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
 		rc = -EIO;
+
+		spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+		ispif->wait_timeout = 1;
+		spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
 	}
-	CDBG("%s: reset returned\n", __func__);
 
 	return rc;
 }
@@ -571,8 +592,14 @@
 		ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
 
 	if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
-		if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ)
-			complete(&ispif->reset_complete);
+		if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
+			unsigned long flags;
+			spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+			if (ispif->wait_timeout == 0)
+				complete(&ispif->reset_complete);
+			spin_unlock_irqrestore(
+				&ispif->auto_complete_lock, flags);
+		}
 
 		if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
 			pr_err("%s: VFE0 pix0 overflow.\n", __func__);
@@ -709,8 +736,6 @@
 		goto error_irq;
 	}
 
-	init_completion(&ispif->reset_complete);
-
 	rc = msm_ispif_reset(ispif);
 	if (rc == 0) {
 		ispif->ispif_state = ISPIF_POWER_UP;
@@ -830,13 +855,8 @@
 	struct ispif_device *ispif = v4l2_get_subdevdata(sd);
 
 	mutex_lock(&ispif->mutex);
-	if (ispif->open_cnt > 0) {
-		CDBG("%s: dev already open\n", __func__);
-		goto end;
-	}
 	/* mem remap is done in init when the clock is on */
 	ispif->open_cnt++;
-end:
 	mutex_unlock(&ispif->mutex);
 	return 0;
 }
@@ -940,7 +960,8 @@
 	ispif->pdev = pdev;
 	ispif->ispif_state = ISPIF_POWER_DOWN;
 	ispif->open_cnt = 0;
-
+	spin_lock_init(&ispif->auto_complete_lock);
+	ispif->wait_timeout = 0;
 	return 0;
 
 error:
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index c4418c1..f8c3cce 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -48,6 +48,8 @@
 	struct mutex mutex;
 	uint8_t start_ack_pending;
 	struct completion reset_complete;
+	spinlock_t auto_complete_lock;
+	uint8_t wait_timeout;
 	uint32_t csid_version;
 	int enb_dump_reg;
 	uint32_t open_cnt;
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 9af6674..77dc6f5 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,9 @@
 	}
 	new_entry->session_id = buf_info->session_id;
 	new_entry->stream_id = buf_info->stream_id;
+	mutex_lock(&buf_mngr_dev->buf_q_lock);
 	list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead);
+	mutex_unlock(&buf_mngr_dev->buf_q_lock);
 	buf_info->index = new_entry->vb2_buf->v4l2_buf.index;
 	return 0;
 }
@@ -55,7 +57,9 @@
 					(bufs->vb2_buf,
 						buf_info->session_id,
 						buf_info->stream_id);
+			mutex_lock(&buf_mngr_dev->buf_q_lock);
 			list_del_init(&bufs->entry);
+			mutex_unlock(&buf_mngr_dev->buf_q_lock);
 			kfree(bufs);
 			break;
 		}
@@ -76,7 +80,9 @@
 			(bufs->vb2_buf->v4l2_buf.index == buf_info->index)) {
 			ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf,
 				buf_info->session_id, buf_info->stream_id);
+			mutex_lock(&buf_mngr_dev->buf_q_lock);
 			list_del_init(&bufs->entry);
+			mutex_unlock(&buf_mngr_dev->buf_q_lock);
 			kfree(bufs);
 			break;
 		}
@@ -156,12 +162,14 @@
 		&msm_buf_mngr_dev->vb2_ops);
 
 	INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
+	mutex_init(&msm_buf_mngr_dev->buf_q_lock);
 end:
 	return rc;
 }
 
 static void __exit msm_buf_mngr_exit(void)
 {
+	mutex_destroy(&msm_buf_mngr_dev->buf_q_lock);
 	kfree(msm_buf_mngr_dev);
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index 7e588cc..a2b3a7e 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -33,6 +33,7 @@
 
 struct msm_buf_mngr_device {
 	struct list_head buf_qhead;
+	struct mutex buf_q_lock;
 	struct msm_sd_subdev subdev;
 	struct msm_sd_req_vb2_q vb2_ops;
 };
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 63ec1cf..9d89a7e 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -18,7 +18,7 @@
 #include "mpq_dmx_plugin_common.h"
 #include "mpq_sdmx.h"
 
-#define SDMX_MAJOR_VERSION_MATCH	(2)
+#define SDMX_MAJOR_VERSION_MATCH	(3)
 
 #define TS_PACKET_HEADER_LENGTH (4)
 
@@ -847,7 +847,7 @@
 	mpq_dmx_info.devices = NULL;
 	mpq_dmx_info.ion_client = NULL;
 
-	mpq_sdmx_check_app_loaded();
+	mpq_dmx_info.secure_demux_app_loaded = 0;
 
 	/*
 	 * TODO: the following should be set based on the decoder:
@@ -4610,6 +4610,16 @@
 
 int mpq_sdmx_is_loaded(void)
 {
-	return mpq_bypass_sdmx ? 0 : mpq_dmx_info.secure_demux_app_loaded;
+	static int sdmx_load_checked;
+
+	if (mpq_bypass_sdmx)
+		return 0;
+
+	if (!sdmx_load_checked) {
+		mpq_sdmx_check_app_loaded();
+		sdmx_load_checked = 1;
+	}
+
+	return mpq_dmx_info.secure_demux_app_loaded;
 }
 EXPORT_SYMBOL(mpq_sdmx_is_loaded);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 0bd04e8..d292992 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -43,6 +43,7 @@
 
 /* Filter-level status indicators */
 #define SDMX_FILTER_STATUS_EOS                    BIT(0)
+#define SDMX_FILTER_STATUS_WR_PTR_CHANGED         BIT(1)
 
 /* Filter-level flags */
 #define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC	BIT(0)
@@ -91,10 +92,9 @@
 	SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11,
 	SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12,
 	SDMX_STATUS_INVALID_FILTER_CFG = -13,
-	SDMX_STATUS_ILLEGAL_WR_PTR_CHANGE = -14,
-	SDMX_STATUS_STALLED_IN_PULL_MODE = -15,
-	SDMX_STATUS_SECURITY_FAULT = -16,
-	SDMX_STATUS_NS_BUFFER_ERROR = -17,
+	SDMX_STATUS_STALLED_IN_PULL_MODE = -14,
+	SDMX_STATUS_SECURITY_FAULT = -15,
+	SDMX_STATUS_NS_BUFFER_ERROR = -16,
 };
 
 enum sdmx_filter {
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 6402437..cee48c7 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -544,7 +544,19 @@
 		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
 		),
 		.cluster = 0,
-	}
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+		.name = "Secure mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = 0,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1434,6 +1446,10 @@
 		}
 		pdata = &enable;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		inst->mode = VIDC_SECURE;
+		dprintk(VIDC_INFO, "Setting secure mode to :%d\n", inst->mode);
+		break;
 	default:
 		rc = -ENOTSUPP;
 		break;
diff --git a/drivers/media/platform/msm/wfd/enc-subdev.h b/drivers/media/platform/msm/wfd/enc-subdev.h
index 93c0079..8bfb884 100644
--- a/drivers/media/platform/msm/wfd/enc-subdev.h
+++ b/drivers/media/platform/msm/wfd/enc-subdev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -76,6 +76,8 @@
 			(a->offset == b->offset);
 	else if (a->kvaddr || b->kvaddr)
 		return a->kvaddr == b->kvaddr;
+	else if (a->paddr || b->paddr)
+		return a->paddr == b->paddr;
 	else
 		return false;
 }
@@ -107,6 +109,7 @@
 #define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
 #define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
 #define SET_FRAMERATE_MODE _IO('V', 27)
+#define ENC_SECURE _IO('V', 28)
 
 extern int venc_init(struct v4l2_subdev *sd, u32 val);
 extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 00d0d07..d37576d 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -252,12 +252,23 @@
 	return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
 }
 
+static long get_iommu_domain(struct venc_inst *inst)
+{
+	struct msm_vidc_iommu_info maps[MAX_MAP];
+	int rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
+	if (rc) {
+		WFD_MSG_ERR("Failed to retreive domain mappings\n");
+		return rc;
+	}
+
+	return maps[inst->secure ? CP_MAP : NS_MAP].domain;
+}
+
 static long venc_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct venc_inst *inst = NULL;
 	struct venc_msg_ops *vmops = arg;
 	struct v4l2_event_subscription event = {0};
-	struct msm_vidc_iommu_info maps[MAX_MAP];
 	int rc = 0;
 
 	if (!vmops) {
@@ -305,15 +316,12 @@
 		goto vidc_subscribe_fail;
 	}
 
-	rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
-	if (rc) {
-		WFD_MSG_ERR("Failed to retreive domain mappings\n");
-		rc = -ENODATA;
+	inst->domain = get_iommu_domain(inst);
+	if (inst->domain < 0) {
+		WFD_MSG_ERR("Failed to get domain\n");
 		goto vidc_subscribe_fail;
 	}
 
-	inst->domain = maps[inst->secure ? CP_MAP : NS_MAP].domain;
-
 	inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
 					"venc_vidc_callback_thread");
 	if (IS_ERR(inst->callback_thread)) {
@@ -477,7 +485,8 @@
 	}
 
 	bufreq->count = v4l2_bufreq.count;
-	bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+	bufreq->size = ALIGN(v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage,
+			inst->secure ? SZ_1M : SZ_4K);
 
 	inst->free_input_indices.size_bits = bufreq->count;
 	inst->free_input_indices.size = roundup(bufreq->count,
@@ -632,12 +641,19 @@
 		struct mem_region *mregion)
 {
 	int rc = 0;
-	unsigned long flags = 0, size = 0;
+	unsigned long flags = 0, size = 0, align_req = 0;
 	if (!mregion) {
 		rc = -EINVAL;
 		goto venc_map_fail;
 	}
 
+	align_req = inst->secure ? SZ_1M : SZ_4K;
+	if (mregion->size % align_req != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %ld\n", align_req);
+		rc = -EINVAL;
+		goto venc_map_fail;
+	}
+
 	mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
 	if (IS_ERR_OR_NULL(mregion->ion_handle)) {
 		rc = PTR_ERR(mregion->ion_handle);
@@ -653,20 +669,31 @@
 		goto venc_map_fail;
 	}
 
-	mregion->kvaddr = ion_map_kernel(venc_ion_client,
+	if (!inst->secure) {
+		mregion->kvaddr = ion_map_kernel(venc_ion_client,
 				mregion->ion_handle);
-
-	if (IS_ERR_OR_NULL(mregion->kvaddr)) {
-		WFD_MSG_ERR("Failed to map buffer into kernel\n");
-		rc = PTR_ERR(mregion->kvaddr);
+		if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+			WFD_MSG_ERR("Failed to map buffer into kernel\n");
+			rc = PTR_ERR(mregion->kvaddr);
+			mregion->kvaddr = NULL;
+			goto venc_map_fail;
+		}
+	} else {
 		mregion->kvaddr = NULL;
-		goto venc_map_fail;
+	}
+
+	if (inst->secure) {
+		rc = msm_ion_secure_buffer(venc_ion_client,
+			mregion->ion_handle, VIDEO_BITSTREAM, 0);
+		if (rc) {
+			WFD_MSG_ERR("Failed to secure output buffer\n");
+			goto venc_map_iommu_map_fail;
+		}
 	}
 
 	rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
-			inst->domain, 0, SZ_4K, 0,
+			inst->domain, 0, align_req, 0,
 			(unsigned long *)&mregion->paddr, &size, flags, 0);
-
 	if (rc) {
 		WFD_MSG_ERR("Failed to map into iommu\n");
 		goto venc_map_iommu_map_fail;
@@ -679,8 +706,12 @@
 venc_map_iommu_size_fail:
 	ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
 			inst->domain, 0);
+
+	if (inst->secure)
+		msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
 venc_map_iommu_map_fail:
-	ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+	if (!inst->secure)
+		ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
 venc_map_fail:
 	return rc;
 }
@@ -702,6 +733,8 @@
 		mregion->kvaddr = NULL;
 	}
 
+	if (inst->secure)
+		msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
 
 	return 0;
 }
@@ -787,7 +820,7 @@
 {
 	struct venc_inst *inst = NULL;
 	struct v4l2_format *fmt = arg, temp;
-	int rc = 0;
+	int rc = 0, align_req = 0;
 
 	if (!sd) {
 		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -823,7 +856,10 @@
 		rc = -EINVAL;
 		goto venc_set_format_fail;
 	}
-	fmt->fmt.pix.sizeimage = temp.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	align_req = inst->secure ? SZ_1M : SZ_4K;
+	fmt->fmt.pix.sizeimage = ALIGN(temp.fmt.pix_mp.plane_fmt[0].sizeimage,
+					align_req);
 	inst->num_output_planes = temp.fmt.pix_mp.num_planes;
 
 	temp.type = BUF_TYPE_INPUT;
@@ -995,7 +1031,6 @@
 		WFD_MSG_ERR("Trying to free a buffer of unknown type\n");
 		return -EINVAL;
 	}
-
 	mregion = get_registered_mregion(buf_list, to_free);
 
 	if (!mregion) {
@@ -1115,7 +1150,7 @@
 {
 	struct mem_region_map *mmap = arg;
 	struct mem_region *mregion = NULL;
-	unsigned long rc = 0, size = 0;
+	unsigned long rc = 0, size = 0, align_req = 0;
 	void *paddr = NULL;
 	struct venc_inst *inst = NULL;
 
@@ -1129,24 +1164,47 @@
 
 	inst = (struct venc_inst *)sd->dev_priv;
 	mregion = mmap->mregion;
-	if (mregion->size % SZ_4K != 0) {
-		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
-		return -EINVAL;
+
+	align_req = inst->secure ? SZ_1M : SZ_4K;
+	if (mregion->size % align_req != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %ld\n", align_req);
+		rc = -EINVAL;
+		goto venc_map_bad_align;
+	}
+
+	if (inst->secure) {
+		rc = msm_ion_secure_buffer(mmap->ion_client,
+			mregion->ion_handle, VIDEO_PIXEL, 0);
+		if (rc) {
+			WFD_MSG_ERR("Failed to secure input buffer\n");
+			goto venc_map_bad_align;
+		}
 	}
 
 	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
-			inst->domain, 0, SZ_4K, 0, (unsigned long *)&paddr,
+			inst->domain, 0, align_req, 0, (unsigned long *)&paddr,
 			&size, 0, 0);
 
 	if (rc) {
-		WFD_MSG_ERR("Failed to get physical addr\n");
+		WFD_MSG_ERR("Failed to get physical addr %ld\n", rc);
 		paddr = NULL;
+		goto venc_map_bad_align;
 	} else if (size < mregion->size) {
 		WFD_MSG_ERR("Failed to map enough memory\n");
 		rc = -ENOMEM;
+		goto venc_map_iommu_size_fail;
 	}
 
 	mregion->paddr = paddr;
+	return 0;
+
+venc_map_iommu_size_fail:
+	ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+			inst->domain, 0);
+
+	if (inst->secure)
+		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+venc_map_bad_align:
 	return rc;
 }
 
@@ -1167,8 +1225,13 @@
 	inst = (struct venc_inst *)sd->dev_priv;
 	mregion = mmap->mregion;
 
-	ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+	if (mregion->paddr)
+		ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
 			inst->domain, 0);
+
+	if (inst->secure)
+		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+
 	return 0;
 }
 
@@ -1181,6 +1244,55 @@
 	return 0;
 }
 
+static long secure_toggle(struct venc_inst *inst, bool secure)
+{
+	if (inst->secure == secure)
+		return 0;
+
+	if (!list_empty(&inst->registered_input_bufs.list) ||
+		!list_empty(&inst->registered_output_bufs.list)) {
+		WFD_MSG_ERR(
+			"Attempt to (un)secure encoder not allowed after registering buffers"
+			);
+		return -EEXIST;
+	}
+
+	inst->secure = secure;
+	inst->domain = get_iommu_domain(inst);
+	return 0;
+}
+
+static long venc_secure(struct v4l2_subdev *sd)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_control ctrl;
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = sd->dev_priv;
+	rc = secure_toggle(inst, true);
+	if (rc) {
+		WFD_MSG_ERR("Failed to toggle into secure mode\n");
+		goto secure_fail;
+	}
+
+	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE;
+	rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+	if (rc) {
+		WFD_MSG_ERR("Failed to move vidc into secure mode\n");
+		goto secure_fail;
+	}
+
+	return 0;
+secure_fail:
+	secure_toggle(sd->dev_priv, false);
+	return rc;
+}
+
 long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	long rc = 0;
@@ -1253,6 +1365,9 @@
 	case SET_FRAMERATE_MODE:
 		rc = venc_set_framerate_mode(sd, arg);
 		break;
+	case ENC_SECURE:
+		rc = venc_secure(sd);
+		break;
 	default:
 		WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
 		rc = -ENOTSUPP;
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 218bbe5..be705df 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -47,6 +47,10 @@
 		WFD_MSG_ERR("Invalid arguments\n");
 		rc = -EINVAL;
 		goto mdp_open_fail;
+	} else if (mops->secure) {
+		/* Deprecated API; use MDP_SECURE ioctl */
+		WFD_MSG_ERR("Deprecated API for securing subdevice\n");
+		return -ENOTSUPP;
 	}
 
 	fbi = msm_fb_get_writeback_fb();
@@ -120,6 +124,8 @@
 	struct fb_info *fbi = NULL;
 	if (inst) {
 		fbi = (struct fb_info *)inst->mdp;
+		if (inst->secure)
+			msm_fb_writeback_set_secure(inst->mdp, false);
 		msm_fb_writeback_terminate(fbi);
 		kfree(inst);
 		/* Unregister wfd node from switch driver */
@@ -193,7 +199,7 @@
 
 int mdp_mmap(struct v4l2_subdev *sd, void *arg)
 {
-	int rc = 0;
+	int rc = 0, align = 0;
 	struct mem_region_map *mmap = arg;
 	struct mem_region *mregion;
 	bool domain = -1;
@@ -206,17 +212,39 @@
 
 	inst = mmap->cookie;
 	mregion = mmap->mregion;
-	if (mregion->size % SZ_4K != 0) {
-		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+	align = inst->secure ? SZ_1M : SZ_4K;
+	if (mregion->size % align != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %d\n", align);
 		return -EINVAL;
 	}
 
-	domain = msm_fb_get_iommu_domain(inst->mdp, MDP_IOMMU_DOMAIN_NS);
+	if (inst->secure) {
+		rc = msm_ion_secure_buffer(mmap->ion_client,
+			mregion->ion_handle, VIDEO_PIXEL, 0);
+		if (rc) {
+			WFD_MSG_ERR("Failed to secure input buffer\n");
+			goto secure_fail;
+		}
+	}
+
+	domain = msm_fb_get_iommu_domain(inst->mdp,
+			inst->secure ? MDP_IOMMU_DOMAIN_CP :
+					MDP_IOMMU_DOMAIN_NS);
+
 	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
-			domain, 0, SZ_4K, 0,
+			domain, 0, align, 0,
 			(unsigned long *)&mregion->paddr,
 			(unsigned long *)&mregion->size,
 			0, 0);
+	if (rc) {
+		WFD_MSG_ERR("Failed to map into %ssecure domain: %d\n",
+				!inst->secure ? "non" : "", rc);
+		goto iommu_fail;
+	}
+iommu_fail:
+	if (inst->secure)
+		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+secure_fail:
 	return rc;
 }
 
@@ -235,13 +263,37 @@
 	inst = mmap->cookie;
 	mregion = mmap->mregion;
 
-	domain = msm_fb_get_iommu_domain(inst->mdp, MDP_IOMMU_DOMAIN_NS);
+	domain = msm_fb_get_iommu_domain(inst->mdp,
+			inst->secure ? MDP_IOMMU_DOMAIN_CP :
+					MDP_IOMMU_DOMAIN_NS);
 	ion_unmap_iommu(mmap->ion_client,
 			mregion->ion_handle,
 			domain, 0);
+
+	if (inst->secure)
+		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+
 	return 0;
 }
 
+int mdp_secure(struct v4l2_subdev *sd, void *arg)
+{
+	struct mdp_instance *inst = NULL;
+	int rc = 0;
+
+	if (!arg) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	inst = arg;
+	rc = msm_fb_writeback_set_secure(inst->mdp, true);
+	if (!rc)
+		inst->secure = true;
+
+	return rc;
+}
+
 long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	int rc = 0;
@@ -277,6 +329,9 @@
 	case MDP_MUNMAP:
 		rc = mdp_munmap(sd, arg);
 		break;
+	case MDP_SECURE:
+		rc = mdp_secure(sd, arg);
+		break;
 	default:
 		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index b2db208..2242c76 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -28,11 +28,12 @@
 	struct mutex mutex;
 };
 
-int mdp_init(struct v4l2_subdev *sd, u32 val)
+static int mdp_init(struct v4l2_subdev *sd, u32 val)
 {
 	return 0;
 }
-int mdp_open(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
 					GFP_KERNEL);
@@ -50,49 +51,54 @@
 	return rc;
 }
 
-int mdp_start(struct v4l2_subdev *sd, void *arg)
+static int mdp_start(struct v4l2_subdev *sd, void *arg)
 {
 	return 0;
 }
-int mdp_stop(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_stop(struct v4l2_subdev *sd, void *arg)
 {
 	return 0;
 }
-int mdp_close(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_close(struct v4l2_subdev *sd, void *arg)
 {
 	return 0;
 }
-int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	static int foo;
 	int rc = 0;
 	struct mdp_buf_info *binfo = arg;
 	struct mdp_instance *inst = NULL;
+	struct mdp_buf_queue *new_entry = NULL;
 
 	if (!binfo || !binfo->inst || !binfo->cookie) {
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
 
-
 	inst = binfo->inst;
-	if (binfo->kvaddr) {
-		struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
-				GFP_KERNEL);
-		memset((void *)binfo->kvaddr, foo++, 1024);
-		new_entry->mdp_buf_info = *binfo;
-		mutex_lock(&inst->mutex);
-		list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
-		mutex_unlock(&inst->mutex);
-		WFD_MSG_DBG("Queue %p with cookie %p\n",
-			(void *)binfo->paddr, (void *)binfo->cookie);
-	} else {
-		rc = -EINVAL;
-	}
+	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
+	if (!new_entry)
+		return -ENOMEM;
 
+	new_entry->mdp_buf_info = *binfo;
+	if (binfo->kvaddr)
+		memset((void *)binfo->kvaddr, foo++, 1024);
+
+
+	mutex_lock(&inst->mutex);
+	list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
+	mutex_unlock(&inst->mutex);
+
+	WFD_MSG_DBG("Queue %p with cookie %p\n",
+			(void *)binfo->paddr, (void *)binfo->cookie);
 	return rc;
 }
-int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_buf_info *binfo = arg;
 	struct mdp_buf_queue *head = NULL;
@@ -121,12 +127,13 @@
 	return 0;
 
 }
-int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
 {
 	return 0;
 }
 
-int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_mmap(struct v4l2_subdev *sd, void *arg)
 {
 	int rc = 0;
 	struct mem_region_map *mmap = arg;
@@ -137,12 +144,17 @@
 	return rc;
 }
 
-int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_munmap(struct v4l2_subdev *sd, void *arg)
 {
 	/* Whatever */
 	return 0;
 }
 
+static int mdp_secure(struct v4l2_subdev *sd)
+{
+	return 0;
+}
+
 long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	int rc = 0;
@@ -178,6 +190,9 @@
 	case MDP_MUNMAP:
 		rc = mdp_munmap(sd, arg);
 		break;
+	case MDP_SECURE:
+		rc = mdp_secure(sd);
+		break;
 	default:
 		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/wfd/mdp-subdev.h b/drivers/media/platform/msm/wfd/mdp-subdev.h
index b04d448..f2c6fb1 100644
--- a/drivers/media/platform/msm/wfd/mdp-subdev.h
+++ b/drivers/media/platform/msm/wfd/mdp-subdev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -59,6 +59,7 @@
 #define MDP_STOP  _IOR(MDP_MAGIC_IOCTL, 7, void *)
 #define MDP_MMAP  _IOR(MDP_MAGIC_IOCTL, 8, struct mem_region_map *)
 #define MDP_MUNMAP  _IOR(MDP_MAGIC_IOCTL, 9, struct mem_region_map *)
+#define MDP_SECURE  _IO(MDP_MAGIC_IOCTL, 9)
 
 
 extern int mdp_init(struct v4l2_subdev *sd, u32 val);
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 3b732ae..9fb7c6d 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -52,7 +52,7 @@
 	struct v4l2_subdev enc_sdev;
 	struct v4l2_subdev vsg_sdev;
 	struct ion_client *ion_client;
-	bool secure_device;
+	bool secure;
 	bool in_use;
 	bool mdp_iommu_split_domain;
 };
@@ -154,16 +154,16 @@
 {
 	struct ion_handle *handle = NULL;
 	void *kvaddr = NULL;
-	unsigned int alloc_regions = 0;
-	unsigned int ion_flags = 0;
+	unsigned int alloc_regions = 0, ion_flags = 0, align = 0;
 	int rc = 0;
 
 	alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
 	alloc_regions |= secure ? 0 :
 				ION_HEAP(ION_IOMMU_HEAP_ID);
 	ion_flags |= secure ? ION_SECURE : 0;
-	handle = ion_alloc(client,
-			mregion->size, SZ_4K, alloc_regions, ion_flags);
+	align = secure ? SZ_1M : SZ_4K;
+	handle = ion_alloc(client, mregion->size, align,
+			alloc_regions, ion_flags);
 
 	if (IS_ERR_OR_NULL(handle)) {
 		WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -171,12 +171,16 @@
 		goto alloc_fail;
 	}
 
-	kvaddr = ion_map_kernel(client, handle);
+	if (!secure) {
+		kvaddr = ion_map_kernel(client, handle);
 
-	if (IS_ERR_OR_NULL(kvaddr)) {
-		WFD_MSG_ERR("Failed to get virtual addr\n");
-		rc = PTR_ERR(kvaddr);
-		goto alloc_fail;
+		if (IS_ERR_OR_NULL(kvaddr)) {
+			WFD_MSG_ERR("Failed to get virtual addr\n");
+			rc = PTR_ERR(kvaddr);
+			goto alloc_fail;
+		}
+	} else {
+		kvaddr = NULL;
 	}
 
 	mregion->kvaddr = kvaddr;
@@ -206,7 +210,8 @@
 				"Invalid client or region");
 		return -EINVAL;
 	}
-	ion_unmap_kernel(client, mregion->ion_handle);
+	if (mregion->kvaddr)
+		ion_unmap_kernel(client, mregion->ion_handle);
 	ion_free(client, mregion->ion_handle);
 	return 0;
 }
@@ -256,7 +261,7 @@
 		enc_mregion->size = ALIGN(inst->input_buf_size, SZ_4K);
 
 		rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
-				wfd_dev->secure_device, enc_mregion);
+				wfd_dev->secure, enc_mregion);
 		if (rc) {
 			WFD_MSG_ERR("Failed to allocate input memory\n");
 			goto alloc_fail;
@@ -391,6 +396,7 @@
 				&inst->input_mem_list) {
 			mpair = list_entry(ptr, struct mem_region_pair,
 						list);
+
 			rc = v4l2_subdev_call(&wfd_dev->enc_sdev,
 					core, ioctl, FREE_INPUT_BUFFER,
 					(void *)mpair->enc);
@@ -1004,8 +1010,31 @@
 {
 	int rc = 0;
 	struct wfd_device *wfd_dev = video_drvdata(filp);
-	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
-			ioctl, SET_PROP, a);
+	struct wfd_inst *inst = filp->private_data;
+
+	switch (a->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+				ioctl, ENC_SECURE, NULL);
+		if (rc) {
+			WFD_MSG_ERR("Couldn't secure encoder");
+			break;
+		}
+
+		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+				ioctl, MDP_SECURE, (void *)inst->mdp_inst);
+		if (rc) {
+			WFD_MSG_ERR("Couldn't secure MDP");
+			break;
+		}
+
+		wfd_dev->secure = true;
+		break;
+	default:
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+				ioctl, SET_PROP, a);
+	}
+
 	if (rc)
 		WFD_MSG_ERR("Failed to set encoder property\n");
 	return rc;
@@ -1355,7 +1384,7 @@
 
 	wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
 
-	mdp_mops.secure = wfd_dev->secure_device;
+	mdp_mops.secure = wfd_dev->secure;
 	mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
 				(void *)&mdp_mops);
@@ -1373,7 +1402,7 @@
 	enc_mops.op_buffer_done = venc_op_buffer_done;
 	enc_mops.ip_buffer_done = venc_ip_buffer_done;
 	enc_mops.cbdata = filp;
-	enc_mops.secure = wfd_dev->secure_device;
+	enc_mops.secure = wfd_dev->secure;
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
 				(void *)&enc_mops);
 	if (rc || !enc_mops.cookie) {
@@ -1421,22 +1450,21 @@
 	inst = filp->private_data;
 	if (inst) {
 		wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		vb2_queue_release(&inst->vid_bufq);
+		wfd_free_input_buffers(wfd_dev, inst);
+
 		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_CLOSE, (void *)inst->mdp_inst);
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
 
-		vb2_queue_release(&inst->vid_bufq);
-		wfd_free_input_buffers(wfd_dev, inst);
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 				CLOSE, (void *)inst->venc_inst);
-
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE enc subdev: %d\n", rc);
 
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
 				VSG_CLOSE, NULL);
-
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE vsg subdev: %d\n", rc);
 
@@ -1604,7 +1632,7 @@
 
 		switch (WFD_DEVICE_NUMBER_BASE + c) {
 		case WFD_DEVICE_SECURE:
-			wfd_dev[c].secure_device = true;
+			wfd_dev[c].secure = true;
 			break;
 		default:
 			break;
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index 3fced2d..e15f4a9 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -50,3 +50,9 @@
 	  This driver supports Ethernet in the FSM9xxx.
 	  To compile this driver as a module, choose M here: the
 	  module will be called qfec.
+
+config ECM_IPA
+	tristate "STD ECM LAN Driver support"
+	depends on IPA
+	help
+	  Allows LAN between Apps and tethered HOST on STD ECM
diff --git a/drivers/net/ethernet/msm/Makefile b/drivers/net/ethernet/msm/Makefile
index 7d9d4c6..e152ec7 100644
--- a/drivers/net/ethernet/msm/Makefile
+++ b/drivers/net/ethernet/msm/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_MSM_RMNET_BAM) += msm_rmnet_bam.o
 obj-$(CONFIG_MSM_RMNET_SMUX) += msm_rmnet_smux.o
 obj-$(CONFIG_QFEC) += qfec.o
+obj-$(CONFIG_ECM_IPA) += ecm_ipa.o
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
new file mode 100644
index 0000000..605fd84
--- /dev/null
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -0,0 +1,1105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <mach/ecm_ipa.h>
+
+#define DRIVER_NAME "ecm_ipa"
+#define DRIVER_VERSION "19-Feb-2013"
+#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
+#define ECM_IPA_IPV6_HDR_NAME "ecm_eth_ipv6"
+#define IPA_TO_USB_CLIENT	IPA_CLIENT_USB_CONS
+#define INACTIVITY_MSEC_DELAY 100
+#define ECM_IPA_ERROR(fmt, args...) \
+	pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
+			fmt, __func__, __LINE__, current->comm, ## args)
+#ifdef ECM_IPA_DEBUG_ON
+#define ECM_IPA_DEBUG(fmt, args...) \
+	pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
+			fmt, __func__, __LINE__, current->comm, ## args)
+#else /* ECM_IPA_DEBUG_ON */
+#define ECM_IPA_DEBUG(fmt, args...)
+#endif /* ECM_IPA_DEBUG_ON */
+
+#define NULL_CHECK(ptr) \
+	do { \
+		if (!(ptr)) { \
+			ECM_IPA_ERROR("null pointer #ptr\n"); \
+			return -EINVAL; \
+		} \
+	} \
+	while (0)
+
+#define ECM_IPA_LOG_ENTRY() ECM_IPA_DEBUG("begin\n")
+#define ECM_IPA_LOG_EXIT() ECM_IPA_DEBUG("end\n")
+
+/**
+ * struct ecm_ipa_dev - main driver context parameters
+ * @ack_spinlock: protect last sent skb
+ * @last_out_skb: last sent skb saved until Tx notify is received from IPA
+ * @net: network interface struct implemented by this driver
+ * @folder: debugfs folder for various debuging switches
+ * @tx_enable: flag that enable/disable Tx path to continue to IPA
+ * @rx_enable: flag that enable/disable Rx path to continue to IPA
+ * @rm_enable: flag that enable/disable Resource manager request prior to Tx
+ * @dma_enable: flag that allow on-the-fly DMA mode for IPA
+ * @tx_file: saved debugfs entry to allow cleanup
+ * @rx_file: saved debugfs entry to allow cleanup
+ * @rm_file: saved debugfs entry to allow cleanup
+ * @dma_file: saved debugfs entry to allow cleanup
+ * @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
+ * @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
+ * @usb_to_ipa_hdl: save handle for IPA pipe operations
+ * @ipa_to_usb_hdl: save handle for IPA pipe operations
+ */
+struct ecm_ipa_dev {
+	spinlock_t ack_spinlock;
+	struct sk_buff *last_out_skb;
+	struct net_device *net;
+	bool tx_enable;
+	bool rx_enable;
+	bool rm_enable;
+	bool dma_enable;
+	struct dentry *folder;
+	struct dentry *tx_file;
+	struct dentry *rx_file;
+	struct dentry *rm_file;
+	struct dentry *dma_file;
+	uint32_t eth_ipv4_hdr_hdl;
+	uint32_t eth_ipv6_hdr_hdl;
+	u32 usb_to_ipa_hdl;
+	u32 ipa_to_usb_hdl;
+};
+
+/**
+ * struct ecm_ipa_ctx - saved pointer for the std ecm network device
+ *                which allow ecm_ipa to be a singleton
+ */
+static struct ecm_ipa_dev *ecm_ipa_ctx;
+
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
+static void sk_buff_print(struct sk_buff *skb);
+static int ecm_ipa_set_device_ethernet_addr(
+	u8 *dev_ethaddr, u8 device_ethaddr[]);
+static void ecm_ipa_packet_receive_notify(void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data);
+static void ecm_ipa_tx_complete_notify(void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data);
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
+static int ecm_ipa_open(struct net_device *net);
+static int ecm_ipa_stop(struct net_device *net);
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+					struct net_device *net);
+static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
+		unsigned long data);
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
+static void ecm_ipa_destory_rm_resource(void);
+static bool rx_filter(struct sk_buff *skb);
+static bool tx_filter(struct sk_buff *skb);
+static bool rm_enabled(struct ecm_ipa_dev *dev);
+
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+		const void *dst_mac, const void *src_mac);
+static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev);
+static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
+		char __user *ubuf, size_t count, loff_t *ppos);
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos);
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos);
+static void eth_get_drvinfo(struct net_device *net,
+		struct ethtool_drvinfo *drv_info);
+
+static const struct net_device_ops ecm_ipa_netdev_ops = {
+	.ndo_open		= ecm_ipa_open,
+	.ndo_stop		= ecm_ipa_stop,
+	.ndo_start_xmit = ecm_ipa_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+static const struct ethtool_ops ops = {
+	.get_drvinfo = eth_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
+const struct file_operations ecm_ipa_debugfs_tx_ops = {
+	.open = ecm_ipa_debugfs_tx_open,
+	.read = ecm_ipa_debugfs_enable_read,
+	.write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_rx_ops = {
+	.open = ecm_ipa_debugfs_rx_open,
+	.read = ecm_ipa_debugfs_enable_read,
+	.write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_rm_ops = {
+	.open = ecm_ipa_debugfs_rm_open,
+	.read = ecm_ipa_debugfs_enable_read,
+	.write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_dma_ops = {
+	.open = ecm_ipa_debugfs_dma_open,
+	.read = ecm_ipa_debugfs_enable_read,
+	.write = ecm_ipa_debugfs_enable_write_dma,
+};
+
+/**
+ * ecm_ipa_init() - initializes internal data structures
+ * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
+ * driver upon data packets received from USB pipe into IPA core.
+ * @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
+ * driver upon exception packets sent from IPA pipe into USB core.
+ * @priv: should be passed later on to ecm_ipa_configure, hold the network
+ * structure allocated for STD ECM interface.
+ *
+ * Shall be called prior to pipe connection.
+ * The out parameters (the callbacks) shall be supplied to ipa_connect.
+ * Detailed description:
+ *  - set the callbacks to be used by the caller upon ipa_connect
+ *  - allocate the network device
+ *  - set the priv argument with a reference to the network device
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
+		ecm_ipa_callback *ecm_ipa_tx_dp_notify,
+		void **priv)
+{
+	int ret = 0;
+	struct net_device *net;
+	struct ecm_ipa_dev *dev;
+	ECM_IPA_LOG_ENTRY();
+	ECM_IPA_DEBUG("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
+	NULL_CHECK(ecm_ipa_rx_dp_notify);
+	NULL_CHECK(ecm_ipa_tx_dp_notify);
+	NULL_CHECK(priv);
+	net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
+	if (!net) {
+		ret = -ENOMEM;
+		ECM_IPA_ERROR("fail to allocate etherdev\n");
+		goto fail_alloc_etherdev;
+	}
+	ECM_IPA_DEBUG("etherdev was successfully allocated\n");
+	dev = netdev_priv(net);
+	memset(dev, 0, sizeof(*dev));
+	dev->tx_enable = true;
+	dev->rx_enable = true;
+	spin_lock_init(&dev->ack_spinlock);
+	dev->net = net;
+	ecm_ipa_ctx = dev;
+	*priv = (void *)dev;
+	snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
+	net->netdev_ops = &ecm_ipa_netdev_ops;
+	ECM_IPA_DEBUG("internal data structures were intialized\n");
+	ret = ecm_ipa_debugfs_init(dev);
+	if (ret)
+		goto fail_debugfs;
+	ECM_IPA_DEBUG("debugfs entries were created\n");
+	*ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
+	*ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
+	ECM_IPA_LOG_EXIT();
+	return 0;
+fail_debugfs:
+	free_netdev(net);
+fail_alloc_etherdev:
+	return ret;
+}
+EXPORT_SYMBOL(ecm_ipa_init);
+
+/**
+ * ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
+ *				Headers will be commited to HW
+ * @dev: main driver context parameters
+ * @dst_mac: destination MAC address
+ * @src_mac: source MAC address
+ *
+ * Returns negative errno, or zero on success
+ */
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+		const void *dst_mac, const void *src_mac)
+{
+	struct ipa_ioc_add_hdr *hdrs;
+	struct ipa_hdr_add *ipv4_hdr;
+	struct ipa_hdr_add *ipv6_hdr;
+	struct ethhdr *eth_ipv4;
+	struct ethhdr *eth_ipv6;
+	int result = 0;
+
+	ECM_IPA_LOG_ENTRY();
+	hdrs = kzalloc(sizeof(*hdrs) + sizeof(*ipv4_hdr) + sizeof(*ipv6_hdr),
+			GFP_KERNEL);
+	if (!hdrs) {
+		result = -ENOMEM;
+		goto out;
+	}
+	ipv4_hdr = &hdrs->hdr[0];
+	eth_ipv4 = (struct ethhdr *)ipv4_hdr->hdr;
+	ipv6_hdr = &hdrs->hdr[1];
+	eth_ipv6 = (struct ethhdr *)ipv6_hdr->hdr;
+	strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
+	memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
+	memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
+	eth_ipv4->h_proto = ETH_P_IP;
+	ipv4_hdr->hdr_len = ETH_HLEN;
+	ipv4_hdr->is_partial = 0;
+	strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
+	memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
+	memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
+	eth_ipv6->h_proto = ETH_P_IPV6;
+	ipv6_hdr->hdr_len = ETH_HLEN;
+	ipv6_hdr->is_partial = 0;
+	hdrs->commit = 1;
+	hdrs->num_hdrs = 2;
+	result = ipa_add_hdr(hdrs);
+	if (result) {
+		ECM_IPA_ERROR("Fail on Header-Insertion(%d)\n", result);
+		goto out_free_mem;
+	}
+	if (ipv4_hdr->status) {
+		ECM_IPA_ERROR("Fail on Header-Insertion ipv4(%d)\n",
+				ipv4_hdr->status);
+		result = ipv4_hdr->status;
+		goto out_free_mem;
+	}
+	if (ipv6_hdr->status) {
+		ECM_IPA_ERROR("Fail on Header-Insertion ipv6(%d)\n",
+				ipv6_hdr->status);
+		result = ipv6_hdr->status;
+		goto out_free_mem;
+	}
+	dev->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
+	dev->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
+	ECM_IPA_LOG_EXIT();
+out_free_mem:
+	kfree(hdrs);
+out:
+	return result;
+}
+
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev)
+{
+	struct ipa_ioc_del_hdr *del_hdr;
+	struct ipa_hdr_del *ipv4;
+	struct ipa_hdr_del *ipv6;
+	int result;
+	del_hdr = kzalloc(sizeof(*del_hdr) + sizeof(*ipv4) +
+			sizeof(*ipv6), GFP_KERNEL);
+	if (!del_hdr)
+		return;
+	del_hdr->commit = 1;
+	del_hdr->num_hdls = 2;
+	ipv4 = &del_hdr->hdl[0];
+	ipv4->hdl = dev->eth_ipv4_hdr_hdl;
+	ipv6 = &del_hdr->hdl[1];
+	ipv6->hdl = dev->eth_ipv6_hdr_hdl;
+	result = ipa_del_hdr(del_hdr);
+	if (result || ipv4->status || ipv6->status)
+		ECM_IPA_ERROR("ipa_del_hdr failed");
+}
+
+static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev)
+{
+	struct ipa_tx_intf tx_properties = {0};
+	struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
+	struct ipa_ioc_tx_intf_prop *ipv4_property;
+	struct ipa_ioc_tx_intf_prop *ipv6_property;
+	int result = 0;
+	ECM_IPA_LOG_ENTRY();
+	tx_properties.prop = properties;
+	ipv4_property = &tx_properties.prop[0];
+	ipv4_property->ip = IPA_IP_v4;
+	ipv4_property->dst_pipe = IPA_TO_USB_CLIENT;
+	strlcpy(ipv4_property->hdr_name, ECM_IPA_IPV4_HDR_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	ipv6_property = &tx_properties.prop[1];
+	ipv6_property->ip = IPA_IP_v6;
+	ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
+	strlcpy(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	tx_properties.num_props = 2;
+	result = ipa_register_intf(dev->net->name, &tx_properties, NULL);
+	if (result)
+		ECM_IPA_ERROR("fail on Tx_prop registration\n");
+	ECM_IPA_LOG_EXIT();
+	return result;
+}
+
+static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev)
+{
+	int result;
+	ECM_IPA_LOG_ENTRY();
+	result = ipa_deregister_intf(dev->net->name);
+	if (result)
+		ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
+	ECM_IPA_LOG_EXIT();
+	return;
+}
+
+/**
+ * ecm_ipa_configure() - make IPA core end-point specific configuration
+ * @usb_to_ipa_hdl: handle of usb_to_ipa end-point for IPA driver
+ * @ipa_to_usb_hdl: handle of ipa_to_usb end-point for IPA driver
+ * @host_ethaddr: host Ethernet address in network order
+ * @device_ethaddr: device Ethernet address in network order
+ *
+ * Configure the usb_to_ipa and ipa_to_usb end-point registers
+ * - USB->IPA end-point: disable de-aggregation, enable link layer
+ *   header removal (Ethernet removal), source NATing and default routing.
+ * - IPA->USB end-point: disable aggregation, add link layer header (Ethernet)
+ * - allocate Ethernet device
+ * - register to Linux network stack
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+		void *priv)
+{
+	struct ecm_ipa_dev *dev = priv;
+	struct net_device *net;
+	int result;
+	ECM_IPA_LOG_ENTRY();
+	NULL_CHECK(host_ethaddr);
+	NULL_CHECK(host_ethaddr);
+	NULL_CHECK(dev);
+	net = dev->net;
+	NULL_CHECK(net);
+	ECM_IPA_DEBUG("host_ethaddr=%pM device_ethaddr=%pM\n",
+					host_ethaddr, device_ethaddr);
+	result = ecm_ipa_create_rm_resource(dev);
+	if (result) {
+		ECM_IPA_ERROR("fail on RM create\n");
+		return -EINVAL;
+	}
+	ECM_IPA_DEBUG("RM resource was created\n");
+	netif_carrier_off(dev->net);
+	result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
+			device_ethaddr);
+	if (result) {
+		ECM_IPA_ERROR("set device MAC failed\n");
+		goto fail_set_device_ethernet;
+	}
+	result = ecm_ipa_rules_cfg(dev, host_ethaddr, device_ethaddr);
+	if (result) {
+		ECM_IPA_ERROR("fail on ipa rules set\n");
+		goto fail_set_device_ethernet;
+	}
+	ECM_IPA_DEBUG("Ethernet header insertion was set\n");
+	result = ecm_ipa_register_tx(dev);
+	if (result) {
+		ECM_IPA_ERROR("fail on properties set\n");
+		goto fail_register_tx;
+	}
+	ECM_IPA_DEBUG("ECM Tx properties were registered\n");
+	result = register_netdev(net);
+	if (result) {
+		ECM_IPA_ERROR("register_netdev failed: %d\n", result);
+		goto fail_register_netdev;
+	}
+	ECM_IPA_DEBUG("register_netdev succeeded\n");
+	ECM_IPA_LOG_EXIT();
+	return 0;
+fail_register_netdev:
+	ecm_ipa_deregister_tx(dev);
+fail_register_tx:
+fail_set_device_ethernet:
+	ecm_ipa_rules_destroy(dev);
+	ecm_ipa_destory_rm_resource();
+	free_netdev(net);
+	return result;
+}
+EXPORT_SYMBOL(ecm_ipa_configure);
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+		void *priv)
+{
+	struct ecm_ipa_dev *dev = priv;
+	ECM_IPA_LOG_ENTRY();
+	NULL_CHECK(priv);
+	ECM_IPA_DEBUG("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
+					usb_to_ipa_hdl, ipa_to_usb_hdl);
+	if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
+		ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
+				usb_to_ipa_hdl);
+		return -EINVAL;
+	}
+	if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
+		ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
+				ipa_to_usb_hdl);
+		return -EINVAL;
+	}
+	dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
+	dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+	ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
+	netif_carrier_on(dev->net);
+	if (!netif_carrier_ok(dev->net)) {
+		ECM_IPA_ERROR("netif_carrier_ok error\n");
+		return -EBUSY;
+	}
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_connect);
+
+int ecm_ipa_disconnect(void *priv)
+{
+	struct ecm_ipa_dev *dev = priv;
+	ECM_IPA_LOG_ENTRY();
+	NULL_CHECK(dev);
+	netif_carrier_off(dev->net);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_disconnect);
+
+
+static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
+		unsigned long data)
+{
+	struct ecm_ipa_dev *dev = user_data;
+	ECM_IPA_LOG_ENTRY();
+	if (event == IPA_RM_RESOURCE_GRANTED &&
+			netif_queue_stopped(dev->net)) {
+		ECM_IPA_DEBUG("Resource Granted - waking queue\n");
+		netif_wake_queue(dev->net);
+	} else {
+		ECM_IPA_DEBUG("Resource released\n");
+	}
+	ECM_IPA_LOG_EXIT();
+}
+
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev)
+{
+	struct ipa_rm_create_params create_params = {0};
+	int result;
+	ECM_IPA_LOG_ENTRY();
+	create_params.name = IPA_RM_RESOURCE_STD_ECM_PROD;
+	create_params.reg_params.user_data = dev;
+	create_params.reg_params.notify_cb = ecm_ipa_rm_notify;
+	result = ipa_rm_create_resource(&create_params);
+	if (result) {
+		ECM_IPA_ERROR("Fail on ipa_rm_create_resource\n");
+		goto fail_rm_create;
+	}
+	ECM_IPA_DEBUG("rm client was created");
+
+	result = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_STD_ECM_PROD,
+			INACTIVITY_MSEC_DELAY);
+	if (result) {
+		ECM_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
+		goto fail_it;
+	}
+	ECM_IPA_DEBUG("rm_it client was created");
+	ECM_IPA_LOG_EXIT();
+	return 0;
+fail_it:
+fail_rm_create:
+	return result;
+}
+
+static void ecm_ipa_destory_rm_resource(void)
+{
+	ECM_IPA_LOG_ENTRY();
+	ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_STD_ECM_PROD);
+	ECM_IPA_LOG_EXIT();
+}
+
+static bool rx_filter(struct sk_buff *skb)
+{
+	struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
+	return !dev->rx_enable;
+}
+
+static bool tx_filter(struct sk_buff *skb)
+{
+	struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
+	return !dev->tx_enable;
+}
+
+static bool rm_enabled(struct ecm_ipa_dev *dev)
+{
+	return dev->rm_enable;
+}
+
+static int ecm_ipa_open(struct net_device *net)
+{
+	ECM_IPA_LOG_ENTRY();
+	netif_start_queue(net);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+static int ecm_ipa_stop(struct net_device *net)
+{
+	ECM_IPA_LOG_ENTRY();
+	ECM_IPA_DEBUG("stopping net device\n");
+	netif_stop_queue(net);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+/**
+ * ecm_ipa_cleanup() - destroys all
+ * ecm information
+ * @priv: main driver context parameters
+ *
+ */
+void ecm_ipa_cleanup(void *priv)
+{
+	struct ecm_ipa_dev *dev = priv;
+	ECM_IPA_LOG_ENTRY();
+	if (!dev) {
+		ECM_IPA_ERROR("dev NULL pointer\n");
+		return;
+	}
+	if (rm_enabled(dev)) {
+		ecm_ipa_destory_rm_resource();
+		ecm_ipa_debugfs_destroy(dev);
+	}
+	if (!dev->net) {
+		unregister_netdev(dev->net);
+		free_netdev(dev->net);
+	}
+	ECM_IPA_DEBUG("cleanup done\n");
+	ecm_ipa_ctx = NULL;
+	ECM_IPA_LOG_EXIT();
+	return ;
+}
+EXPORT_SYMBOL(ecm_ipa_cleanup);
+
+static int resource_request(struct ecm_ipa_dev *dev)
+{
+	int result = 0;
+	ECM_IPA_LOG_ENTRY();
+	if (!rm_enabled(dev))
+		goto out;
+	result = ipa_rm_inactivity_timer_request_resource(
+			IPA_RM_RESOURCE_STD_ECM_PROD);
+out:
+	ECM_IPA_LOG_EXIT();
+	return result;
+}
+
+static void resource_release(struct ecm_ipa_dev *dev)
+{
+	ECM_IPA_LOG_ENTRY();
+	if (!rm_enabled(dev))
+		goto out;
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+out:
+	ECM_IPA_LOG_EXIT();
+}
+
+/**
+ * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
+ * @skb: packet received from Linux stack
+ * @net: the network device being used to send this packet
+ *
+ * Several conditions needed in order to send the packet to IPA:
+ * - we are in a valid state were the queue is not stopped
+ * - Filter Tx switch is turned off
+ * - The resources required for actual Tx are all up
+ *
+ */
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+					struct net_device *net)
+{
+	int ret;
+	netdev_tx_t status = NETDEV_TX_BUSY;
+	struct ecm_ipa_dev *dev = netdev_priv(net);
+	unsigned long flags;
+	ECM_IPA_LOG_ENTRY();
+	if (unlikely(netif_queue_stopped(net))) {
+		ECM_IPA_ERROR("interface queue is stopped\n");
+		goto out;
+	}
+	ECM_IPA_DEBUG("send (proto=0x%04x)\n", ntohs(skb->protocol));
+	if (unlikely(tx_filter(skb))) {
+		dev_kfree_skb_any(skb);
+		ECM_IPA_ERROR("packet got filtered out on Tx path\n");
+		status = NETDEV_TX_OK;
+		goto out;
+	}
+	ret = resource_request(dev);
+	if (ret) {
+		ECM_IPA_DEBUG("Waiting to resource\n");
+		netif_stop_queue(net);
+		goto resource_busy;
+	}
+	ECM_IPA_DEBUG("taking ack_lock\n");
+	spin_lock_irqsave(&dev->ack_spinlock, flags);
+	ECM_IPA_DEBUG("ack_lock taken\n");
+	if (dev->last_out_skb) {
+		ECM_IPA_DEBUG("No Tx-ack received for previous packet\n");
+		ECM_IPA_DEBUG("releasing ack_lock\n");
+		spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+		ECM_IPA_DEBUG("ack_lock released\n");
+		netif_stop_queue(net);
+		status = -NETDEV_TX_BUSY;
+		goto out;
+	} else {
+		dev->last_out_skb = skb;
+	}
+	ECM_IPA_DEBUG("releasing ack_lock\n");
+	spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+	ECM_IPA_DEBUG("ack_lock released\n");
+	sk_buff_print(skb);
+	ECM_IPA_DEBUG("ipa_tx_dp is called (dst_client=%d)\n",
+			IPA_TO_USB_CLIENT);
+	ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
+	if (ret) {
+		ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
+		goto fail_tx_packet;
+	}
+	net->stats.tx_packets++;
+	net->stats.tx_bytes += skb->len;
+	ECM_IPA_LOG_EXIT();
+	status = NETDEV_TX_OK;
+	goto out;
+fail_tx_packet:
+out:
+	resource_release(dev);
+resource_busy:
+	ECM_IPA_LOG_EXIT();
+	return status;
+}
+
+/**
+ * ecm_ipa_packet_receive_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ */
+void ecm_ipa_packet_receive_notify(void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	struct ecm_ipa_dev *dev = priv;
+	int result;
+	ECM_IPA_LOG_ENTRY();
+	if (evt != IPA_RECEIVE)	{
+		ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
+		return;
+	}
+	ECM_IPA_DEBUG("receive\n");
+	sk_buff_print(skb);
+	skb->dev = dev->net;
+	skb->protocol = eth_type_trans(skb, dev->net);
+	if (rx_filter(skb)) {
+		ECM_IPA_ERROR("packet got filtered out on Rx path\n");
+		dev_kfree_skb_any(skb);
+		return;
+	}
+	ECM_IPA_DEBUG("kernel stack Rx is called\n");
+	result = netif_rx(skb);
+	if (result)
+		ECM_IPA_ERROR("fail on netif_rx\n");
+	dev->net->stats.rx_packets++;
+	dev->net->stats.rx_bytes += skb->len;
+	ECM_IPA_LOG_EXIT();
+	return;
+}
+
+/**
+ * ecm_ipa_tx_complete_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * Check that the packet is the one we sent and release it
+ * This function will be called in defered context in IPA wq.
+ */
+void ecm_ipa_tx_complete_notify(void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	struct ecm_ipa_dev *dev = priv;
+	unsigned long flags;
+	ECM_IPA_LOG_ENTRY();
+
+	if (!dev) {
+		ECM_IPA_ERROR("dev is NULL pointer\n");
+		return;
+	}
+	if (evt != IPA_WRITE_DONE) {
+		ECM_IPA_ERROR("unsupported event on Tx callback\n");
+		return;
+	}
+	ECM_IPA_DEBUG("taking ack_lock\n");
+	spin_lock_irqsave(&dev->ack_spinlock, flags);
+	ECM_IPA_DEBUG("ack_lock taken\n");
+	if (skb != dev->last_out_skb)
+		ECM_IPA_ERROR("ACKed/Sent not the same(FIFO expected)\n");
+	dev->last_out_skb = NULL;
+	ECM_IPA_DEBUG("releasing ack_lock\n");
+	spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+	ECM_IPA_DEBUG("ack_lock released\n");
+	if (netif_queue_stopped(dev->net)) {
+		ECM_IPA_DEBUG("waking up queue\n");
+		netif_wake_queue(dev->net);
+	}
+	dev_kfree_skb_any(skb);
+	ECM_IPA_LOG_EXIT();
+	return;
+}
+
+static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
+{
+	struct ecm_ipa_dev *dev = inode->i_private;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = &(dev->tx_enable);
+	ECM_IPA_LOG_ENTRY();
+	return 0;
+}
+
+static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
+{
+	struct ecm_ipa_dev *dev = inode->i_private;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = &(dev->rx_enable);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
+{
+	struct ecm_ipa_dev *dev = inode->i_private;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = &(dev->rm_enable);
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct ecm_ipa_dev *dev = file->private_data;
+	int result;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = &dev->dma_enable;
+	result = ecm_ipa_debugfs_enable_write(file, buf, count, ppos);
+	if (dev->dma_enable)
+		ecm_ipa_ep_registers_dma_cfg(dev->usb_to_ipa_hdl);
+	else
+		ecm_ipa_ep_registers_cfg(dev->usb_to_ipa_hdl,
+				dev->usb_to_ipa_hdl);
+	ECM_IPA_LOG_EXIT();
+	return result;
+}
+
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file)
+{
+	struct ecm_ipa_dev *dev = inode->i_private;
+	ECM_IPA_LOG_ENTRY();
+	file->private_data = dev;
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	unsigned long missing;
+	char input;
+	bool *enable = file->private_data;
+	if (count != sizeof(input) + 1) {
+		ECM_IPA_ERROR("wrong input length(%zd)\n", count);
+		return -EINVAL;
+	}
+	if (!buf) {
+		ECM_IPA_ERROR("Bad argument\n");
+		return -EINVAL;
+	}
+	missing = copy_from_user(&input, buf, 1);
+	if (missing)
+		return -EFAULT;
+	ECM_IPA_DEBUG("input received %c\n", input);
+	*enable = input - '0';
+	ECM_IPA_DEBUG("value was set to %d\n", *enable);
+	return count;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
+		char __user *ubuf, size_t count, loff_t *ppos)
+{
+	int nbytes;
+	int size = 0;
+	int ret;
+	loff_t pos;
+	u8 enable_str[sizeof(char)*3] = {0};
+	bool *enable = file->private_data;
+	pos = *ppos;
+	nbytes = scnprintf(enable_str, sizeof(enable_str), "%d\n", *enable);
+	ret = simple_read_from_buffer(ubuf, count, ppos, enable_str, nbytes);
+	if (ret < 0) {
+		ECM_IPA_ERROR("simple_read_from_buffer problem");
+		return ret;
+	}
+	size += ret;
+	count -= nbytes;
+	*ppos = pos + size;
+	return size;
+}
+
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
+{
+	const mode_t flags = S_IRUSR | S_IRGRP | S_IROTH |
+			S_IWUSR | S_IWGRP | S_IWOTH;
+	int ret = -EINVAL;
+	ECM_IPA_LOG_ENTRY();
+	if (!dev)
+		return -EINVAL;
+	dev->folder = debugfs_create_dir("ecm_ipa", NULL);
+	if (!dev->folder) {
+		ECM_IPA_ERROR("could not create debugfs folder entry\n");
+		ret = -EFAULT;
+		goto fail_folder;
+	}
+	dev->tx_file = debugfs_create_file("tx_enable", flags, dev->folder, dev,
+		   &ecm_ipa_debugfs_tx_ops);
+	if (!dev->tx_file) {
+		ECM_IPA_ERROR("could not create debugfs tx file\n");
+		ret = -EFAULT;
+		goto fail_file;
+	}
+	dev->rx_file = debugfs_create_file("rx_enable", flags, dev->folder, dev,
+			&ecm_ipa_debugfs_rx_ops);
+	if (!dev->rx_file) {
+		ECM_IPA_ERROR("could not create debugfs rx file\n");
+		ret = -EFAULT;
+		goto fail_file;
+	}
+	dev->rm_file = debugfs_create_file("rm_enable", flags, dev->folder, dev,
+			&ecm_ipa_debugfs_rm_ops);
+	if (!dev->rm_file) {
+		ECM_IPA_ERROR("could not create debugfs rm file\n");
+		ret = -EFAULT;
+		goto fail_file;
+	}
+	dev->dma_file = debugfs_create_file("dma_enable", flags, dev->folder,
+			dev, &ecm_ipa_debugfs_dma_ops);
+	if (!dev->dma_file) {
+		ECM_IPA_ERROR("could not create debugfs dma file\n");
+		ret = -EFAULT;
+		goto fail_file;
+	}
+	ECM_IPA_LOG_EXIT();
+	return 0;
+fail_file:
+	debugfs_remove_recursive(dev->folder);
+fail_folder:
+	return ret;
+}
+
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
+{
+	debugfs_remove_recursive(dev->folder);
+}
+
+static void eth_get_drvinfo(struct net_device *net,
+		struct ethtool_drvinfo *drv_info)
+{
+	ECM_IPA_LOG_ENTRY();
+	strlcpy(drv_info->driver, DRIVER_NAME, sizeof(drv_info->driver));
+	strlcpy(drv_info->version, DRIVER_VERSION, sizeof(drv_info->version));
+	ECM_IPA_LOG_EXIT();
+}
+
+
+/**
+ * ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
+ *
+ *usb_to_ipa_hdl: handle received from ipa_connect
+ *ipa_to_usb_hdl: handle received from ipa_connect
+ *
+ * USB to IPA pipe:
+ *  - No de-aggregation
+ *  - Remove Ethernet header
+ *  - SRC NAT
+ *  - Default routing(0)
+ * IPA to USB Pipe:
+ *  - No aggregation
+ *  - Add Ethernet header
+ */
+int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
+{
+	int result = 0;
+	struct ipa_ep_cfg usb_to_ipa_ep_cfg;
+	struct ipa_ep_cfg ipa_to_usb_ep_cfg;
+	ECM_IPA_LOG_ENTRY();
+	memset(&usb_to_ipa_ep_cfg, 0 , sizeof(struct ipa_ep_cfg));
+	usb_to_ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
+	usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
+	usb_to_ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT;
+	usb_to_ipa_ep_cfg.route.rt_tbl_hdl = 0;
+	usb_to_ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
+	usb_to_ipa_ep_cfg.mode.mode = IPA_BASIC;
+	result = ipa_cfg_ep(usb_to_ipa_hdl, &usb_to_ipa_ep_cfg);
+	if (result) {
+		ECM_IPA_ERROR("failed to configure USB to IPA point\n");
+		goto out;
+	}
+	memset(&ipa_to_usb_ep_cfg, 0 , sizeof(struct ipa_ep_cfg));
+	ipa_to_usb_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
+	ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN;
+	ipa_to_usb_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
+	result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
+	if (result) {
+		ECM_IPA_ERROR("failed to configure IPA to USB end-point\n");
+		goto out;
+	}
+	ECM_IPA_DEBUG("end-point registers successfully configured\n");
+out:
+	ECM_IPA_LOG_EXIT();
+	return result;
+}
+
+/**
+ * ecm_ipa_ep_registers_dma_cfg() - configure the USB endpoints for ECM
+ *	DMA
+ * @usb_to_ipa_hdl: handle received from ipa_connect
+ *
+ * This function will override the previous configuration
+ * which is needed for cores that does not support blocks logic
+ * Note that client handles are the actual pipe index
+ */
+int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
+{
+	int result = 0;
+	struct ipa_ep_cfg_mode cfg_mode;
+	u32 apps_to_ipa_hdl = 2;
+	ECM_IPA_LOG_ENTRY();
+	/* Apps to IPA - override the configuration made by IPA driver
+	 * in order to allow data path on older platforms*/
+	memset(&cfg_mode, 0 , sizeof(cfg_mode));
+	cfg_mode.mode = IPA_DMA;
+	cfg_mode.dst = IPA_CLIENT_USB_CONS;
+	result = ipa_cfg_ep_mode(apps_to_ipa_hdl, &cfg_mode);
+	if (result) {
+		ECM_IPA_ERROR("failed to configure Apps to IPA\n");
+		goto out;
+	}
+	memset(&cfg_mode, 0 , sizeof(cfg_mode));
+	cfg_mode.mode = IPA_DMA;
+	cfg_mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
+	result = ipa_cfg_ep_mode(usb_to_ipa_hdl, &cfg_mode);
+	if (result) {
+		ECM_IPA_ERROR("failed to configure USB to IPA\n");
+		goto out;
+	}
+	ECM_IPA_DEBUG("end-point registers successfully configured\n");
+out:
+	ECM_IPA_LOG_EXIT();
+	return result;
+}
+
+static void ecm_ipa_dump_buff(u8 *buff, u32 byte_size)
+{
+	int i;
+	ECM_IPA_DEBUG("ofst(hex), addr(hex), data(hex), value(char):\n");
+	for (i = 0 ; i < byte_size; i += 4) {
+		ECM_IPA_DEBUG("%2x  %p   %02x %02x %02x %02x | %c %c %c %c\n",
+				i, &buff[i],
+				buff[i], buff[i+1], buff[i+2], buff[i+3],
+				buff[i], buff[i+1], buff[i+2], buff[i+3]);
+	}
+}
+
+/**
+ * sk_buff_print() - detailed sk_buff printouts
+ * @skb: the socket buff
+ */
+void sk_buff_print(struct sk_buff *skb)
+{
+	ECM_IPA_DEBUG("called by: %s\n", current->comm);
+	ECM_IPA_DEBUG("skb->next=0x%p, skb->prev=0x%p, skb->sk=0x%p\n",
+			skb->next, skb->prev, skb->sk);
+	ECM_IPA_DEBUG("skb->len=0x%x, skb->data_len=0x%x protocol=0x%04x\n",
+				skb->len, skb->data_len, skb->protocol);
+	ECM_IPA_DEBUG("skb->mac_len=0x%x, skb->hdr_len=0x%x, skb->csum=%x\n",
+			skb->mac_len, skb->hdr_len, skb->csum);
+
+	ECM_IPA_DEBUG("mac_header = 0x%p\n", skb_mac_header(skb));
+	ECM_IPA_DEBUG("network_header = 0x%p\n", skb_network_header(skb));
+	ECM_IPA_DEBUG("transport_header=0x%p\n", skb_transport_header(skb));
+
+	ECM_IPA_DEBUG("skb->head=0x%p\n", skb->head);
+	ECM_IPA_DEBUG("skb->data=0x%p\n", skb->data);
+	ECM_IPA_DEBUG("tail=0x%p\n", skb_tail_pointer(skb));
+	ECM_IPA_DEBUG("end =0x%p\n", skb_end_pointer(skb));
+	ECM_IPA_DEBUG("skb->truesize=0x%x (buffer size)\n",
+				skb->truesize);
+	ecm_ipa_dump_buff(skb->data, skb->len);
+}
+
+/**
+ * ecm_ipa_set_device_ethernet_addr() - set device etherenet address
+ * @dev_ethaddr: device etherenet address
+ *
+ * Returns 0 for success, negative otherwise
+ */
+int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr, u8 device_ethaddr[])
+{
+	if (!is_valid_ether_addr(device_ethaddr))
+		return -EINVAL;
+	memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
+	ECM_IPA_DEBUG("device ethernet address: %pM\n", dev_ethaddr);
+	return 0;
+}
+
+/**
+ * ecm_ipa_init_module() - module initialization
+ *
+ */
+static int ecm_ipa_init_module(void)
+{
+	ECM_IPA_LOG_ENTRY();
+	ECM_IPA_LOG_EXIT();
+	return 0;
+}
+
+/**
+ * ecm_ipa_cleanup_module() - module cleanup
+ *
+ */
+static void ecm_ipa_cleanup_module(void)
+{
+	ECM_IPA_LOG_ENTRY();
+	ECM_IPA_LOG_EXIT();
+	return;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ECM IPA network interface");
+
+late_initcall(ecm_ipa_init_module);
+module_exit(ecm_ipa_cleanup_module);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index f4dff66..76e3175 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -101,4 +101,14 @@
 		This driver gets the Q6 out of power collapsed state and
 		exposes ioctl control to read avtimer tick.
 
+config SSM
+	tristate "Qualcomm Secure Service Module"
+	depends on QSEECOM
+	depends on MSM_SMD
+	help
+	  Provides an interface for OEM driver to communicate with Trustzone
+	  and modem for key exchange and mode change.
+	  This driver uses Secure Channel Manager interface for trustzone
+	  communication and communicates with modem over SMD channel.
+
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index a679fb9..289ece9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o
 obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
 obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
+obj-$(CONFIG_SSM) += ssm.o
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index c541eb7..a25c799 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
-	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o
+	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o \
+	ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 7690b21..ccf5f96 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -26,6 +26,7 @@
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include "ipa_i.h"
+#include "ipa_rm_i.h"
 
 #define IPA_SUMMING_THRESHOLD (0x10)
 #define IPA_PIPE_MEM_START_OFST (0x0)
@@ -1528,6 +1529,7 @@
 * - Create empty routing table in system memory(no committing)
 * - Initialize pipes memory pool with ipa_pipe_mem_init for supported platforms
 * - Create a char-device for IPA
+* - Initialize IPA RM (resource manager)
 */
 static int ipa_init(const struct ipa_plat_drv_res *resource_p)
 {
@@ -1870,10 +1872,20 @@
 	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
 		ipa_disable_clks();
 
+	/* Initialize IPA RM (resource manager) */
+	result = ipa_rm_initialize();
+	if (result) {
+		IPAERR(":cdev_add err=%d\n", -result);
+		result = -ENODEV;
+		goto fail_ipa_rm_init;
+	}
+
 	IPADBG(":IPA driver init OK.\n");
 
 	return 0;
 
+fail_ipa_rm_init:
+	cdev_del(&ipa_ctx->cdev);
 fail_cdev_add:
 	device_destroy(ipa_ctx->class, ipa_ctx->dev_num);
 fail_device_create:
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
new file mode 100644
index 0000000..99b19cc
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+#include "ipa_i.h"
+#include "ipa_rm_dependency_graph.h"
+#include "ipa_rm_i.h"
+#include "ipa_rm_resource.h"
+
+struct ipa_rm_context_type {
+	struct ipa_rm_dep_graph *dep_graph;
+	struct workqueue_struct *ipa_rm_wq;
+};
+static struct ipa_rm_context_type *ipa_rm_ctx;
+
+/**
+ * ipa_rm_create_resource() - create resource
+ * @create_params: [in] parameters needed
+ *                  for resource initialization
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * This function is called by IPA RM client to initialize client's resources.
+ * This API should be called before any other IPA RM API
+ * on given resource name.
+ *
+ */
+int ipa_rm_create_resource(struct ipa_rm_create_params *create_params)
+{
+	struct ipa_rm_resource *resource;
+	int result;
+
+	if (!create_params) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					  create_params->name,
+					  &resource) == 0) {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_create(create_params,
+			&resource);
+	if (result)
+		goto bail;
+	result = ipa_rm_dep_graph_add(ipa_rm_ctx->dep_graph, resource);
+	if (result)
+		ipa_rm_resource_delete(resource);
+bail:
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_create_resource);
+
+/**
+ * ipa_rm_add_dependency() - create dependency
+ *					between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+			enum ipa_rm_resource_name depends_on_name)
+{
+	return ipa_rm_dep_graph_add_dependency(
+			ipa_rm_ctx->dep_graph,
+			resource_name,
+			depends_on_name);
+}
+EXPORT_SYMBOL(ipa_rm_add_dependency);
+
+/**
+ * ipa_rm_delete_dependency() - create dependency
+ *					between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+			enum ipa_rm_resource_name depends_on_name)
+{
+	return ipa_rm_dep_graph_delete_dependency(
+			ipa_rm_ctx->dep_graph,
+			resource_name,
+			depends_on_name);
+}
+EXPORT_SYMBOL(ipa_rm_delete_dependency);
+
+/**
+ * ipa_rm_request_resource() - request resource
+ * @resource_name: [in] name of the requested resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * All registered callbacks are called with IPA_RM_RESOURCE_GRANTED
+ * on successful completion of this operation.
+ */
+int ipa_rm_request_resource(enum ipa_rm_resource_name resource_name)
+{
+	struct ipa_rm_resource *resource;
+	int result;
+	IPADBG("IPA RM ::ipa_rm_request_resource ENTER\n");
+
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+			result = -EINVAL;
+			goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+			resource_name,
+			&resource) != 0) {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_producer_request(
+			(struct ipa_rm_resource_prod *)resource);
+
+bail:
+	IPADBG("IPA RM ::ipa_rm_request_resource EXIT [%d]\n", result);
+
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_request_resource);
+
+/**
+ * ipa_rm_release_resource() - release resource
+ * @resource_name: [in] name of the requested resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * All registered callbacks are called with IPA_RM_RESOURCE_RELEASED
+ * on successful completion of this operation.
+ */
+int ipa_rm_release_resource(enum ipa_rm_resource_name resource_name)
+{
+	struct ipa_rm_resource *resource;
+	int result;
+	IPADBG("IPA RM ::ipa_rm_release_resource ENTER\n");
+
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					  resource_name,
+					  &resource) != 0) {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_producer_release(
+		    (struct ipa_rm_resource_prod *)resource);
+
+bail:
+	IPADBG("IPA RM ::ipa_rm_release_resource EXIT [%d]\n", result);
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_release_resource);
+
+/**
+ * ipa_rm_register() - register for event
+ * @resource_name: resource name
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Registration parameters provided here should be the same
+ * as provided later in  ipa_rm_deregister() call.
+ */
+int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params)
+{
+	int result;
+	struct ipa_rm_resource *resource;
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+				resource_name,
+				&resource) != 0) {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_producer_register(
+			(struct ipa_rm_resource_prod *)resource,
+			reg_params);
+bail:
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_register);
+
+/**
+ * ipa_rm_deregister() - cancel the registration
+ * @resource_name: resource name
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Registration parameters provided here should be the same
+ * as provided in  ipa_rm_register() call.
+ */
+int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+			struct ipa_rm_register_params *reg_params)
+{
+	int result;
+	struct ipa_rm_resource *resource;
+	if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+			resource_name,
+			&resource) != 0) {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_producer_deregister(
+			(struct ipa_rm_resource_prod *)resource,
+			reg_params);
+bail:
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_deregister);
+
+/**
+ * ipa_rm_notify_completion() -
+ *	consumer driver notification for
+ *	request_resource / release_resource operations
+ *	completion
+ * @event: notified event
+ * @resource_name: resource name
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_notify_completion(enum ipa_rm_event event,
+		enum ipa_rm_resource_name resource_name)
+{
+	int result;
+	if (!IPA_RM_RESORCE_IS_CONS(resource_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	ipa_rm_wq_send_cmd(IPA_RM_WQ_RESOURCE_CB,
+			resource_name,
+			event);
+	result = 0;
+bail:
+	return result;
+}
+EXPORT_SYMBOL(ipa_rm_notify_completion);
+
+static void ipa_rm_wq_handler(struct work_struct *work)
+{
+	struct ipa_rm_resource *resource;
+	struct ipa_rm_wq_work_type *ipa_rm_work =
+			container_of(work,
+					struct ipa_rm_wq_work_type,
+					work);
+	switch (ipa_rm_work->wq_cmd) {
+	case IPA_RM_WQ_NOTIFY_PROD:
+		if (!IPA_RM_RESORCE_IS_PROD(ipa_rm_work->resource_name))
+			return;
+		if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+						ipa_rm_work->resource_name,
+						&resource) != 0)
+			return;
+		ipa_rm_resource_producer_notify_clients(
+				(struct ipa_rm_resource_prod *)resource,
+				ipa_rm_work->event);
+
+		break;
+	case IPA_RM_WQ_NOTIFY_CONS:
+		break;
+	case IPA_RM_WQ_RESOURCE_CB:
+		if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+						ipa_rm_work->resource_name,
+						&resource) != 0)
+			return;
+		ipa_rm_resource_consumer_handle_cb(
+				(struct ipa_rm_resource_cons *)resource,
+				ipa_rm_work->event);
+		break;
+	default:
+		break;
+	}
+
+	kfree((void *) work);
+}
+
+/**
+ * ipa_rm_wq_send_cmd() - send a command for deferred work
+ * @wq_cmd: command that should be executed
+ * @resource_name: resource on which command should be executed
+ *
+ * Returns: 0 on success, negative otherwise
+ */
+int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_event event)
+{
+	int result = -ENOMEM;
+	struct ipa_rm_wq_work_type *work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (work) {
+		INIT_WORK((struct work_struct *)work, ipa_rm_wq_handler);
+		work->wq_cmd = wq_cmd;
+		work->resource_name = resource_name;
+		work->event = event;
+		result = queue_work(ipa_rm_ctx->ipa_rm_wq,
+				(struct work_struct *)work);
+	}
+	return result;
+}
+
+/**
+ * ipa_rm_initialize() - initialize IPA RM component
+ *
+ * Returns: 0 on success, negative otherwise
+ */
+int ipa_rm_initialize(void)
+{
+	int result;
+
+	ipa_rm_ctx = kzalloc(sizeof(*ipa_rm_ctx), GFP_KERNEL);
+	if (!ipa_rm_ctx) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	ipa_rm_ctx->ipa_rm_wq = create_singlethread_workqueue("ipa_rm_wq");
+	if (!ipa_rm_ctx->ipa_rm_wq) {
+		result = -ENOMEM;
+		goto create_wq_fail;
+	}
+	result = ipa_rm_dep_graph_create(&(ipa_rm_ctx->dep_graph));
+	if (result)
+		goto graph_alloc_fail;
+	IPADBG("IPA RM ipa_rm_initialize SUCCESS\n");
+	return 0;
+
+graph_alloc_fail:
+	destroy_workqueue(ipa_rm_ctx->ipa_rm_wq);
+create_wq_fail:
+	kfree(ipa_rm_ctx);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_exit() - free all IPA RM resources
+ */
+void ipa_rm_exit(void)
+{
+	ipa_rm_dep_graph_delete(ipa_rm_ctx->dep_graph);
+	destroy_workqueue(ipa_rm_ctx->ipa_rm_wq);
+	kfree(ipa_rm_ctx);
+	ipa_rm_ctx = NULL;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
new file mode 100644
index 0000000..6afab42
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include "ipa_rm_dependency_graph.h"
+#include "ipa_rm_i.h"
+
+static int ipa_rm_dep_get_index(enum ipa_rm_resource_name resource_name)
+{
+	int resource_index = IPA_RM_INDEX_INVALID;
+	if (IPA_RM_RESORCE_IS_PROD(resource_name))
+		resource_index = ipa_rm_prod_index(resource_name);
+	else if (IPA_RM_RESORCE_IS_CONS(resource_name))
+		resource_index = ipa_rm_cons_index(resource_name);
+
+	return resource_index;
+}
+
+/**
+ * ipa_rm_dep_graph_create() - creates graph
+ * @dep_graph: [out] created dependency graph
+ *
+ * Returns: dependency graph on success, NULL on failure
+ */
+int  ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph)
+{
+	int result = 0;
+	*dep_graph = kzalloc(sizeof(**dep_graph), GFP_KERNEL);
+	if (!*dep_graph) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	rwlock_init(&((*dep_graph)->lock));
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_dep_graph_delete() - destroyes the graph
+ * @graph: [in] dependency graph
+ *
+ * Frees all resources.
+ */
+void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph)
+{
+	int resource_index;
+	if (!graph)
+		return;
+	write_lock(&graph->lock);
+	for (resource_index = 0;
+			resource_index < IPA_RM_RESOURCE_MAX;
+			resource_index++)
+		kfree(graph->resource_table[resource_index]);
+	write_unlock(&graph->lock);
+	memset(graph->resource_table, 0, sizeof(graph->resource_table));
+}
+
+/**
+ * ipa_rm_dep_graph_get_resource() - provides a resource by name
+ * @graph: [in] dependency graph
+ * @name: [in] name of the resource
+ * @resource: [out] resource in case of success
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_get_resource(
+				struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name resource_name,
+				struct ipa_rm_resource **resource)
+{
+	int result;
+	int resource_index;
+	if (!graph) {
+		result = -EINVAL;
+		goto bail;
+	}
+	resource_index = ipa_rm_dep_get_index(resource_name);
+	if (resource_index == IPA_RM_INDEX_INVALID) {
+		result = -EINVAL;
+		goto bail;
+	}
+	read_lock(&graph->lock);
+	*resource = graph->resource_table[resource_index];
+	read_unlock(&graph->lock);
+	if (!*resource) {
+		result = -EINVAL;
+		goto bail;
+	}
+	result = 0;
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_dep_graph_add() - adds resource to graph
+ * @graph: [in] dependency graph
+ * @resource: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
+			 struct ipa_rm_resource *resource)
+{
+	int result = 0;
+	int resource_index;
+	if (!graph || !resource) {
+		result = -EINVAL;
+		goto bail;
+	}
+	resource_index = ipa_rm_dep_get_index(resource->name);
+	if (resource_index == IPA_RM_INDEX_INVALID) {
+		result = -EINVAL;
+		goto bail;
+	}
+	write_lock(&graph->lock);
+	graph->resource_table[resource_index] = resource;
+	write_unlock(&graph->lock);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_dep_graph_add_dependency() - adds dependency between
+ *				two nodes in graph
+ * @graph: [in] dependency graph
+ * @resource_name: [in] resource to add
+ * @depends_on_name: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
+				    enum ipa_rm_resource_name resource_name,
+				    enum ipa_rm_resource_name depends_on_name)
+{
+	struct ipa_rm_resource *dependant = NULL;
+	struct ipa_rm_resource *dependency = NULL;
+	int result;
+	if (!graph ||
+		!IPA_RM_RESORCE_IS_PROD(resource_name) ||
+		!IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(graph,
+					  resource_name,
+					  &dependant)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(graph,
+					depends_on_name,
+					  &dependency)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	result = ipa_rm_resource_add_dependency(dependant, dependency);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_dep_graph_delete_dependency() - deleted dependency between
+ *				two nodes in graph
+ * @graph: [in] dependency graph
+ * @resource_name: [in] resource to delete
+ * @depends_on_name: [in] resource to delete
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ */
+int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name resource_name,
+				enum ipa_rm_resource_name depends_on_name)
+{
+	struct ipa_rm_resource *dependant = NULL;
+	struct ipa_rm_resource *dependency = NULL;
+	int result;
+	if (!graph ||
+		!IPA_RM_RESORCE_IS_PROD(resource_name) ||
+		!IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(graph,
+					  resource_name,
+					  &dependant)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (ipa_rm_dep_graph_get_resource(graph,
+					  depends_on_name,
+					  &dependency)) {
+		result = -EINVAL;
+		goto bail;
+	}
+	result = ipa_rm_resource_delete_dependency(dependant, dependency);
+bail:
+	return result;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
new file mode 100644
index 0000000..19d9461
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPA_RM_DEPENDENCY_GRAPH_H_
+#define _IPA_RM_DEPENDENCY_GRAPH_H_
+
+#include <linux/list.h>
+#include <mach/ipa.h>
+#include "ipa_rm_resource.h"
+
+struct ipa_rm_dep_graph {
+	struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
+	rwlock_t lock;
+};
+
+int ipa_rm_dep_graph_get_resource(
+				struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name name,
+				struct ipa_rm_resource **resource);
+
+int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph);
+
+void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph);
+
+int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
+			 struct ipa_rm_resource *resource);
+
+int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name resource_name,
+				enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
+				enum ipa_rm_resource_name resource_name,
+				enum ipa_rm_resource_name depends_on_name);
+
+#endif /* _IPA_RM_DEPENDENCY_GRAPH_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
new file mode 100644
index 0000000..141a442
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPA_RM_I_H_
+#define _IPA_RM_I_H_
+
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+
+#define IPA_RM_RESOURCE_CONS_MAX \
+	(IPA_RM_RESOURCE_MAX - IPA_RM_RESOURCE_PROD_MAX)
+#define IPA_RM_RESORCE_IS_PROD(x) \
+	(x >= IPA_RM_RESOURCE_PROD && x < IPA_RM_RESOURCE_PROD_MAX)
+#define IPA_RM_RESORCE_IS_CONS(x) \
+	(x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX)
+#define IPA_RM_INDEX_INVALID	(-1)
+
+int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name);
+int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name);
+
+/**
+ * enum ipa_rm_wq_cmd - workqueue commands
+ */
+enum ipa_rm_wq_cmd {
+	IPA_RM_WQ_NOTIFY_PROD,
+	IPA_RM_WQ_NOTIFY_CONS,
+	IPA_RM_WQ_RESOURCE_CB
+};
+
+/**
+ * struct ipa_rm_wq_work_type - IPA RM worqueue specific
+ *				work type
+ * @work: work struct
+ * @wq_cmd: command that should be processed in workqueue context
+ * @resource_name: name of the resource on which this work
+ *			should be done
+ * @dep_graph: data structure to search for resource if exists
+ * @event: event to notify
+ */
+struct ipa_rm_wq_work_type {
+	struct work_struct		work;
+	enum ipa_rm_wq_cmd		wq_cmd;
+	enum ipa_rm_resource_name	resource_name;
+	enum ipa_rm_event		event;
+};
+
+int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_event event);
+
+int ipa_rm_initialize(void);
+
+void ipa_rm_exit(void);
+
+#endif /* _IPA_RM_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
new file mode 100644
index 0000000..2a3b8d3
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/unistd.h>
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+#include "ipa_i.h"
+
+/**
+ * struct ipa_rm_it_private - IPA RM Inactivity Timer private
+ *	data
+ * @initied: indicates if instance was initialized
+ * @lock - spinlock for mutual exclusion
+ * @resource_name - resource name
+ * @work: delayed work object for running delayed releas
+ *	function
+ * @release_in_prog: boolean flag indicates if release resource
+ *			is scheduled for happen in the future.
+ * @jiffies: number of jiffies for timeout
+ *
+ * WWAN private - holds all relevant info about WWAN driver
+ */
+struct ipa_rm_it_private {
+	bool initied;
+	enum ipa_rm_resource_name resource_name;
+	spinlock_t lock;
+	struct delayed_work work;
+	bool release_in_prog;
+	unsigned long jiffies;
+};
+
+static struct ipa_rm_it_private ipa_rm_it_handles[IPA_RM_RESOURCE_MAX];
+
+/**
+ * ipa_rm_inactivity_timer_func() - called when timer expired in
+ * the context of the shared workqueue. Checks internally is
+ * release_in_prog flag is set and calls to
+ * ipa_rm_release_resource(). release_in_prog is cleared when
+ * calling to ipa_rm_inactivity_timer_request_resource(). In
+ * this situation this function shall not call to
+ * ipa_rm_release_resource() since the resource needs to remain
+ * up
+ *
+ * @work: work object provided by the work queue
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_inactivity_timer_func(struct work_struct *work)
+{
+
+	struct ipa_rm_it_private *me = container_of(to_delayed_work(work),
+						    struct ipa_rm_it_private,
+						    work);
+	unsigned long flags;
+
+	IPADBG("%s: timer expired for resource %d!\n", __func__,
+	    me->resource_name);
+
+	/* check that release still need to be performed */
+	spin_lock_irqsave(
+		&ipa_rm_it_handles[me->resource_name].lock, flags);
+	if (ipa_rm_it_handles[me->resource_name].release_in_prog) {
+		IPADBG("%s: calling release_resource on resource %d!\n",
+		     __func__, me->resource_name);
+		ipa_rm_release_resource(me->resource_name);
+		ipa_rm_it_handles[me->resource_name].release_in_prog = false;
+	}
+	spin_unlock_irqrestore(
+		&ipa_rm_it_handles[me->resource_name].lock, flags);
+}
+
+/**
+* ipa_rm_inactivity_timer_init() - Init function for IPA RM
+* inactivity timer. This function shall be called prior calling
+* any other API of IPA RM inactivity timer.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+* @msecs: time in miliseccond, that IPA RM inactivity timer
+* shall wait prior calling to ipa_rm_release_resource().
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_init(enum ipa_rm_resource_name resource_name,
+				 unsigned long msecs)
+{
+	IPADBG("%s: resource %d\n", __func__, resource_name);
+
+	if (resource_name < 0 ||
+	    resource_name >= IPA_RM_RESOURCE_MAX) {
+		IPAERR("%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (ipa_rm_it_handles[resource_name].initied) {
+		IPAERR("%s: resource %d already inited\n",
+		    __func__, resource_name);
+		return -EINVAL;
+	}
+
+	spin_lock_init(&ipa_rm_it_handles[resource_name].lock);
+	ipa_rm_it_handles[resource_name].resource_name = resource_name;
+	ipa_rm_it_handles[resource_name].jiffies = msecs_to_jiffies(msecs);
+	ipa_rm_it_handles[resource_name].release_in_prog = false;
+
+	INIT_DELAYED_WORK(&ipa_rm_it_handles[resource_name].work,
+			  ipa_rm_inactivity_timer_func);
+	ipa_rm_it_handles[resource_name].initied = 1;
+
+	return 0;
+}
+
+/**
+* ipa_rm_inactivity_timer_destroy() - De-Init function for IPA
+* RM inactivity timer.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_destroy(enum ipa_rm_resource_name resource_name)
+{
+	IPADBG("%s: resource %d\n", __func__, resource_name);
+
+	if (resource_name < 0 ||
+	    resource_name >= IPA_RM_RESOURCE_MAX) {
+		IPAERR("%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ipa_rm_it_handles[resource_name].initied) {
+		IPAERR("%s: resource %d already inited\n",
+		    __func__, resource_name);
+		return -EINVAL;
+	}
+
+	memset(&ipa_rm_it_handles[resource_name], 0,
+	       sizeof(struct ipa_rm_it_private));
+
+	return 0;
+}
+
+/**
+* ipa_rm_inactivity_timer_request_resource() - Same as
+* ipa_rm_request_resource(), with a difference that calling to
+* this function will also cancel the inactivity timer, if
+* ipa_rm_inactivity_timer_release_resource() was called earlier.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_request_resource(
+				enum ipa_rm_resource_name resource_name)
+{
+	int ret;
+	unsigned long flags;
+	IPADBG("%s: resource %d\n", __func__, resource_name);
+
+	if (resource_name < 0 ||
+	    resource_name >= IPA_RM_RESOURCE_MAX) {
+		IPAERR("%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ipa_rm_it_handles[resource_name].initied) {
+		IPAERR("%s: Not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ipa_rm_it_handles[resource_name].lock, flags);
+	cancel_delayed_work(&ipa_rm_it_handles[resource_name].work);
+	ipa_rm_it_handles[resource_name].release_in_prog = false;
+	spin_unlock_irqrestore(&ipa_rm_it_handles[resource_name].lock, flags);
+	ret = ipa_rm_request_resource(resource_name);
+	IPADBG("%s: resource %d: returning %d\n", __func__, resource_name, ret);
+	return ret;
+}
+
+/**
+* ipa_rm_inactivity_timer_release_resource() - Sets the
+* inactivity timer to the timeout set by
+* ipa_rm_inactivity_timer_init(). When the timeout expires, IPA
+* RM inactivity timer will call to ipa_rm_release_resource().
+* If a call to ipa_rm_inactivity_timer_request_resource() was
+* made BEFORE the timout has expired, rge timer will be
+* cancelled.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_release_resource(
+				enum ipa_rm_resource_name resource_name)
+{
+	unsigned long flags;
+	IPADBG("%s: resource %d\n", __func__, resource_name);
+
+	if (resource_name < 0 ||
+	    resource_name >= IPA_RM_RESOURCE_MAX) {
+		IPAERR("%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ipa_rm_it_handles[resource_name].initied) {
+		IPAERR("%s: Not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ipa_rm_it_handles[resource_name].lock, flags);
+	if (ipa_rm_it_handles[resource_name].release_in_prog) {
+		IPADBG("%s: Timer already set, not scheduling again %d\n",
+		    __func__, resource_name);
+		spin_unlock_irqrestore(
+			&ipa_rm_it_handles[resource_name].lock, flags);
+		return 0;
+	}
+	ipa_rm_it_handles[resource_name].release_in_prog = true;
+	spin_unlock_irqrestore(&ipa_rm_it_handles[resource_name].lock, flags);
+
+	IPADBG("%s: setting delayed work\n", __func__);
+	schedule_delayed_work(&ipa_rm_it_handles[resource_name].work,
+			      ipa_rm_it_handles[resource_name].jiffies);
+
+	return 0;
+}
+
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
new file mode 100644
index 0000000..55f8239
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include "ipa_i.h"
+#include "ipa_rm_i.h"
+#include "ipa_rm_resource.h"
+
+/**
+ * ipa_rm_peers_list_get_resource_index() - resource name to index
+ *	of this resource in corresponding peers list
+ * @resource_name: [in] resource name
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ * in case provided resource name isn't contained in enum
+ * ipa_rm_resource_name.
+ *
+ */
+static int ipa_rm_peers_list_get_resource_index(
+		enum ipa_rm_resource_name resource_name)
+{
+	int resource_index = IPA_RM_INDEX_INVALID;
+	if (IPA_RM_RESORCE_IS_PROD(resource_name))
+		resource_index = ipa_rm_prod_index(resource_name);
+	else if (IPA_RM_RESORCE_IS_CONS(resource_name)) {
+		resource_index = ipa_rm_cons_index(resource_name);
+		if (resource_index != IPA_RM_INDEX_INVALID)
+			resource_index =
+				resource_index - IPA_RM_RESOURCE_PROD_MAX;
+	}
+
+	return resource_index;
+}
+
+static bool ipa_rm_peers_list_check_index(int index,
+		struct ipa_rm_peers_list *peers_list)
+{
+	return !(index > peers_list->max_peers || index < 0);
+}
+
+/**
+ * ipa_rm_peers_list_create() - creates the peers list
+ *
+ * @max_peers: maximum number of peers in new list
+ * @peers_list: [out] newly created peers list
+ *
+ * Returns: 0 in case of SUCCESS, negative otherwise
+ */
+int ipa_rm_peers_list_create(int max_peers,
+		struct ipa_rm_peers_list **peers_list)
+{
+	int result;
+	*peers_list = kzalloc(sizeof(**peers_list), GFP_KERNEL);
+	if (!*peers_list) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	rwlock_init(&(*peers_list)->peers_lock);
+	(*peers_list)->max_peers = max_peers;
+	(*peers_list)->peers = kzalloc((*peers_list)->max_peers *
+				sizeof(struct ipa_rm_resource *), GFP_KERNEL);
+	if (!((*peers_list)->peers)) {
+		result = -ENOMEM;
+		goto list_alloc_fail;
+	}
+	return 0;
+
+list_alloc_fail:
+	kfree(*peers_list);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_peers_list_delete() - deletes the peers list
+ *
+ * @peers_list: peers list
+ *
+ */
+void ipa_rm_peers_list_delete(struct ipa_rm_peers_list *peers_list)
+{
+	if (peers_list) {
+		kfree(peers_list->peers);
+		kfree(peers_list);
+	}
+}
+
+/**
+ * ipa_rm_peers_list_remove_peer() - removes peer from the list
+ *
+ * @peers_list: peers list
+ * @resource_name: name of the resource to remove
+ *
+ */
+void ipa_rm_peers_list_remove_peer(
+		struct ipa_rm_peers_list *peers_list,
+		enum ipa_rm_resource_name resource_name)
+{
+	if (!peers_list)
+		return;
+	write_lock(&peers_list->peers_lock);
+	peers_list->peers[ipa_rm_peers_list_get_resource_index(
+			resource_name)] = NULL;
+	peers_list->peers_count--;
+	write_unlock(&peers_list->peers_lock);
+}
+
+/**
+ * ipa_rm_peers_list_add_peer() - adds peer to the list
+ *
+ * @peers_list: peers list
+ * @resource: resource to add
+ *
+ */
+void ipa_rm_peers_list_add_peer(
+		struct ipa_rm_peers_list *peers_list,
+		struct ipa_rm_resource *resource)
+{
+	if (!peers_list || !resource)
+		return;
+	read_lock(&peers_list->peers_lock);
+	peers_list->peers[ipa_rm_peers_list_get_resource_index(
+			resource->name)] =
+			resource;
+	peers_list->peers_count++;
+	read_unlock(&peers_list->peers_lock);
+}
+
+/**
+ * ipa_rm_peers_list_is_empty() - checks
+ *	if resource peers list is empty
+ *
+ * @peers_list: peers list
+ *
+ * Returns: true if the list is empty, false otherwise
+ */
+bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list)
+{
+	bool result = true;
+	if (!peers_list)
+		goto bail;
+	read_lock(&peers_list->peers_lock);
+	if (peers_list->peers_count > 0)
+		result = false;
+	read_unlock(&peers_list->peers_lock);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_peers_list_has_last_peer() - checks
+ *	if resource peers list has exactly one peer
+ *
+ * @peers_list: peers list
+ *
+ * Returns: true if the list has exactly one peer, false otherwise
+ */
+bool ipa_rm_peers_list_has_last_peer(
+		struct ipa_rm_peers_list *peers_list)
+{
+	bool result = true;
+	if (!peers_list)
+		goto bail;
+	read_lock(&peers_list->peers_lock);
+	if (peers_list->peers_count == 1)
+		result = false;
+	read_unlock(&peers_list->peers_lock);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_peers_list_check_dependency() - check dependency
+ *	between 2 peer lists
+ * @resource_peers: first peers list
+ * @resource_name: first peers list resource name
+ * @depends_on_peers: second peers list
+ * @depends_on_name: second peers list resource name
+ *
+ * Returns: true if there is dependency, false otherwise
+ *
+ */
+bool ipa_rm_peers_list_check_dependency(
+		struct ipa_rm_peers_list *resource_peers,
+		enum ipa_rm_resource_name resource_name,
+		struct ipa_rm_peers_list *depends_on_peers,
+		enum ipa_rm_resource_name depends_on_name)
+{
+	bool result = false;
+	if (!resource_peers || !depends_on_peers)
+		return result;
+	read_lock(&resource_peers->peers_lock);
+	if (resource_peers->peers[ipa_rm_peers_list_get_resource_index(
+			depends_on_name)] != NULL)
+		result = true;
+	read_unlock(&resource_peers->peers_lock);
+
+	read_lock(&depends_on_peers->peers_lock);
+	if (depends_on_peers->peers[ipa_rm_peers_list_get_resource_index(
+						resource_name)] != NULL)
+		result = true;
+	read_unlock(&depends_on_peers->peers_lock);
+
+	return result;
+}
+
+/**
+ * ipa_rm_peers_list_get_resource() - get resource by
+ *	resource index
+ * @resource_index: resource index
+ * @resource_peers: peers list
+ *
+ * Returns: the resource if found, NULL otherwise
+ */
+struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
+		struct ipa_rm_peers_list *resource_peers)
+{
+	struct ipa_rm_resource *result = NULL;
+	if (!ipa_rm_peers_list_check_index(resource_index, resource_peers))
+		goto bail;
+	read_lock(&resource_peers->peers_lock);
+	result = resource_peers->peers[resource_index];
+	read_unlock(&resource_peers->peers_lock);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_peers_list_get_size() - get peers list sise
+ *
+ * @peers_list: peers list
+ *
+ * Returns: the size of the peers list
+ */
+int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list)
+{
+	return peers_list->max_peers;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.h b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
new file mode 100644
index 0000000..f8fd1ca
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPA_RM_PEERS_LIST_H_
+#define _IPA_RM_PEERS_LIST_H_
+
+#include "ipa_rm_resource.h"
+
+/**
+ * struct ipa_rm_peers_list - IPA RM resource peers list
+ * @peers: the list of references to resources dependent on this resource
+ *          in case of producer or list of dependencies in case of consumer
+ * @max_peers: maximum number of peers for this resource
+ * @peers_count: actual number of peers for this resource
+ * @peers_lock: RW lock for peers container
+ */
+struct ipa_rm_peers_list {
+	struct ipa_rm_resource		**peers;
+	int				max_peers;
+	int				peers_count;
+	rwlock_t			peers_lock;
+};
+
+int ipa_rm_peers_list_create(int max_peers,
+		struct ipa_rm_peers_list **peers_list);
+void ipa_rm_peers_list_delete(struct ipa_rm_peers_list *peers_list);
+void ipa_rm_peers_list_remove_peer(
+		struct ipa_rm_peers_list *peers_list,
+		enum ipa_rm_resource_name resource_name);
+void ipa_rm_peers_list_add_peer(
+		struct ipa_rm_peers_list *peers_list,
+		struct ipa_rm_resource *resource);
+bool ipa_rm_peers_list_check_dependency(
+		struct ipa_rm_peers_list *resource_peers,
+		enum ipa_rm_resource_name resource_name,
+		struct ipa_rm_peers_list *depends_on_peers,
+		enum ipa_rm_resource_name depends_on_name);
+struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
+		struct ipa_rm_peers_list *peers_list);
+int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list);
+bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list);
+bool ipa_rm_peers_list_has_last_peer(
+		struct ipa_rm_peers_list *peers_list);
+
+
+#endif /* _IPA_RM_PEERS_LIST_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
new file mode 100644
index 0000000..3ba8e84
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -0,0 +1,809 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include "ipa_i.h"
+#include "ipa_rm_resource.h"
+#include "ipa_rm_i.h"
+
+/**
+ * ipa_rm_dep_prod_index() - producer name to producer index mapping
+ * @resource_name: [in] resource name (should be of producer)
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ *	in case provided resource name isn't contained
+ *	in enum ipa_rm_resource_name or is not of producers.
+ *
+ */
+int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name)
+{
+	int result = resource_name;
+	switch (resource_name) {
+	case IPA_RM_RESOURCE_BRIDGE_PROD:
+	case IPA_RM_RESOURCE_A2_PROD:
+	case IPA_RM_RESOURCE_USB_PROD:
+	case IPA_RM_RESOURCE_HSIC_PROD:
+	case IPA_RM_RESOURCE_STD_ECM_PROD:
+	case IPA_RM_RESOURCE_WWAN_0_PROD:
+	case IPA_RM_RESOURCE_WWAN_1_PROD:
+	case IPA_RM_RESOURCE_WWAN_2_PROD:
+	case IPA_RM_RESOURCE_WWAN_3_PROD:
+	case IPA_RM_RESOURCE_WWAN_4_PROD:
+	case IPA_RM_RESOURCE_WWAN_5_PROD:
+	case IPA_RM_RESOURCE_WWAN_6_PROD:
+	case IPA_RM_RESOURCE_WWAN_7_PROD:
+	case IPA_RM_RESOURCE_WLAN_PROD:
+		break;
+	default:
+		result = IPA_RM_INDEX_INVALID;
+		break;
+	}
+	return result;
+}
+
+/**
+ * ipa_rm_cons_index() - consumer name to consumer index mapping
+ * @resource_name: [in] resource name (should be of consumer)
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ *	in case provided resource name isn't contained
+ *	in enum ipa_rm_resource_name or is not of consumers.
+ *
+ */
+int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name)
+{
+	int result = resource_name;
+	switch (resource_name) {
+	case IPA_RM_RESOURCE_A2_CONS:
+	case IPA_RM_RESOURCE_USB_CONS:
+	case IPA_RM_RESOURCE_HSIC_CONS:
+		break;
+	default:
+		result = IPA_RM_INDEX_INVALID;
+		break;
+	}
+	return result;
+}
+
+static int ipa_rm_resource_consumer_request(
+		struct ipa_rm_resource_cons *consumer)
+{
+	int result = 0;
+	int driver_result;
+	unsigned long flags;
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_request ENTER\n");
+	spin_lock_irqsave(&consumer->resource.state_lock, flags);
+	switch (consumer->resource.state) {
+	case IPA_RM_RELEASED:
+	case IPA_RM_RELEASE_IN_PROGRESS:
+	{
+		enum ipa_rm_resource_state prev_state =
+						consumer->resource.state;
+		consumer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
+		spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+		driver_result = consumer->request_resource();
+		spin_lock_irqsave(&consumer->resource.state_lock, flags);
+		if (driver_result == 0)
+			consumer->resource.state = IPA_RM_GRANTED;
+		else if (driver_result != -EINPROGRESS) {
+			consumer->resource.state = prev_state;
+			result = driver_result;
+			goto bail;
+		}
+		result = driver_result;
+		break;
+	}
+	case IPA_RM_GRANTED:
+		break;
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		result = -EINPROGRESS;
+		break;
+	default:
+		result = -EPERM;
+		goto bail;
+	}
+	consumer->usage_count++;
+bail:
+	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
+	return result;
+}
+
+static int ipa_rm_resource_consumer_release(
+		struct ipa_rm_resource_cons *consumer)
+{
+	int result = 0;
+	int driver_result;
+	unsigned long flags;
+	enum ipa_rm_resource_state save_state;
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_release ENTER\n");
+	spin_lock_irqsave(&consumer->resource.state_lock, flags);
+	switch (consumer->resource.state) {
+	case IPA_RM_RELEASED:
+		break;
+	case IPA_RM_GRANTED:
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		if (consumer->usage_count > 0)
+			consumer->usage_count--;
+		if (consumer->usage_count == 0) {
+			save_state = consumer->resource.state;
+			consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
+			spin_unlock_irqrestore(&consumer->resource.state_lock,
+					flags);
+			driver_result = consumer->release_resource();
+			spin_lock_irqsave(&consumer->resource.state_lock,
+					flags);
+			if (driver_result == 0)
+				consumer->resource.state = IPA_RM_RELEASED;
+			else if (driver_result != -EINPROGRESS)
+				consumer->resource.state = save_state;
+			result = driver_result;
+		}
+		break;
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		if (consumer->usage_count > 0)
+			consumer->usage_count--;
+		result = -EINPROGRESS;
+		break;
+	default:
+		result = -EPERM;
+		goto bail;
+	}
+bail:
+	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+	IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
+	return result;
+}
+
+/**
+ * ipa_rm_resource_producer_notify_clients() - notify
+ *	all registered clients of given producer
+ * @producer: producer
+ * @event: event to notify
+ */
+void ipa_rm_resource_producer_notify_clients(
+				struct ipa_rm_resource_prod *producer,
+				enum ipa_rm_event event)
+{
+	struct ipa_rm_notification_info *reg_info, *reg_info_cloned;
+	struct list_head *pos, *q;
+	LIST_HEAD(cloned_list);
+	read_lock(&producer->event_listeners_lock);
+	list_for_each(pos, &(producer->event_listeners)) {
+		reg_info = list_entry(pos,
+					struct ipa_rm_notification_info,
+					link);
+		reg_info_cloned = kzalloc(sizeof(*reg_info_cloned), GFP_ATOMIC);
+		if (!reg_info_cloned)
+			goto clone_list_failed;
+		reg_info_cloned->reg_params.notify_cb =
+				reg_info->reg_params.notify_cb;
+		reg_info_cloned->reg_params.user_data =
+				reg_info->reg_params.user_data;
+		list_add(&reg_info_cloned->link, &cloned_list);
+	}
+	read_unlock(&producer->event_listeners_lock);
+	list_for_each_safe(pos, q, &cloned_list) {
+		reg_info = list_entry(pos,
+					struct ipa_rm_notification_info,
+					link);
+		reg_info->reg_params.notify_cb(
+				reg_info->reg_params.user_data,
+				event,
+				0);
+		list_del(pos);
+		kfree(reg_info);
+	}
+	return;
+clone_list_failed:
+	read_unlock(&producer->event_listeners_lock);
+}
+
+static int ipa_rm_resource_producer_create(struct ipa_rm_resource **resource,
+		struct ipa_rm_resource_prod **producer,
+		struct ipa_rm_create_params *create_params,
+		int *max_peers)
+{
+	int result = 0;
+	*producer = kzalloc(sizeof(**producer), GFP_KERNEL);
+	if (*producer == NULL) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	rwlock_init(&(*producer)->event_listeners_lock);
+	INIT_LIST_HEAD(&((*producer)->event_listeners));
+	result = ipa_rm_resource_producer_register(*producer,
+			&(create_params->reg_params));
+	if (result)
+		goto register_fail;
+	(*resource) = (struct ipa_rm_resource *) (*producer);
+	(*resource)->type = IPA_RM_PRODUCER;
+	*max_peers = IPA_RM_RESOURCE_CONS_MAX;
+	goto bail;
+register_fail:
+	kfree(*producer);
+bail:
+	return result;
+}
+
+static void ipa_rm_resource_producer_delete(
+				struct ipa_rm_resource_prod *producer)
+{
+	struct ipa_rm_notification_info *reg_info;
+	struct list_head *pos, *q;
+	write_lock(&producer->event_listeners_lock);
+	list_for_each_safe(pos, q, &(producer->event_listeners)) {
+		reg_info = list_entry(pos,
+				struct ipa_rm_notification_info,
+				link);
+		list_del(pos);
+		kfree(reg_info);
+	}
+	write_unlock(&producer->event_listeners_lock);
+}
+
+static int ipa_rm_resource_consumer_create(struct ipa_rm_resource **resource,
+		struct ipa_rm_resource_cons **consumer,
+		struct ipa_rm_create_params *create_params,
+		int *max_peers)
+{
+	int result = 0;
+	*consumer = kzalloc(sizeof(**consumer), GFP_KERNEL);
+	if (*consumer == NULL) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	(*consumer)->request_resource = create_params->request_resource;
+	(*consumer)->release_resource = create_params->release_resource;
+	(*resource) = (struct ipa_rm_resource *) (*consumer);
+	(*resource)->type = IPA_RM_CONSUMER;
+	*max_peers = IPA_RM_RESOURCE_PROD_MAX;
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_resource_create() - creates resource
+ * @create_params: [in] parameters needed
+ *			for resource initialization with IPA RM
+ * @resource: [out] created resource
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_create(
+		struct ipa_rm_create_params *create_params,
+		struct ipa_rm_resource **resource)
+{
+	struct ipa_rm_resource_cons *consumer;
+	struct ipa_rm_resource_prod *producer;
+	int max_peers;
+	int result = 0;
+
+	if (!create_params) {
+		result = -EINVAL;
+		goto bail;
+	}
+	if (IPA_RM_RESORCE_IS_PROD(create_params->name)) {
+		result = ipa_rm_resource_producer_create(resource,
+				&producer,
+				create_params,
+				&max_peers);
+		if (result)
+			goto bail;
+	} else if (IPA_RM_RESORCE_IS_CONS(create_params->name)) {
+		result = ipa_rm_resource_consumer_create(resource,
+				&consumer,
+				create_params,
+				&max_peers);
+		if (result)
+			goto bail;
+	} else {
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_peers_list_create(max_peers,
+			&((*resource)->peers_list));
+	if (result)
+		goto peers_alloc_fail;
+	(*resource)->name = create_params->name;
+	(*resource)->state = IPA_RM_RELEASED;
+	spin_lock_init(&((*resource)->state_lock));
+	goto bail;
+peers_alloc_fail:
+	ipa_rm_resource_delete(*resource);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_resource_delete() - deletes resource
+ * @resource: [in] resource
+ *			for resource initialization with IPA RM
+ */
+void ipa_rm_resource_delete(struct ipa_rm_resource *resource)
+{
+	if (!resource)
+		return;
+	if (resource->peers_list)
+		ipa_rm_peers_list_delete(resource->peers_list);
+	if (resource->type == IPA_RM_PRODUCER) {
+		ipa_rm_resource_producer_delete(
+				(struct ipa_rm_resource_prod *) resource);
+		kfree((struct ipa_rm_resource_prod *) resource);
+	} else
+		kfree((struct ipa_rm_resource_cons *) resource);
+}
+
+/**
+ * ipa_rm_resource_register() - register resource
+ * @resource: [in] resource
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Producer resource is expected for this call.
+ *
+ */
+int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
+		struct ipa_rm_register_params *reg_params)
+{
+	int result = 0;
+	struct ipa_rm_notification_info *reg_info;
+	struct list_head *pos;
+	if (!producer || !reg_params) {
+		result = -EPERM;
+		goto bail;
+	}
+	read_lock(&producer->event_listeners_lock);
+	list_for_each(pos, &(producer->event_listeners)) {
+		reg_info = list_entry(pos,
+					struct ipa_rm_notification_info,
+					link);
+		if (reg_info->reg_params.notify_cb ==
+						reg_params->notify_cb) {
+			result = -EPERM;
+			read_unlock(&producer->event_listeners_lock);
+			goto bail;
+		}
+
+	}
+	read_unlock(&producer->event_listeners_lock);
+	reg_info = kzalloc(sizeof(*reg_info), GFP_KERNEL);
+	if (reg_info == NULL) {
+		result = -ENOMEM;
+		goto bail;
+	}
+	reg_info->reg_params.user_data = reg_params->user_data;
+	reg_info->reg_params.notify_cb = reg_params->notify_cb;
+	INIT_LIST_HEAD(&reg_info->link);
+	write_lock(&producer->event_listeners_lock);
+	list_add(&reg_info->link, &producer->event_listeners);
+	write_unlock(&producer->event_listeners_lock);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_resource_deregister() - register resource
+ * @resource: [in] resource
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Producer resource is expected for this call.
+ * This function deleted only single instance of
+ * registration info.
+ *
+ */
+int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
+		struct ipa_rm_register_params *reg_params)
+{
+	int result = -EINVAL;
+	struct ipa_rm_notification_info *reg_info;
+	struct list_head *pos, *q;
+	if (!producer || !reg_params)
+		return -EINVAL;
+	write_lock(&producer->event_listeners_lock);
+	list_for_each_safe(pos, q, &(producer->event_listeners)) {
+		reg_info = list_entry(pos,
+				struct ipa_rm_notification_info,
+				link);
+		if (reg_info->reg_params.notify_cb ==
+						reg_params->notify_cb) {
+			list_del(pos);
+			kfree(reg_info);
+			result = 0;
+			goto bail;
+		}
+
+	}
+bail:
+	write_unlock(&producer->event_listeners_lock);
+	return result;
+}
+
+/**
+ * ipa_rm_resource_add_dependency() - add dependency between two
+ *				given resources
+ * @resource: [in] resource resource
+ * @depends_on: [in] depends_on resource
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
+				   struct ipa_rm_resource *depends_on)
+{
+	int result = 0;
+	unsigned long flags;
+	int consumer_result;
+	if (!resource || !depends_on)
+		return -EINVAL;
+	if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+			resource->name,
+			depends_on->peers_list,
+			depends_on->name))
+		return -EINVAL;
+	ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
+	ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
+	spin_lock_irqsave(&resource->state_lock, flags);
+	switch (resource->state) {
+	case IPA_RM_RELEASED:
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		break;
+	case IPA_RM_GRANTED:
+	case IPA_RM_REQUEST_IN_PROGRESS:
+	{
+		enum ipa_rm_resource_state prev_state = resource->state;
+		resource->state = IPA_RM_REQUEST_IN_PROGRESS;
+		((struct ipa_rm_resource_prod *)
+					resource)->pending_request++;
+		spin_unlock_irqrestore(&resource->state_lock, flags);
+		consumer_result = ipa_rm_resource_consumer_request(
+				(struct ipa_rm_resource_cons *)depends_on);
+		spin_lock_irqsave(&resource->state_lock, flags);
+		if (consumer_result != -EINPROGRESS)
+			resource->state = prev_state;
+			((struct ipa_rm_resource_prod *)
+					resource)->pending_request--;
+		result = consumer_result;
+		break;
+	}
+	default:
+		result = -EPERM;
+		goto bail;
+	}
+bail:
+	spin_unlock_irqrestore(&resource->state_lock, flags);
+	IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
+			resource->name, resource->peers_list->peers_count);
+	IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
+			depends_on->name, depends_on->peers_list->peers_count);
+	return result;
+}
+
+/**
+ * ipa_rm_resource_delete_dependency() - add dependency between two
+ *				given resources
+ * @resource: [in] resource resource
+ * @depends_on: [in] depends_on resource
+ *
+ * Returns: 0 on success, negative on failure
+ * EINPROGRESS is returned in case this is the last dependency
+ * of given resource and IPA RM client should receive the RELEASED cb
+ */
+int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
+				   struct ipa_rm_resource *depends_on)
+{
+	int result = 0;
+	unsigned long flags;
+	if (!resource || !depends_on)
+		return -EINVAL;
+	if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+			resource->name,
+			depends_on->peers_list,
+			depends_on->name))
+		return -EINVAL;
+	spin_lock_irqsave(&resource->state_lock, flags);
+	switch (resource->state) {
+	case IPA_RM_RELEASED:
+	case IPA_RM_GRANTED:
+		break;
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		if (((struct ipa_rm_resource_prod *)
+				resource)->pending_release > 0)
+			((struct ipa_rm_resource_prod *)
+					resource)->pending_release--;
+		break;
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		if (((struct ipa_rm_resource_prod *)
+				resource)->pending_request > 0)
+			((struct ipa_rm_resource_prod *)
+					resource)->pending_request--;
+		break;
+	default:
+		result = -EINVAL;
+		spin_unlock_irqrestore(&resource->state_lock, flags);
+		goto bail;
+	}
+	spin_unlock_irqrestore(&resource->state_lock, flags);
+	(void) ipa_rm_resource_consumer_release(
+			(struct ipa_rm_resource_cons *)depends_on);
+	if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
+		(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
+				resource->name,
+				IPA_RM_RESOURCE_RELEASED);
+		result = -EINPROGRESS;
+	}
+	ipa_rm_peers_list_remove_peer(resource->peers_list,
+			depends_on->name);
+	ipa_rm_peers_list_remove_peer(depends_on->peers_list,
+			resource->name);
+bail:
+	return result;
+}
+
+/**
+ * ipa_rm_resource_producer_request() - producer resource request
+ * @producer: [in] producer
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer)
+{
+	int peers_index;
+	int result = 0;
+	unsigned long flags;
+	struct ipa_rm_resource *consumer;
+	int consumer_result;
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
+			producer->resource.name);
+	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
+		spin_lock_irqsave(&producer->resource.state_lock, flags);
+		producer->resource.state = IPA_RM_GRANTED;
+		spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+		return 0;
+	}
+	spin_lock_irqsave(&producer->resource.state_lock, flags);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request state [%d]\n",
+			producer->resource.state);
+	switch (producer->resource.state) {
+	case IPA_RM_RELEASED:
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		producer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
+		break;
+	case IPA_RM_GRANTED:
+		goto unlock_and_bail;
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		result = -EINPROGRESS;
+		goto unlock_and_bail;
+	default:
+		result = -EINVAL;
+		goto unlock_and_bail;
+	}
+	producer->pending_request = 0;
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+	for (peers_index = 0;
+		peers_index < ipa_rm_peers_list_get_size(
+				producer->resource.peers_list);
+		peers_index++) {
+		consumer = ipa_rm_peers_list_get_resource(peers_index,
+				producer->resource.peers_list);
+		if (consumer) {
+			spin_lock_irqsave(
+				&producer->resource.state_lock, flags);
+			producer->pending_request++;
+			spin_unlock_irqrestore(
+				&producer->resource.state_lock, flags);
+			consumer_result = ipa_rm_resource_consumer_request(
+				(struct ipa_rm_resource_cons *)consumer);
+			if (consumer_result == -EINPROGRESS) {
+				result = -EINPROGRESS;
+			} else {
+				spin_lock_irqsave(
+					&producer->resource.state_lock, flags);
+				producer->pending_request--;
+				spin_unlock_irqrestore(
+					&producer->resource.state_lock, flags);
+				if (consumer_result != 0) {
+					result = consumer_result;
+					goto bail;
+				}
+			}
+		}
+	}
+	spin_lock_irqsave(&producer->resource.state_lock, flags);
+	if (producer->pending_request == 0)
+		producer->resource.state = IPA_RM_GRANTED;
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+	return result;
+unlock_and_bail:
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+bail:
+	IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
+	return result;
+}
+
+/**
+ * ipa_rm_resource_producer_release() - producer resource release
+ * producer: [in] producer resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ */
+int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer)
+{
+	int peers_index;
+	int result = 0;
+	unsigned long flags;
+	struct ipa_rm_resource *consumer;
+	int consumer_result;
+	IPADBG("IPA RM ::ipa_rm_resource_producer_release ENTER\n");
+	if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
+		spin_lock_irqsave(&producer->resource.state_lock, flags);
+		producer->resource.state = IPA_RM_RELEASED;
+		spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+		return 0;
+	}
+	spin_lock_irqsave(&producer->resource.state_lock, flags);
+	switch (producer->resource.state) {
+	case IPA_RM_RELEASED:
+		goto bail;
+	case IPA_RM_GRANTED:
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		producer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
+		break;
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		result = -EINPROGRESS;
+		goto bail;
+	default:
+		result = -EPERM;
+		goto bail;
+	}
+	producer->pending_release = 0;
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+	for (peers_index = 0;
+		peers_index < ipa_rm_peers_list_get_size(
+				producer->resource.peers_list);
+		peers_index++) {
+		consumer = ipa_rm_peers_list_get_resource(peers_index,
+				producer->resource.peers_list);
+		if (consumer) {
+			spin_lock_irqsave(
+				&producer->resource.state_lock, flags);
+			producer->pending_release++;
+			spin_unlock_irqrestore(
+				&producer->resource.state_lock, flags);
+			consumer_result = ipa_rm_resource_consumer_release(
+				(struct ipa_rm_resource_cons *)consumer);
+			if (consumer_result == -EINPROGRESS) {
+				result = -EINPROGRESS;
+			} else {
+				spin_lock_irqsave(
+					&producer->resource.state_lock, flags);
+				producer->pending_release--;
+				spin_unlock_irqrestore(
+					&producer->resource.state_lock, flags);
+			}
+		}
+	}
+	spin_lock_irqsave(&producer->resource.state_lock, flags);
+	if (producer->pending_release == 0)
+		producer->resource.state = IPA_RM_RELEASED;
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+	return result;
+bail:
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+	IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
+	return result;
+}
+
+static void ipa_rm_resource_producer_handle_cb(
+		struct ipa_rm_resource_prod *producer,
+		enum ipa_rm_event event)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&producer->resource.state_lock, flags);
+	switch (producer->resource.state) {
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		if (event != IPA_RM_RESOURCE_GRANTED)
+			goto unlock_and_bail;
+		if (producer->pending_request > 0) {
+			producer->pending_request--;
+			if (producer->pending_request == 0) {
+				producer->resource.state =
+						IPA_RM_GRANTED;
+				spin_unlock_irqrestore(
+					&producer->resource.state_lock, flags);
+				ipa_rm_resource_producer_notify_clients(
+						producer,
+						IPA_RM_RESOURCE_GRANTED);
+				goto bail;
+			}
+		}
+		break;
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		if (event != IPA_RM_RESOURCE_RELEASED)
+			goto unlock_and_bail;
+		if (producer->pending_release > 0) {
+			producer->pending_release--;
+			if (producer->pending_release == 0) {
+				producer->resource.state =
+						IPA_RM_RELEASED;
+				spin_unlock_irqrestore(
+					&producer->resource.state_lock, flags);
+				ipa_rm_resource_producer_notify_clients(
+						producer,
+						IPA_RM_RESOURCE_RELEASED);
+				goto bail;
+			}
+		}
+		break;
+	case IPA_RM_GRANTED:
+	case IPA_RM_RELEASED:
+	default:
+		goto unlock_and_bail;
+	}
+unlock_and_bail:
+	spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+bail:
+	return;
+}
+
+/**
+ * ipa_rm_resource_consumer_handle_cb() - propagates resource
+ *	notification to all dependent producers
+ * @consumer: [in] notifying resource
+ *
+ */
+void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
+				enum ipa_rm_event event)
+{
+	int peers_index;
+	struct ipa_rm_resource *producer;
+	unsigned long flags;
+	if (!consumer)
+		return;
+	spin_lock_irqsave(&consumer->resource.state_lock, flags);
+	switch (consumer->resource.state) {
+	case IPA_RM_REQUEST_IN_PROGRESS:
+		if (event == IPA_RM_RESOURCE_RELEASED)
+			goto bail;
+		consumer->resource.state = IPA_RM_GRANTED;
+		break;
+	case IPA_RM_RELEASE_IN_PROGRESS:
+		if (event == IPA_RM_RESOURCE_GRANTED)
+			goto bail;
+		consumer->resource.state = IPA_RM_RELEASED;
+		break;
+	case IPA_RM_GRANTED:
+	case IPA_RM_RELEASED:
+	default:
+		goto bail;
+	}
+	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+	for (peers_index = 0;
+		peers_index < ipa_rm_peers_list_get_size(
+				consumer->resource.peers_list);
+		peers_index++) {
+		producer = ipa_rm_peers_list_get_resource(peers_index,
+				consumer->resource.peers_list);
+		if (producer)
+			ipa_rm_resource_producer_handle_cb(
+					(struct ipa_rm_resource_prod *)
+						producer,
+						event);
+	}
+	return;
+bail:
+	spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+	return;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
new file mode 100644
index 0000000..b9c2e91
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPA_RM_RESOURCE_H_
+#define _IPA_RM_RESOURCE_H_
+
+#include <linux/list.h>
+#include <mach/ipa.h>
+#include "ipa_rm_peers_list.h"
+
+/**
+ * enum ipa_rm_resource_state - resource state
+ */
+enum ipa_rm_resource_state {
+	IPA_RM_RELEASED,
+	IPA_RM_REQUEST_IN_PROGRESS,
+	IPA_RM_GRANTED,
+	IPA_RM_RELEASE_IN_PROGRESS
+};
+
+/**
+ * enum ipa_rm_resource_type - IPA resource manager resource type
+ */
+enum ipa_rm_resource_type {
+	IPA_RM_PRODUCER,
+	IPA_RM_CONSUMER
+};
+
+/**
+ * struct ipa_rm_notification_info - notification information
+ *				of IPA RM client
+ * @reg_params: registration parameters
+ * @link: link to the list of all registered clients information
+ */
+struct ipa_rm_notification_info {
+	struct ipa_rm_register_params	reg_params;
+	struct list_head		link;
+};
+
+/**
+ * struct ipa_rm_resource - IPA RM resource
+ * @name: name identifying resource
+ * @state: state of the resource
+ * @state_lock: lock for all resource state related variables
+ * @peers_list: list of the peers of the resource
+ */
+struct ipa_rm_resource {
+	enum ipa_rm_resource_name	name;
+	enum ipa_rm_resource_type	type;
+	enum ipa_rm_resource_state	state;
+	spinlock_t			state_lock;
+	struct ipa_rm_peers_list	*peers_list;
+};
+
+/**
+ * struct ipa_rm_resource_cons - IPA RM consumer
+ * @resource: resource
+ * @usage_count: number of producers in GRANTED / REQUESTED state
+ *		using this consumer
+ * @request_resource: function which should be called to request resource
+ *			from resource manager
+ * @release_resource: function which should be called to release resource
+ *			from resource manager
+ * Add new fields after @resource only.
+ */
+struct ipa_rm_resource_cons {
+	struct ipa_rm_resource resource;
+	int usage_count;
+	int (*request_resource)(void);
+	int (*release_resource)(void);
+};
+
+/**
+ * struct ipa_rm_resource_prod - IPA RM producer
+ * @resource: resource
+ * @event_listeners: clients registered with this producer
+ *		for notifications in resource state
+ * @event_listeners_lock: RW lock protecting the event listeners list
+ * Add new fields after @resource only.
+ */
+struct ipa_rm_resource_prod {
+	struct ipa_rm_resource	resource;
+	struct list_head	event_listeners;
+	rwlock_t		event_listeners_lock;
+	int			pending_request;
+	int			pending_release;
+};
+
+int ipa_rm_resource_create(
+		struct ipa_rm_create_params *create_params,
+		struct ipa_rm_resource **resource);
+
+void ipa_rm_resource_delete(struct ipa_rm_resource *resource);
+
+int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
+				struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
+				struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
+				   struct ipa_rm_resource *depends_on);
+
+int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
+				      struct ipa_rm_resource *depends_on);
+
+int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer);
+
+int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer);
+
+void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
+				enum ipa_rm_event event);
+
+void ipa_rm_resource_producer_notify_clients(
+				struct ipa_rm_resource_prod *producer,
+				enum ipa_rm_event event);
+
+#endif /* _IPA_RM_RESOURCE_H_ */
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
new file mode 100644
index 0000000..c57bb91
--- /dev/null
+++ b/drivers/platform/msm/ssm.c
@@ -0,0 +1,931 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/*
+ * Qualcomm Secure Service Module(SSM) driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <linux/platform_device.h>
+#include <linux/msm_ion.h>
+#include <linux/platform_data/qcom_ssm.h>
+#include <mach/scm.h>
+#include <mach/msm_smd.h>
+
+#include "ssm.h"
+
+/* Macros */
+#define SSM_DEV_NAME			"ssm"
+#define MPSS_SUBSYS			0
+#define SSM_INFO_CMD_ID			1
+#define QSEOS_CHECK_VERSION_CMD		0x00001803
+
+#define MAX_APP_NAME_SIZE		32
+#define SSM_MSG_LEN			(104  + 4) /* bytes + pad */
+#define SSM_MSG_FIELD_LEN		11
+#define SSM_HEADER_LEN			(SSM_MSG_FIELD_LEN * 4)
+#define ATOM_MSG_LEN			(SSM_HEADER_LEN + SSM_MSG_LEN)
+#define FIRMWARE_NAME			"ssmapp"
+#define TZAPP_NAME			"SsmApp"
+#define CHANNEL_NAME			"SSM_RTR"
+
+#define ALIGN_BUFFER(size)		((size + 4095) & ~4095)
+
+/* SSM driver structure.*/
+struct ssm_driver {
+	int32_t app_id;
+	int32_t app_status;
+	int32_t update_status;
+	int32_t atom_replay;
+	int32_t mtoa_replay;
+	uint32_t buff_len;
+	unsigned char *channel_name;
+	unsigned char *smd_buffer;
+	struct ion_client *ssm_ion_client;
+	struct ion_handle *ssm_ion_handle;
+	struct tzapp_get_mode_info_rsp *resp;
+	struct device *dev;
+	smd_channel_t *ch;
+	ion_phys_addr_t buff_phys;
+	ion_virt_addr_t buff_virt;
+	dev_t ssm_device_no;
+	struct work_struct ipc_work;
+	struct mutex mutex;
+	bool key_status;
+	bool ready;
+};
+
+static struct ssm_driver *ssm_drv;
+
+static unsigned int getint(char *buff, unsigned long *res)
+{
+	char value[SSM_MSG_FIELD_LEN];
+
+	memcpy(value, buff, SSM_MSG_FIELD_LEN);
+	value[SSM_MSG_FIELD_LEN - 1] = '\0';
+
+	return kstrtoul(skip_spaces(value), 10, res);
+}
+
+/*
+ * Send packet to modem over SMD channel.
+ */
+static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm,
+		int length, char *data)
+{
+	unsigned int packet_len = SSM_HEADER_LEN + length + 1;
+	int rc = 0;
+
+	ssm->atom_replay += 1;
+	snprintf(ssm->smd_buffer, SSM_HEADER_LEN + 1, "%10u|%10u|%10u|%10u|"
+			, packet_len, ssm->atom_replay, ipc_req, length);
+	memcpy(ssm->smd_buffer + SSM_HEADER_LEN, data, length);
+
+	ssm->smd_buffer[packet_len - 1] = '|';
+
+	if (smd_write_avail(ssm->ch) < packet_len) {
+		dev_err(ssm->dev, "Not enough space dropping request\n");
+		rc = -ENOSPC;
+	}
+
+	rc = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
+	if (rc < packet_len) {
+		dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req);
+		rc = -EIO;
+	}
+
+	return rc;
+}
+
+/*
+ * Header Format
+ * Each member of header is of 10 byte (ASCII).
+ * Each entry is separated by '|' delimiter.
+ * |<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|
+ * |-----------------------------------------------------------------
+ * | length     | replay no. | request    | msg_len    | message    |
+ * |-----------------------------------------------------------------
+ *
+ */
+static int  decode_header(char *buffer, int length,
+		struct ssm_common_msg *pkt)
+{
+	int rc;
+
+	rc =  getint(buffer, &pkt->pktlen);
+	if (rc < 0)
+		return -EINVAL;
+
+	buffer += SSM_MSG_FIELD_LEN;
+	rc =  getint(buffer, &pkt->replaynum);
+	if (rc < 0)
+		return -EINVAL;
+
+	buffer += SSM_MSG_FIELD_LEN;
+	rc =  getint(buffer, (unsigned long *)&pkt->ipc_req);
+	if (rc < 0)
+		return -EINVAL;
+
+	buffer += SSM_MSG_FIELD_LEN;
+	rc =  getint(buffer, &pkt->msg_len);
+	if ((rc < 0) || (pkt->msg_len > SSM_MSG_LEN))
+		return -EINVAL;
+
+	pkt->msg = buffer + SSM_MSG_FIELD_LEN;
+
+	dev_dbg(ssm_drv->dev, "len %lu rep %lu req %d msg_len %lu\n",
+			pkt->pktlen, pkt->replaynum, pkt->ipc_req,
+			pkt->msg_len);
+	return 0;
+}
+
+/*
+ * Decode address for storing the decryption key.
+ * Only for Key Exchange
+ * Message Format
+ * |Length@Address|
+ */
+static int decode_message(char *msg, unsigned int len, unsigned long *length,
+		unsigned long *address)
+{
+	int i = 0, rc = 0;
+	char *buff;
+
+	buff = kzalloc(len, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+	while (i < len) {
+		if (msg[i] == '@')
+			break;
+		i++;
+	}
+	if ((i < len) && (msg[i] == '@')) {
+		memcpy(buff, msg, i);
+		buff[i] = '\0';
+		rc = kstrtoul(skip_spaces(buff), 10, length);
+		if (rc || (length <= 0)) {
+			rc = -EINVAL;
+			goto exit;
+		}
+		memcpy(buff, &msg[i + 1], len - (i + 1));
+		buff[len - i] = '\0';
+		rc = kstrtoul(skip_spaces(buff), 10, address);
+	} else
+		rc = -EINVAL;
+
+exit:
+	kfree(buff);
+	return rc;
+}
+
+static void process_message(int cmd, char *msg, int len,
+		struct ssm_driver *ssm)
+{
+	int rc;
+	unsigned long key_len = 0, key_add = 0, val;
+	struct ssm_keyexchg_req req;
+
+	switch (cmd) {
+	case SSM_MTOA_KEY_EXCHANGE:
+		if (len < 3) {
+			dev_err(ssm->dev, "Invalid message\n");
+			break;
+		}
+
+		if (ssm->key_status) {
+			dev_err(ssm->dev, "Key exchange already done\n");
+			break;
+		}
+
+		rc = decode_message(msg, len, &key_len, &key_add);
+		if (rc) {
+			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+					1, "1");
+			break;
+		}
+
+		/*
+		 * We are doing key-exchange part here as it is very
+		 * specific for this case. For all other tz
+		 * communication we have generic function.
+		 */
+		req.ssid = MPSS_SUBSYS;
+		req.address = (void *)key_add;
+		req.length = key_len;
+		req.status = (uint32_t *)ssm->buff_phys;
+
+		*(unsigned int *)ssm->buff_virt = -1;
+		rc = scm_call(KEY_EXCHANGE, 0x1, &req,
+				sizeof(struct ssm_keyexchg_req), NULL, 0);
+		if (rc) {
+			dev_err(ssm->dev, "Call for key exchg failed %d", rc);
+			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+								1, "1");
+		} else {
+			/* Success encode packet and update modem */
+			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+					1, "0");
+			ssm->key_status = true;
+		}
+		break;
+
+	case SSM_MTOA_MODE_UPDATE_STATUS:
+		msg[len] = '\0';
+		rc = kstrtoul(skip_spaces(msg), 10, &val);
+		if (val) {
+			dev_err(ssm->dev, "Modem mode update failed\n");
+			ssm->update_status = FAILED;
+		} else
+			ssm->update_status = SUCCESS;
+
+		dev_dbg(ssm->dev, "Modem mode update status %lu\n", val);
+		break;
+
+	default:
+		dev_dbg(ssm->dev, "Invalid message\n");
+		break;
+	};
+}
+
+/*
+ * Work function to handle and process packets coming from modem.
+ */
+static void ssm_app_modem_work_fn(struct work_struct *work)
+{
+	int sz, rc;
+	struct ssm_common_msg pkt;
+	struct ssm_driver *ssm;
+
+	ssm = container_of(work, struct ssm_driver, ipc_work);
+
+	mutex_lock(&ssm->mutex);
+	sz = smd_cur_packet_size(ssm->ch);
+	if ((sz <= 0) || (sz > ATOM_MSG_LEN)) {
+		dev_dbg(ssm_drv->dev, "Garbled message size\n");
+		goto unlock;
+	}
+
+	if (smd_read_avail(ssm->ch) < sz) {
+		dev_err(ssm_drv->dev, "SMD error data in channel\n");
+		goto unlock;
+	}
+
+	if (sz < SSM_HEADER_LEN) {
+		dev_err(ssm_drv->dev, "Invalid packet\n");
+		goto unlock;
+	}
+
+	if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) {
+		dev_err(ssm_drv->dev, "Incomplete data\n");
+		goto unlock;
+	}
+
+	rc = decode_header(ssm->smd_buffer, sz, &pkt);
+	if (rc < 0) {
+		dev_err(ssm_drv->dev, "Corrupted header\n");
+		goto unlock;
+	}
+
+	/* Check validity of message */
+	if (ssm->mtoa_replay >= (int)pkt.replaynum) {
+		dev_err(ssm_drv->dev, "Replay attack...\n");
+		goto unlock;
+	}
+
+	if (pkt.msg[pkt.msg_len] != '|') {
+		dev_err(ssm_drv->dev, "Garbled message\n");
+		goto unlock;
+	}
+
+	ssm->mtoa_replay = pkt.replaynum;
+	process_message(pkt.ipc_req, pkt.msg, pkt.msg_len, ssm);
+
+unlock:
+	mutex_unlock(&ssm->mutex);
+}
+
+/*
+ * MODEM-APPS smd channel callback function.
+ */
+static void modem_request(void *ctxt, unsigned event)
+{
+	struct ssm_driver *ssm;
+
+	ssm = (struct ssm_driver *)ctxt;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+	case SMD_EVENT_CLOSE:
+		dev_info(ssm->dev, "Port %s\n",
+			(event == SMD_EVENT_OPEN) ? "opened" : "closed");
+		break;
+	case SMD_EVENT_DATA:
+		if (smd_read_avail(ssm->ch) > 0)
+			schedule_work(&ssm->ipc_work);
+		break;
+	};
+}
+
+/*
+ * Communication interface between ssm driver and TZ.
+ */
+static int tz_scm_call(struct ssm_driver *ssm, void *tz_req, int tz_req_len,
+			void **tz_resp, int tz_resp_len)
+{
+	int rc;
+	struct common_req req;
+	struct common_resp resp;
+
+	memcpy((void *)ssm->buff_virt, tz_req, tz_req_len);
+
+	req.cmd_id = CLIENT_SEND_DATA_COMMAND;
+	req.app_id = ssm->app_id;
+	req.req_ptr = (void *)ssm->buff_phys;
+	req.req_len = tz_req_len;
+	req.resp_ptr = (void *)(ssm->buff_phys + tz_req_len);
+	req.resp_len = tz_resp_len;
+
+	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &req,
+			sizeof(req), (void *)&resp, sizeof(resp));
+	if (rc) {
+		dev_err(ssm->dev, "SCM call failed for data command\n");
+		return rc;
+	}
+
+	if (resp.result != RESULT_SUCCESS) {
+		dev_err(ssm->dev, "Data command response failure %d\n",
+				resp.result);
+		return -EINVAL;
+	}
+
+	*tz_resp = (void *)(ssm->buff_virt + tz_req_len);
+
+	return rc;
+}
+
+/*
+ * Load SSM application in TZ and start application:
+ * 1. Check if SSM application is already loaded.
+ * 2. Load SSM application firmware.
+ * 3. Start SSM application in TZ.
+ */
+static int ssm_load_app(struct ssm_driver *ssm)
+{
+	unsigned char name[MAX_APP_NAME_SIZE], *pos;
+	int rc, i, fw_count;
+	uint32_t buff_len, size = 0, ion_len;
+	struct check_app_req app_req;
+	struct scm_resp app_resp;
+	struct load_app app_img_info;
+	const struct firmware **fw, *fw_mdt;
+	const struct elf32_hdr *ehdr;
+	const struct elf32_phdr *phdr;
+	struct ion_handle *ion_handle;
+	ion_phys_addr_t buff_phys;
+	ion_virt_addr_t buff_virt;
+
+	/* Check if TZ app already loaded */
+	app_req.cmd_id = APP_LOOKUP_COMMAND;
+	memcpy(app_req.app_name, TZAPP_NAME, MAX_APP_NAME_SIZE);
+
+	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_req,
+				sizeof(struct check_app_req),
+				&app_resp, sizeof(app_resp));
+	if (rc) {
+		dev_err(ssm->dev, "SCM call failed for LOOKUP COMMAND\n");
+		return -EINVAL;
+	}
+
+	if (app_resp.result == RESULT_FAILURE)
+		ssm->app_id = 0;
+	else
+		ssm->app_id = app_resp.data;
+
+	if (ssm->app_id) {
+		rc = 0;
+		dev_info(ssm->dev, "TZAPP already loaded...\n");
+		goto out;
+	}
+
+	/* APP not loaded get the firmware */
+	/* Get .mdt first */
+	rc =  request_firmware(&fw_mdt, FIRMWARE_NAME".mdt", ssm->dev);
+	if (rc) {
+		dev_err(ssm->dev, "Unable to get mdt file %s\n",
+						FIRMWARE_NAME".mdt");
+		rc = -EIO;
+		goto out;
+	}
+
+	if (fw_mdt->size < sizeof(*ehdr)) {
+		dev_err(ssm->dev, "Not big enough to be an elf header\n");
+		rc = -EIO;
+		goto release_mdt;
+	}
+
+	ehdr = (struct elf32_hdr *)fw_mdt->data;
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(ssm->dev, "Not an elf header\n");
+		rc = -EIO;
+		goto release_mdt;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(ssm->dev, "No loadable segments\n");
+		rc = -EIO;
+		goto release_mdt;
+	}
+
+	phdr = (const struct elf32_phdr *)(fw_mdt->data +
+					sizeof(struct elf32_hdr));
+
+	fw = kzalloc((sizeof(struct firmware *) * ehdr->e_phnum), GFP_KERNEL);
+	if (!fw) {
+		rc = -ENOMEM;
+		goto release_mdt;
+	}
+
+	/* Valid .mdt now we need to load other parts .b0* */
+	for (fw_count = 0; fw_count < ehdr->e_phnum ; fw_count++) {
+		snprintf(name, MAX_APP_NAME_SIZE, FIRMWARE_NAME".b%02d",
+								fw_count);
+		rc = request_firmware(&fw[fw_count], name, ssm->dev);
+		if (rc < 0) {
+			rc = -EIO;
+			dev_err(ssm->dev, "Unable to get blob file\n");
+			goto release_blob;
+		}
+
+		if (fw[fw_count]->size != phdr->p_filesz) {
+			dev_err(ssm->dev, "Blob size %u doesn't match %u\n",
+					fw[fw_count]->size, phdr->p_filesz);
+			rc = -EIO;
+			goto release_blob;
+		}
+
+		phdr++;
+		size += fw[fw_count]->size;
+	}
+
+	/* Ion allocation for loading tzapp */
+	/* ION buffer size 4k aligned */
+	ion_len = ALIGN_BUFFER(size);
+	ion_handle = ion_alloc(ssm_drv->ssm_ion_client,
+			ion_len, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(ion_handle)) {
+		rc = PTR_ERR(ion_handle);
+		dev_err(ssm->dev, "Unable to get ion handle\n");
+		goto release_blob;
+	}
+
+	rc = ion_phys(ssm_drv->ssm_ion_client, ion_handle,
+			&buff_phys, &buff_len);
+	if (rc < 0) {
+		dev_err(ssm->dev, "Unable to get ion physical address\n");
+		goto ion_free;
+	}
+
+	if (buff_len < size) {
+		rc = -ENOMEM;
+		goto ion_free;
+	}
+
+	buff_virt =
+		(ion_virt_addr_t)ion_map_kernel(ssm_drv->ssm_ion_client,
+				ion_handle);
+	if (IS_ERR_OR_NULL((void *)buff_virt)) {
+		rc = PTR_ERR((void *)buff_virt);
+		dev_err(ssm->dev, "Unable to get ion virtual address\n");
+		goto ion_free;
+	}
+
+	/* Copy firmware to ION memory */
+	memcpy((unsigned char *)buff_virt, fw_mdt->data, fw_mdt->size);
+	pos = (unsigned char *)buff_virt + fw_mdt->size;
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		memcpy(pos, fw[i]->data, fw[i]->size);
+		pos += fw[i]->size;
+	}
+
+	/* Loading app */
+	app_img_info.cmd_id = APP_START_COMMAND;
+	app_img_info.mdt_len = fw_mdt->size;
+	app_img_info.img_len = size;
+	app_img_info.phy_addr = buff_phys;
+
+	/* SCM call to load the TZ APP */
+	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_img_info,
+		sizeof(struct load_app), &app_resp, sizeof(app_resp));
+	if (rc) {
+		rc = -EIO;
+		dev_err(ssm->dev, "SCM call to load APP failed\n");
+		goto ion_unmap;
+	}
+
+	if (app_resp.result == RESULT_FAILURE) {
+		rc = -EIO;
+		dev_err(ssm->dev, "SCM command to load TzAPP failed\n");
+		goto ion_unmap;
+	}
+
+	ssm->app_id = app_resp.data;
+	ssm->app_status = SUCCESS;
+
+ion_unmap:
+	ion_unmap_kernel(ssm_drv->ssm_ion_client, ion_handle);
+ion_free:
+	ion_free(ssm_drv->ssm_ion_client, ion_handle);
+release_blob:
+	while (--fw_count >= 0)
+		release_firmware(fw[fw_count]);
+	kfree(fw);
+release_mdt:
+	release_firmware(fw_mdt);
+out:
+	return rc;
+}
+
+/*
+ * Allocate buffer for transactions.
+ */
+static int ssm_setup_ion(struct ssm_driver *ssm)
+{
+	int rc = 0;
+	unsigned int size;
+
+	size = ALIGN_BUFFER(ATOM_MSG_LEN);
+
+	/* ION client for communicating with TZ */
+	ssm->ssm_ion_client = msm_ion_client_create(UINT_MAX,
+							"ssm-kernel");
+	if (IS_ERR_OR_NULL(ssm->ssm_ion_client)) {
+		rc = PTR_ERR(ssm->ssm_ion_client);
+		dev_err(ssm->dev, "Ion client not created\n");
+		return rc;
+	}
+
+	/* Setup a small ION buffer for tz communication */
+	ssm->ssm_ion_handle = ion_alloc(ssm->ssm_ion_client,
+				size, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(ssm->ssm_ion_handle)) {
+		rc = PTR_ERR(ssm->ssm_ion_handle);
+		dev_err(ssm->dev, "Unable to get ion handle\n");
+		goto out;
+	}
+
+	rc = ion_phys(ssm->ssm_ion_client, ssm->ssm_ion_handle,
+			&ssm->buff_phys, &ssm->buff_len);
+	if (rc < 0) {
+		dev_err(ssm->dev,
+			"Unable to get ion buffer physical address\n");
+		goto ion_free;
+	}
+
+	if (ssm->buff_len < size) {
+		rc = -ENOMEM;
+		goto ion_free;
+	}
+
+	ssm->buff_virt =
+		(ion_virt_addr_t)ion_map_kernel(ssm->ssm_ion_client,
+				ssm->ssm_ion_handle);
+	if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
+		rc = PTR_ERR((void *)ssm->buff_virt);
+		dev_err(ssm->dev,
+			"Unable to get ion buffer virtual address\n");
+		goto ion_free;
+	}
+
+	return rc;
+
+ion_free:
+	ion_free(ssm->ssm_ion_client, ssm->ssm_ion_handle);
+out:
+	ion_client_destroy(ssm_drv->ssm_ion_client);
+	return rc;
+}
+
+static struct ssm_platform_data *populate_ssm_pdata(struct device *dev)
+{
+	struct ssm_platform_data *pdata;
+	int rc;
+
+	pdata = devm_kzalloc(dev, sizeof(struct ssm_platform_data),
+								GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	pdata->need_key_exchg =
+		of_property_read_bool(dev->of_node, "qcom,need-keyexhg");
+
+	rc = of_property_read_string(dev->of_node, "qcom,channel-name",
+							&pdata->channel_name);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Error reading channel_name property %d\n", rc);
+		return NULL;
+	} else if (rc == -EINVAL)
+		pdata->channel_name = CHANNEL_NAME;
+
+	return pdata;
+}
+
+static int __devinit ssm_probe(struct platform_device *pdev)
+{
+	int rc;
+	uint32_t system_call_id;
+	char legacy = '\0';
+	struct ssm_platform_data *pdata;
+	struct ssm_driver *drv;
+
+	if (pdev->dev.of_node)
+		pdata = populate_ssm_pdata(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "Empty platform data\n");
+		return -ENOMEM;
+	}
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(struct ssm_driver),
+								GFP_KERNEL);
+	if (!drv) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize the driver structure */
+	drv->atom_replay = -1;
+	drv->mtoa_replay = -1;
+	drv->app_id = -1;
+	drv->app_status = RETRY;
+	drv->ready = false;
+	drv->update_status = FAILED;
+	mutex_init(&drv->mutex);
+	drv->key_status = !pdata->need_key_exchg;
+	drv->channel_name = (char *)pdata->channel_name;
+	INIT_WORK(&drv->ipc_work, ssm_app_modem_work_fn);
+
+	/* Allocate memory for smd buffer */
+	drv->smd_buffer = devm_kzalloc(&pdev->dev,
+			(sizeof(char) * ATOM_MSG_LEN), GFP_KERNEL);
+	if (!drv->smd_buffer) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	/* Allocate response buffer */
+	drv->resp = devm_kzalloc(&pdev->dev,
+				sizeof(struct tzapp_get_mode_info_rsp),
+				GFP_KERNEL);
+	if (!drv->resp) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+
+	/* Check for TZ version */
+	system_call_id = QSEOS_CHECK_VERSION_CMD;
+	rc = scm_call(SCM_SVC_INFO, SSM_INFO_CMD_ID, &system_call_id,
+			sizeof(system_call_id), &legacy, sizeof(legacy));
+	if (rc) {
+		dev_err(&pdev->dev, "Get version failed %d\n", rc);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	/* This driver only support 1.4 TZ and QSEOS */
+	if (!legacy) {
+		dev_err(&pdev->dev,
+				"Driver doesn't support legacy version\n");
+		rc = -EINVAL;
+		goto exit;
+
+	}
+
+	/* Setup the ion buffer for transaction */
+	rc = ssm_setup_ion(drv);
+	if (rc < 0)
+		goto exit;
+
+	drv->dev = &pdev->dev;
+	ssm_drv = drv;
+	platform_set_drvdata(pdev, ssm_drv);
+
+	dev_dbg(&pdev->dev, "probe success\n");
+	return 0;
+
+exit:
+	mutex_destroy(&drv->mutex);
+	platform_set_drvdata(pdev, NULL);
+	return rc;
+
+}
+
+static int __devexit ssm_remove(struct platform_device *pdev)
+{
+	int rc;
+
+	struct scm_shutdown_req req;
+	struct scm_resp resp;
+
+	if (!ssm_drv)
+		return 0;
+	/*
+	 * Step to exit
+	 * 1. set ready to 0 (oem access closed).
+	 * 2. Close SMD modem connection closed.
+	 * 3. cleanup ion.
+	 */
+	ssm_drv->ready = false;
+	smd_close(ssm_drv->ch);
+	flush_work_sync(&ssm_drv->ipc_work);
+
+	/* ION clean up*/
+	ion_unmap_kernel(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
+	ion_free(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
+	ion_client_destroy(ssm_drv->ssm_ion_client);
+
+	/* Shutdown tzapp */
+	req.app_id = ssm_drv->app_id;
+	req.cmd_id = APP_SHUTDOWN_COMMAND;
+	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
+			&resp, sizeof(resp));
+	if (rc)
+		dev_err(&pdev->dev, "TZ_app Unload failed\n");
+
+	return rc;
+}
+
+static struct of_device_id ssm_match_table[] = {
+	{
+		.compatible = "qcom,ssm",
+	},
+	{}
+};
+
+static struct platform_driver ssm_pdriver = {
+	.probe          = ssm_probe,
+	.remove         = __devexit_p(ssm_remove),
+	.driver = {
+		.name   = SSM_DEV_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = ssm_match_table,
+	},
+};
+module_platform_driver(ssm_pdriver);
+
+/*
+ * Interface for external OEM driver.
+ * This interface supports following functionalities:
+ * 1. Get TZAPP ID.
+ * 2. Set default mode.
+ * 3. Set mode (encrypted mode and it's length is passed as parameter).
+ * 4. Set mode from TZ.
+ * 5. Get status of mode update.
+ *
+ */
+int ssm_oem_driver_intf(int cmd, char *mode, int len)
+{
+	int rc, req_len, resp_len;
+	struct tzapp_get_mode_info_req get_mode_req;
+	struct tzapp_get_mode_info_rsp *get_mode_resp;
+
+	/* If ssm_drv is NULL, probe failed */
+	if (!ssm_drv)
+		return -ENODEV;
+
+	mutex_lock(&ssm_drv->mutex);
+
+	if (ssm_drv->app_status == RETRY) {
+		/* Load TZAPP */
+		rc = ssm_load_app(ssm_drv);
+		if (rc) {
+			rc = -ENODEV;
+			ssm_drv->app_status = FAILED;
+			goto unlock;
+		}
+	} else if (ssm_drv->app_status == FAILED) {
+		rc = -ENODEV;
+		goto unlock;
+	}
+
+	/* Open modem SMD interface */
+	if (!ssm_drv->ready) {
+		rc = smd_open(ssm_drv->channel_name, &ssm_drv->ch, ssm_drv,
+							modem_request);
+		if (rc) {
+			rc = -EAGAIN;
+			goto unlock;
+		} else
+			ssm_drv->ready = true;
+	}
+
+	/* Try again modem key-exchange not yet done.*/
+	if (!ssm_drv->key_status) {
+		rc = -EAGAIN;
+		goto unlock;
+	}
+
+	/* Set return status to success */
+	rc = 0;
+
+	switch (cmd) {
+	case SSM_READY:
+		break;
+
+	case SSM_GET_APP_ID:
+		rc = ssm_drv->app_id;
+		break;
+
+	case SSM_MODE_INFO_READY:
+		ssm_drv->update_status = RETRY;
+		/* Fill command structure */
+		req_len = sizeof(struct tzapp_get_mode_info_req);
+		resp_len = sizeof(struct tzapp_get_mode_info_rsp);
+		get_mode_req.tzapp_ssm_cmd = GET_ENC_MODE;
+		rc = tz_scm_call(ssm_drv, (void *)&get_mode_req,
+				req_len, (void **)&get_mode_resp, resp_len);
+		if (rc) {
+			ssm_drv->update_status = FAILED;
+			break;
+		}
+
+		/* Send mode_info to modem */
+		rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
+				get_mode_resp->enc_mode_len,
+				get_mode_resp->enc_mode_info);
+		if (rc)
+			ssm_drv->update_status = FAILED;
+		break;
+
+	case SSM_SET_MODE:
+		ssm_drv->update_status = RETRY;
+
+		if (len > ENC_MODE_MAX_SIZE) {
+			ssm_drv->update_status = FAILED;
+			rc = -EINVAL;
+			break;
+		}
+		memcpy(ssm_drv->resp->enc_mode_info, mode, len);
+		ssm_drv->resp->enc_mode_len = len;
+
+		/* Send mode_info to modem */
+		rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
+				ssm_drv->resp->enc_mode_len,
+				ssm_drv->resp->enc_mode_info);
+		if (rc)
+			ssm_drv->update_status = FAILED;
+		break;
+
+	case SSM_GET_MODE_STATUS:
+		rc = ssm_drv->update_status;
+		break;
+
+	case SSM_SET_DEFAULT_MODE:
+		/* Modem does not send response for this */
+		ssm_drv->update_status = RETRY;
+		rc = update_modem(SSM_ATOM_SET_DEFAULT_MODE, ssm_drv,
+				1, "0");
+		if (rc)
+			ssm_drv->update_status = FAILED;
+		else
+			/* For default mode we don't get any resp
+			 * from modem.
+			 */
+			ssm_drv->update_status = SUCCESS;
+		break;
+	default:
+		rc = -EINVAL;
+		dev_err(ssm_drv->dev, "Invalid command\n");
+		break;
+	};
+
+unlock:
+	mutex_unlock(&ssm_drv->mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(ssm_oem_driver_intf);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Secure Service Module");
+
diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h
new file mode 100644
index 0000000..97add11
--- /dev/null
+++ b/drivers/platform/msm/ssm.h
@@ -0,0 +1,160 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SSM_H_
+#define __SSM_H_
+
+#define MAX_APP_NAME_SIZE	32
+#define MODE_INFO_MAX_SIZE	4
+#define ENC_MODE_MAX_SIZE	(100 + MODE_INFO_MAX_SIZE)
+
+/* tzapp response.*/
+enum tz_response {
+	RESULT_SUCCESS = 0,
+	RESULT_FAILURE  = 0xFFFFFFFF,
+};
+
+/* tzapp command list.*/
+enum tz_commands {
+	ENC_MODE,
+	GET_ENC_MODE,
+	KEY_EXCHANGE = 11,
+};
+
+/* Command list for QSEOS.*/
+enum qceos_cmd_id {
+	APP_START_COMMAND = 0x01,
+	APP_SHUTDOWN_COMMAND,
+	APP_LOOKUP_COMMAND,
+	CLIENT_SEND_DATA_COMMAND = 0x6,
+	QSEOS_CMD_MAX = 0xEFFFFFFF,
+};
+
+/* MODEM/SSM command list.*/
+enum ssm_ipc_req {
+	SSM_MTOA_KEY_EXCHANGE = 0x0000AAAA,
+	SSM_ATOM_KEY_STATUS,
+	SSM_ATOM_MODE_UPDATE,
+	SSM_MTOA_MODE_UPDATE_STATUS,
+	SSM_MTOA_PREV_INVALID,
+	SSM_ATOM_PREV_INVALID,
+	SSM_ATOM_SET_DEFAULT_MODE,
+	SSM_INVALID_REQ,
+};
+
+/* OEM reuest commands list.*/
+enum oem_req {
+	SSM_READY,
+	SSM_GET_APP_ID,
+	SSM_MODE_INFO_READY,
+	SSM_SET_MODE,
+	SSM_GET_MODE_STATUS,
+	SSM_SET_DEFAULT_MODE,
+	SSM_INVALID,
+};
+
+/* Modem mode update status.*/
+enum modem_mode_status {
+	SUCCESS,
+	RETRY,
+	FAILED = -1,
+};
+
+__packed struct load_app {
+	uint32_t cmd_id;
+	uint32_t mdt_len;
+	uint32_t img_len;
+	uint32_t phy_addr;
+	char     app_name[MAX_APP_NAME_SIZE];
+};
+
+/* Stop tzapp reuest.*/
+__packed struct scm_shutdown_req {
+	uint32_t cmd_id;
+	uint32_t app_id;
+};
+
+/* Common tzos response.*/
+__packed struct scm_resp {
+	uint32_t result;
+	enum tz_response resp_type;
+	unsigned int data;
+};
+
+/* tzos request.*/
+__packed struct check_app_req {
+	uint32_t cmd_id;
+	char     app_name[MAX_APP_NAME_SIZE];
+};
+
+/* tzapp encode mode reuest.*/
+__packed struct tzapp_mode_enc_req {
+	uint32_t tzapp_ssm_cmd;
+	uint8_t  mode_info[4];
+};
+
+/* tzapp encode mode response.*/
+__packed struct tzapp_mode_enc_rsp {
+	uint32_t tzapp_ssm_cmd;
+	uint8_t enc_mode_info[ENC_MODE_MAX_SIZE];
+	uint32_t enc_mode_len;
+	long status;
+};
+
+/* tzapp get mode request.*/
+__packed struct tzapp_get_mode_info_req {
+	uint32_t tzapp_ssm_cmd;
+};
+
+/* tzapp get mode response.*/
+__packed struct tzapp_get_mode_info_rsp {
+	uint32_t tzapp_ssm_cmd;
+	uint8_t  enc_mode_info[ENC_MODE_MAX_SIZE];
+	uint32_t enc_mode_len;
+	long status;
+};
+
+/* tzos key exchange request.*/
+__packed struct ssm_keyexchg_req {
+	uint32_t ssid;
+	void *address;
+	uint32_t length;
+	uint32_t *status;
+};
+
+/* tzos common request.*/
+__packed struct common_req {
+	uint32_t cmd_id;
+	uint32_t app_id;
+	void *req_ptr;
+	uint32_t req_len;
+	void *resp_ptr;
+	uint32_t resp_len;
+};
+
+/* tzos common response.*/
+__packed struct common_resp {
+	uint32_t result;
+	uint32_t type;
+	uint32_t data;
+};
+
+/* Modem/SSM packet format.*/
+struct ssm_common_msg {
+	unsigned long pktlen;
+	unsigned long replaynum;
+	enum ssm_ipc_req ipc_req;
+	unsigned long msg_len;
+	char *msg;
+};
+
+#endif
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 13e23e8..c5b1db4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -128,7 +128,6 @@
 	int			catch_up_time_us;
 	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
-	int			cc_reading_at_100;
 	int			max_voltage_uv;
 
 	int			chg_term_ua;
@@ -1042,10 +1041,8 @@
 	}
 
 	/* stop faking 100% after an OCV event */
-	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
 		chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
-		chip->cc_reading_at_100 = 0;
-	}
 	pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
 	pr_debug("1p25 = %duV\n", chip->xoadc_v125);
 	pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
@@ -1185,10 +1182,7 @@
 	int64_t cc_voltage_uv, cc_pvh, cc_uah;
 
 	cc_voltage_uv = cc;
-	cc_voltage_uv -= chip->cc_reading_at_100;
-	pr_debug("cc = %d. after subtracting 0x%x cc = %lld\n",
-					cc, chip->cc_reading_at_100,
-					cc_voltage_uv);
+	pr_debug("cc = %d\n", cc);
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
 	cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
 	pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
@@ -1513,10 +1507,7 @@
 
 	/* calculate cc micro_volt_hour */
 	calculate_cc_uah(chip, raw->cc, cc_uah);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
-				*cc_uah, raw->cc,
-				(int64_t)raw->cc - chip->cc_reading_at_100,
-				chip->cc_reading_at_100);
+	pr_debug("cc_uah = %duAh raw->cc = %x\n", *cc_uah, raw->cc);
 
 	soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah;
 	if (soc_rbatt < 0)
@@ -2653,19 +2644,20 @@
 
 	if (is_battery_full) {
 		the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
-		the_chip->cc_reading_at_100 = raw.cc;
 
 		the_chip->last_ocv_uv = the_chip->max_voltage_uv;
 		raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+		raw.cc = 0;
+		/* reset the cc in h/w */
+		reset_cc(the_chip);
 		the_chip->last_ocv_temp_decidegc = batt_temp;
 		/*
 		 * since we are treating this as an ocv event
 		 * forget the old cc value
 		 */
 		the_chip->last_cc_uah = 0;
-		pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
-				the_chip->ocv_reading_at_100,
-				the_chip->cc_reading_at_100);
+		pr_debug("EOC BATT_FULL ocv_reading = 0x%x\n",
+				the_chip->ocv_reading_at_100);
 	}
 
 	the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index e37b3c4..482d383 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -63,7 +63,7 @@
 #define TSENS_SN_REMOTE_CONFIG(n)	((n) + 0x3c)
 
 #define TSENS_EEPROM(n)			((n) + 0xd0)
-#define TSENS_EEPROM_REDUNDANCY_SEL(n)	((n) + 0x1cc)
+#define TSENS_EEPROM_REDUNDANCY_SEL(n)	((n) + 0x444)
 #define TSENS_EEPROM_BACKUP_REGION(n)	((n) + 0x440)
 
 #define TSENS_MAIN_CALIB_ADDR_RANGE	6
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 116b5b0..8e25780 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2051,6 +2051,7 @@
 	struct android_configuration *conf;
 	int enabled = 0;
 	bool audio_enabled = false;
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
 	if (!cdev)
 		return -ENODEV;
@@ -2096,7 +2097,7 @@
 					f_holder->f->disable(f_holder->f);
 			}
 		dev->enabled = false;
-	} else {
+	} else if (__ratelimit(&rl)) {
 		pr_err("android_usb: already %s\n",
 				dev->enabled ? "enabled" : "disabled");
 	}
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index a55f0e5..ff2287e 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -463,7 +463,10 @@
 
 static int adb_open(struct inode *ip, struct file *fp)
 {
-	pr_info("adb_open\n");
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+
+	if (__ratelimit(&rl))
+		pr_info("adb_open\n");
 	if (!_adb_dev)
 		return -ENODEV;
 
@@ -486,7 +489,10 @@
 
 static int adb_release(struct inode *ip, struct file *fp)
 {
-	pr_info("adb_release\n");
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+
+	if (__ratelimit(&rl))
+		pr_info("adb_release\n");
 
 	/*
 	 * ADB daemon closes the device file after I/O error.  The
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 38a3c15..323b481 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -145,29 +145,37 @@
  */
 static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	union xhci_trb *next;
 	unsigned long long addr;
 
 	ring->deq_updates++;
 
-	/* If this is not event ring, there is one more usable TRB */
+	/*
+	 * If this is not event ring, and the dequeue pointer
+	 * is not on a link TRB, there is one more usable TRB
+	 */
 	if (ring->type != TYPE_EVENT &&
 			!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
 		ring->num_trbs_free++;
-	next = ++(ring->dequeue);
 
-	/* Update the dequeue pointer further if that was a link TRB or we're at
-	 * the end of an event ring segment (which doesn't have link TRBS)
-	 */
-	while (last_trb(xhci, ring, ring->deq_seg, next)) {
-		if (ring->type == TYPE_EVENT &&	last_trb_on_last_seg(xhci,
-				ring, ring->deq_seg, next)) {
-			ring->cycle_state = (ring->cycle_state ? 0 : 1);
+	do {
+		/*
+		 * Update the dequeue pointer further if that was a link TRB or
+		 * we're at the end of an event ring segment (which doesn't have
+		 * link TRBS)
+		 */
+		if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
+			if (ring->type == TYPE_EVENT &&
+					last_trb_on_last_seg(xhci, ring,
+						ring->deq_seg, ring->dequeue)) {
+				ring->cycle_state = (ring->cycle_state ? 0 : 1);
+			}
+			ring->deq_seg = ring->deq_seg->next;
+			ring->dequeue = ring->deq_seg->trbs;
+		} else {
+			ring->dequeue++;
 		}
-		ring->deq_seg = ring->deq_seg->next;
-		ring->dequeue = ring->deq_seg->trbs;
-		next = ring->dequeue;
-	}
+	} while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
+
 	addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
 }
 
@@ -885,6 +893,17 @@
 	num_trbs_free_temp = ep_ring->num_trbs_free;
 	dequeue_temp = ep_ring->dequeue;
 
+	/* If we get two back-to-back stalls, and the first stalled transfer
+	 * ends just before a link TRB, the dequeue pointer will be left on
+	 * the link TRB by the code in the while loop.  So we have to update
+	 * the dequeue pointer one segment further, or we'll jump off
+	 * the segment into la-la-land.
+	 */
+	if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
+		ep_ring->deq_seg = ep_ring->deq_seg->next;
+		ep_ring->dequeue = ep_ring->deq_seg->trbs;
+	}
+
 	while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
 		/* We have more usable TRBs */
 		ep_ring->num_trbs_free++;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index f84fd82..8c88646 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -98,6 +98,9 @@
 		num_blks = DIV_ROUND_UP(2 * ps.ystride[i],
 			mdss_res->smp_mb_size);
 
+		if (mdss_res->mdp_rev == MDSS_MDP_HW_REV_100)
+			num_blks = roundup_pow_of_two(num_blks);
+
 		pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
 				num_blks, pipe->num, i);
 		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h
index c544356..294b1e7 100644
--- a/include/asm-generic/dma-contiguous.h
+++ b/include/asm-generic/dma-contiguous.h
@@ -18,7 +18,7 @@
 {
 	if (dev)
 		dev->cma_area = cma;
-	if (!dev || !dma_contiguous_default_area)
+	if (!dev && !dma_contiguous_default_area)
 		dma_contiguous_default_area = cma;
 }
 
diff --git a/include/linux/coresight-cti.h b/include/linux/coresight-cti.h
new file mode 100644
index 0000000..7f2da3f
--- /dev/null
+++ b/include/linux/coresight-cti.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_CORESIGHT_CTI_H
+#define _LINUX_CORESIGHT_CTI_H
+
+struct coresight_cti_data {
+	int nr_ctis;
+	const char **names;
+};
+
+struct coresight_cti {
+	const char *name;
+	struct list_head link;
+};
+
+#ifdef CONFIG_CORESIGHT_CTI
+extern struct coresight_cti *coresight_cti_get(const char *name);
+extern void coresight_cti_put(struct coresight_cti *cti);
+extern int coresight_cti_map_trigin(
+			struct coresight_cti *cti, int trig, int ch);
+extern int coresight_cti_map_trigout(
+			struct coresight_cti *cti, int trig, int ch);
+extern void coresight_cti_unmap_trigin(
+			struct coresight_cti *cti, int trig, int ch);
+extern void coresight_cti_unmap_trigout(
+			struct coresight_cti *cti, int trig, int ch);
+#else
+static inline struct coresight_cti *coresight_cti_get(const char *name)
+{
+	return NULL;
+}
+static inline void coresight_cti_put(struct coresight_cti *cti) {}
+static inline int coresight_cti_map_trigin(
+			struct coresight_cti *cti, int trig, int ch)
+{
+	return -ENOSYS;
+}
+static inline int coresight_cti_map_trigout(
+			struct coresight_cti *cti, int trig, int ch)
+{
+	return -ENOSYS;
+}
+static inline void coresight_cti_unmap_trigin(
+			struct coresight_cti *cti, int trig, int ch) {}
+static inline void coresight_cti_unmap_trigout(
+			struct coresight_cti *cti, int trig, int ch) {}
+#endif
+
+#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 2f303e4..01b5c84 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -68,7 +68,7 @@
 extern struct cma *dma_contiguous_default_area;
 
 void dma_contiguous_reserve(phys_addr_t addr_limit);
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
 			   phys_addr_t base, phys_addr_t limit);
 
 struct page *dma_alloc_from_contiguous(struct device *dev, int count,
@@ -83,7 +83,7 @@
 static inline void dma_contiguous_reserve(phys_addr_t limit) { }
 
 static inline
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
 			   phys_addr_t base, phys_addr_t limit)
 {
 	return -ENOSYS;
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 6a5e4d4..0943dda 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,12 +16,19 @@
 #ifdef CONFIG_OF
 extern struct coresight_platform_data *of_get_coresight_platform_data(
 				struct device *dev, struct device_node *node);
+extern struct coresight_cti_data *of_get_coresight_cti_data(
+				struct device *dev, struct device_node *node);
 #else
 static inline struct coresight_platform_data *of_get_coresight_platform_data(
 				struct device *dev, struct device_node *node)
 {
 	return NULL;
 }
+static inline struct coresight_cti_data *of_get_coresight_cti_data(
+				struct device *dev, struct device_node *node)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/include/linux/platform_data/qcom_ssm.h b/include/linux/platform_data/qcom_ssm.h
new file mode 100644
index 0000000..03ac67a
--- /dev/null
+++ b/include/linux/platform_data/qcom_ssm.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_SSM_H_
+#define __QCOM_SSM_H_
+
+struct ssm_platform_data {
+	bool need_key_exchg;
+	const char *channel_name;
+};
+
+#endif /* __QCOM_SSM_H_ */
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 4bcea07..c8647fb1 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -50,9 +50,9 @@
 #define MSM8X10_WCD_I2S_MASTER_MODE_MASK	0x08
 #define MSM8X10_DINO_CODEC_BASE_ADDR		0xFE043000
 
-#define MAX_MSM8X10_WCD_DEVICE	2
+#define MAX_MSM8X10_WCD_DEVICE	4
 #define CODEC_DT_MAX_PROP_SIZE	40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "2-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
 
 enum {
 	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -88,6 +88,7 @@
 	IIR2,
 	IIR_MAX,
 };
+
 /* Codec supports 5 bands */
 enum {
 	BAND1 = 0,
@@ -119,7 +120,6 @@
 	struct wcd9xxx_mbhc mbhc;
 };
 
-
 static unsigned short rx_digital_gain_reg[] = {
 	MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
 	MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -171,7 +171,7 @@
 	return rtn;
 }
 
-static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
 {
 	u32 temp = ((u32)(*value)) & 0x000000FF;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,10 +179,10 @@
 	return 0;
 }
 
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
 {
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	*value = (u8)ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+	*value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
 				      offset, 4));
 	return 0;
 }
@@ -194,10 +194,10 @@
 	int ret;
 	u8 reg_addr = 0;
 	u8 data[bytes + 1];
-	struct msm8x10_wcd_i2c *msm8x10_wcd;
+	struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
 
 	ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
-	if (!ret) {
+	if (ret) {
 		pr_err("%s: Invalid register address\n", __func__);
 		return ret;
 	}
@@ -219,7 +219,7 @@
 	/* Try again if the write fails */
 	if (ret != 1) {
 		ret = i2c_transfer(msm8x10_wcd->client->adapter,
-						msm8x10_wcd->xfer_msg, 1);
+				   msm8x10_wcd->xfer_msg, 1);
 		if (ret != 1) {
 			pr_err("failed to write the device\n");
 			return ret;
@@ -235,11 +235,11 @@
 	struct i2c_msg *msg;
 	int ret = 0;
 	u8 reg_addr = 0;
-	struct msm8x10_wcd_i2c *msm8x10_wcd;
+	struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
 	u8 i = 0;
 
 	ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
-	if (!ret) {
+	if (ret) {
 		pr_err("%s: Invalid register address\n", __func__);
 		return ret;
 	}
@@ -256,7 +256,6 @@
 		msg->len = 1;
 		msg->flags = 0;
 		msg->buf = &reg_addr;
-
 		msg = &msm8x10_wcd->xfer_msg[1];
 		msg->addr = msm8x10_wcd->client->addr;
 		msg->len = 1;
@@ -275,38 +274,45 @@
 			}
 		}
 	}
+	pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
 	return 0;
 }
 
-static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd, u16 reg)
+int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
 {
-	u8 val;
+	return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
+}
+
+int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
+{
+	return msm8x10_wcd_i2c_write_device(reg, src, bytes);
+}
+
+static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
+				u16 reg, unsigned int *val)
+{
 	int ret = -EINVAL;
 
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
-		ret = msm8x10_wcd_i2c_read_device(reg, 1, &val);
+		ret = msm8x10_wcd_i2c_read(reg, 1, val);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_read_device(reg, 1, &val);
+		ret = msm8x10_wcd_abh_read_device(reg, 1, val);
 	mutex_unlock(&msm8x10_wcd->io_lock);
-
-	if (ret < 0)
-		return ret;
-	else
-		return val;
+	return ret;
 }
 
 
 static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16  reg,
-				 u8 val)
+				 unsigned int val)
 {
 	int ret = -EINVAL;
 
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
-		ret = msm8x10_wcd_i2c_write_device(reg, &val, 1);
+		ret = msm8x10_wcd_i2c_write(reg, 1, &val);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
 		ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
 	mutex_unlock(&msm8x10_wcd->io_lock);
@@ -331,12 +337,13 @@
 	return rtn;
 }
 
-static int msm8x10_wcd_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
 {
 	/*
 	 * Registers lower than 0x100 are top level registers which can be
 	 * written by the Taiko core driver.
 	 */
+	dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
 
 	if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
 		return 1;
@@ -373,7 +380,7 @@
 			     unsigned int value)
 {
 	int ret;
-
+	dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
 	if (reg == SND_SOC_NOPM)
 		return 0;
 
@@ -395,6 +402,7 @@
 	unsigned int val;
 	int ret;
 
+	dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
 	if (reg == SND_SOC_NOPM)
 		return 0;
 
@@ -411,7 +419,7 @@
 				reg, ret);
 	}
 
-	val = msm8x10_wcd_reg_read(codec->control_data, reg);
+	ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
 	return val;
 }
 
@@ -431,7 +439,7 @@
 
 	if (!regnode) {
 		dev_err(dev, "Looking up %s property in node %s failed",
-				prop_name, dev->of_node->full_name);
+			prop_name, dev->of_node->full_name);
 		return -ENODEV;
 	}
 	vreg->name = vreg_name;
@@ -442,7 +450,7 @@
 
 	if (!prop || (len != (2 * sizeof(__be32)))) {
 		dev_err(dev, "%s %s property\n",
-				prop ? "invalid format" : "no", prop_name);
+			prop ? "invalid format" : "no", prop_name);
 		return -ENODEV;
 	} else {
 		vreg->min_uV = be32_to_cpup(&prop[0]);
@@ -450,18 +458,18 @@
 	}
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-			"qcom,%s-current", vreg_name);
+		"qcom,%s-current", vreg_name);
 
 	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
-				prop_name, dev->of_node->full_name);
+			prop_name, dev->of_node->full_name);
 		return -ENODEV;
 	}
 	vreg->optimum_uA = prop_val;
 
 	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
-		vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+		 vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
 	return 0;
 }
 
@@ -473,7 +481,7 @@
 	u32 prop_val;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-			"qcom,cdc-micbias-ldoh-v");
+		 "qcom,cdc-micbias-ldoh-v");
 	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
@@ -483,7 +491,7 @@
 	micbias->ldoh_v = (u8)prop_val;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-			"qcom,cdc-micbias-cfilt1-mv");
+		 "qcom,cdc-micbias-cfilt1-mv");
 	ret = of_property_read_u32(dev->of_node, prop_name,
 				   &micbias->cfilt1_mv);
 	if (ret) {
@@ -493,7 +501,7 @@
 	}
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
-			"qcom,cdc-micbias1-cfilt-sel");
+		 "qcom,cdc-micbias1-cfilt-sel");
 	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
@@ -508,7 +516,7 @@
 	     MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 
 	dev_dbg(dev, "ldoh_v  %u cfilt1_mv %u\n",
-			(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
+		(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
 	dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
 	dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
 
@@ -533,13 +541,14 @@
 		num_of_supplies = ARRAY_SIZE(msm8x10_wcd_supplies);
 	} else {
 		dev_err(dev, "%s unsupported device %s\n",
-				__func__, dev_name(dev));
+			__func__, dev_name(dev));
 		goto err;
 	}
 
 	if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
 		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
-		      __func__, num_of_supplies, ARRAY_SIZE(pdata->regulator));
+			__func__, num_of_supplies,
+			ARRAY_SIZE(pdata->regulator));
 
 		goto err;
 	}
@@ -574,8 +583,8 @@
 		struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
 
-	pr_debug("%s %d\n", __func__, event);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Enable charge pump clock*/
@@ -623,13 +632,11 @@
 	} else if (ear_pa_gain == 0x04) {
 		ucontrol->value.integer.value[0] = 1;
 	} else  {
-		pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
-				__func__, ear_pa_gain);
+		dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+			__func__, ear_pa_gain);
 		return -EINVAL;
 	}
-
-	pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
-
+	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
 	return 0;
 }
 
@@ -639,8 +646,8 @@
 	u8 ear_pa_gain;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
-	pr_debug("%s: ucontrol->value.integer.value[0]  = %ld\n",
-		 __func__, ucontrol->value.integer.value[0]);
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
 
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
@@ -673,7 +680,7 @@
 			    (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
 		(1 << band_idx);
 
-	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
 		iir_idx, band_idx,
 		(uint32_t)ucontrol->value.integer.value[0]);
 	return 0;
@@ -692,15 +699,15 @@
 
 	/* Mask first 5 bits, 6-8 are reserved */
 	snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
-		(1 << band_idx), (value << band_idx));
+			    (1 << band_idx), (value << band_idx));
 
-	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
 		iir_idx, band_idx, value);
 	return 0;
 }
 static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
-				int iir_idx, int band_idx,
-				int coeff_idx)
+				   int iir_idx, int band_idx,
+				   int coeff_idx)
 {
 	/* Address does not automatically update if reading */
 	snd_soc_write(codec,
@@ -734,7 +741,7 @@
 	ucontrol->value.integer.value[4] =
 		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
 
-	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
 		"%s: IIR #%d band #%d b1 = 0x%x\n"
 		"%s: IIR #%d band #%d b2 = 0x%x\n"
 		"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -780,17 +787,17 @@
 					kcontrol->private_value)->shift;
 
 	set_iir_band_coeff(codec, iir_idx, band_idx, 0,
-				ucontrol->value.integer.value[0]);
+			   ucontrol->value.integer.value[0]);
 	set_iir_band_coeff(codec, iir_idx, band_idx, 1,
-				ucontrol->value.integer.value[1]);
+			   ucontrol->value.integer.value[1]);
 	set_iir_band_coeff(codec, iir_idx, band_idx, 2,
-				ucontrol->value.integer.value[2]);
+			   ucontrol->value.integer.value[2]);
 	set_iir_band_coeff(codec, iir_idx, band_idx, 3,
-				ucontrol->value.integer.value[3]);
+			   ucontrol->value.integer.value[3]);
 	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
-				ucontrol->value.integer.value[4]);
+			   ucontrol->value.integer.value[4]);
 
-	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
 		"%s: IIR #%d band #%d b1 = 0x%x\n"
 		"%s: IIR #%d band #%d b2 = 0x%x\n"
 		"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -970,7 +977,6 @@
 	"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
 };
 
-
 static const char * const anc_mux_text[] = {
 	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
 		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
@@ -1076,14 +1082,16 @@
 	dec_name = strsep(&widget_name, " ");
 	widget_name = temp;
 	if (!dec_name) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
 		ret =  -EINVAL;
 		goto out;
 	}
 
 	ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
 	if (ret < 0) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, dec_name);
 		ret =  -EINVAL;
 		goto out;
 	}
@@ -1100,7 +1108,8 @@
 			adc_dmic_sel = 0x0;
 		break;
 	default:
-		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
+			__func__, decimator);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1204,18 +1213,18 @@
 static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
 					 int enable)
 {
-	struct msm8x10_wcd_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
 
-	pr_debug("%s %d\n", __func__, enable);
+	dev_dbg(codec->dev, "%s %d\n", __func__, enable);
 
 	if (enable) {
-		taiko->adc_count++;
+		wcd8x10->adc_count++;
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 				    0x20, 0x20);
 	} else {
-		taiko->adc_count--;
-		if (!taiko->adc_count)
+		wcd8x10->adc_count--;
+		if (!wcd8x10->adc_count)
 			snd_soc_update_bits(codec,
 					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 					    0x20, 0x0);
@@ -1229,7 +1238,7 @@
 	u16 adc_reg;
 	u8 init_bit_shift;
 
-	pr_debug("%s %d\n", __func__, event);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
 
 	if (w->reg == MSM8X10_WCD_A_TX_1_EN)
@@ -1237,7 +1246,8 @@
 	else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
 		init_bit_shift = 6;
 	else {
-		pr_err("%s: Error, invalid adc register\n", __func__);
+		dev_err(codec->dev, "%s: Error, invalid adc register\n",
+			__func__);
 		return -EINVAL;
 	}
 
@@ -1263,14 +1273,15 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 lineout_gain_reg;
 
-	pr_debug("%s %d %s\n", __func__, event, w->name);
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
 
 	switch (w->shift) {
 	case 0:
 		lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
 		break;
 	default:
-		pr_err("%s: Error, incorrect lineout register value\n",
+		dev_err(codec->dev,
+			"%s: Error, incorrect lineout register value\n",
 			__func__);
 		return -EINVAL;
 	}
@@ -1280,8 +1291,8 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
-				__func__, w->name);
+		dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
+			__func__, w->name);
 		usleep_range(16000, 16100);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -1294,7 +1305,7 @@
 static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
 				     struct snd_kcontrol *kcontrol, int event)
 {
-	pr_debug("%s %d %s\n", __func__, event, w->name);
+	dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
 	return 0;
 }
 
@@ -1311,7 +1322,8 @@
 
 	ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
 	if (ret < 0) {
-		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+		dev_err(codec->dev,
+			"%s: Invalid DMIC line on the codec\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1321,11 +1333,12 @@
 		dmic_clk_en = 0x01;
 		dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
 		dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
-		pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+		dev_dbg(codec->dev,
+			"%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
 			__func__, event,  dmic, *dmic_clk_cnt);
 		break;
 	default:
-		pr_err("%s: Invalid DMIC Selection\n", __func__);
+		dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1360,7 +1373,7 @@
 	char *internal3_text = "Internal3";
 	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
-	pr_debug("%s %d\n", __func__, event);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
@@ -1371,7 +1384,8 @@
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
-		pr_err("%s: Error, invalid micbias register\n", __func__);
+		dev_err(codec->dev,
+			"%s: Error, invalid micbias register\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1432,7 +1446,7 @@
 	u8 dec_hpf_cut_of_freq;
 	int offset;
 
-	pr_debug("%s %d\n", __func__, event);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 
 	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
 	if (!widget_name)
@@ -1442,26 +1456,29 @@
 	dec_name = strsep(&widget_name, " ");
 	widget_name = temp;
 	if (!dec_name) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, w->name);
 		ret = -EINVAL;
 		goto out;
 	}
 
 	ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
 	if (ret < 0) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, dec_name);
 		ret = -EINVAL;
 		goto out;
 	}
 
-	pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
-			w->name, dec_name, decimator);
+	dev_dbg(codec->dev,
+		"%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+		w->name, dec_name, decimator);
 
 	if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
 		dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
 		offset = 0;
 	} else {
-		pr_err("%s: Error, incorrect dec\n", __func__);
+		dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1531,11 +1548,12 @@
 }
 
 static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
+						 struct snd_kcontrol *kcontrol,
+						 int event)
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_debug("%s %d %s\n", __func__, event, w->name);
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1565,7 +1583,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 
-	pr_debug("%s %d\n", __func__, event);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1583,7 +1601,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_debug("%s %s %d\n", __func__, w->name, event);
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1603,7 +1621,7 @@
 	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	enum wcd9xxx_notify_event e_pre_on, e_post_off;
 
-	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
+	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
@@ -1611,7 +1629,8 @@
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
 	} else {
-		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
+		dev_err(codec->dev,
+			"%s: Invalid w->shift %d\n", __func__, w->shift);
 		return -EINVAL;
 	}
 
@@ -1635,8 +1654,9 @@
 		 * would have been locked while snd_soc_jack_report also
 		 * attempts to acquire same lock.
 		 */
-		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
-			 w->name);
+		dev_dbg(codec->dev,
+			"%s: sleep 10 ms after %s PA disable.\n", __func__,
+			w->name);
 		usleep_range(10000, 10100);
 		break;
 	}
@@ -1648,7 +1668,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_debug("%s %s %d\n", __func__, w->name, event);
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1665,7 +1685,7 @@
 static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	pr_debug("%s %s %d\n", __func__, w->name, event);
+	dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
 	return 0;
 }
 
@@ -1812,14 +1832,14 @@
 	{"MIC BIAS1 External", NULL, "LDO_H"},
 };
 
-
 static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
 	struct msm8x10_wcd *msm8x10_wcd_core =
 		dev_get_drvdata(dai->codec->dev);
-	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
-		 substream->name, substream->stream);
+	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
+		__func__,
+		substream->name, substream->stream);
 	if ((msm8x10_wcd_core != NULL) &&
 	    (msm8x10_wcd_core->dev != NULL))
 		pm_runtime_get_sync(msm8x10_wcd_core->dev);
@@ -1832,8 +1852,9 @@
 {
 	struct msm8x10_wcd *msm8x10_wcd_core =
 		dev_get_drvdata(dai->codec->dev);
-	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
-		 substream->name, substream->stream);
+	dev_dbg(dai->codec->dev,
+		"%s(): substream = %s  stream = %d\n" , __func__,
+		substream->name, substream->stream);
 	if ((msm8x10_wcd_core != NULL) &&
 	    (msm8x10_wcd_core->dev != NULL)) {
 		pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
@@ -1846,9 +1867,9 @@
 {
 	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 
-	pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
-		 dapm);
-
+	dev_dbg(codec->dev,
+		"%s: mclk_enable = %u, dapm = %d\n", __func__,
+		mclk_enable, dapm);
 	WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
 	if (mclk_enable) {
 		wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
@@ -1870,13 +1891,13 @@
 static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	pr_debug("%s\n", __func__);
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
 	return 0;
 }
 
 static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	pr_debug("%s\n", __func__);
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
 	return 0;
 }
 
@@ -1885,7 +1906,7 @@
 				unsigned int rx_num, unsigned int *rx_slot)
 
 {
-	pr_debug("%s\n", __func__);
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
 	return 0;
 }
 
@@ -1894,7 +1915,7 @@
 				 unsigned int *rx_num, unsigned int *rx_slot)
 
 {
-	pr_debug("%s\n", __func__);
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
 	return 0;
 }
 
@@ -1917,7 +1938,8 @@
 	u8 tx_fs_rate, rx_fs_rate;
 	int ret;
 
-	pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+	dev_dbg(dai->codec->dev,
+		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
 		 dai->name, dai->id, params_rate(params),
 		 params_channels(params));
 
@@ -1947,7 +1969,8 @@
 		rx_fs_rate = 0xA0;
 		break;
 	default:
-		pr_err("%s: Invalid sampling rate %d\n", __func__,
+		dev_err(dai->codec->dev,
+			"%s: Invalid sampling rate %d\n", __func__,
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -1957,7 +1980,8 @@
 		ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
 					       params_rate(params));
 		if (ret < 0) {
-			pr_err("%s: set decimator rate failed %d\n", __func__,
+			dev_err(dai->codec->dev,
+				"%s: set decimator rate failed %d\n", __func__,
 				ret);
 			return ret;
 		}
@@ -1966,13 +1990,15 @@
 		ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
 						  params_rate(params));
 		if (ret < 0) {
-			pr_err("%s: set decimator rate failed %d\n", __func__,
+			dev_err(dai->codec->dev,
+				"%s: set decimator rate failed %d\n", __func__,
 				ret);
 			return ret;
 		}
 		break;
 	default:
-		pr_err("%s: Invalid stream type %d\n", __func__,
+		dev_err(dai->codec->dev,
+			"%s: Invalid stream type %d\n", __func__,
 			substream->stream);
 		return -EINVAL;
 	}
@@ -2026,13 +2052,15 @@
 {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
-				 __func__);
+		dev_dbg(w->codec->dev,
+			"%s: Sleeping 20ms after enabling EAR PA\n",
+			__func__);
 		msleep(20);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
-				 __func__);
+		dev_dbg(w->codec->dev,
+			"%s: Sleeping 20ms after disabling EAR PA\n",
+			__func__);
 		msleep(20);
 		break;
 	}
@@ -2310,11 +2338,12 @@
 
 static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
 {
-	msm8x10_wcd_codec_init_reg(codec);
+	dev_dbg(codec->dev, "%s()\n", __func__);
 
+	codec->control_data = dev_get_drvdata(codec->dev);
+	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
 
-	dev_dbg(codec->dev, "%s()\n", __func__);
 
 	return 0;
 }
@@ -2324,6 +2353,18 @@
 	return 0;
 }
 
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+
+	mutex_init(&msm8x10->io_lock);
+	mutex_init(&msm8x10->xfer_lock);
+	mutex_init(&msm8x10->pm_lock);
+	msm8x10->wlock_holders = 0;
+
+	return 0;
+}
+
+
 static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
 	.probe	= msm8x10_wcd_codec_probe,
 	.remove	= msm8x10_wcd_codec_remove,
@@ -2349,8 +2390,21 @@
 static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	int ret;
+	int ret = 0;
+	struct msm8x10_wcd *msm8x10 = NULL;
 	struct msm8x10_wcd_pdata *pdata;
+	static int device_id;
+	struct device *dev;
+
+	dev_dbg(&client->dev, "%s:slave addr = 0x%x device_id = %d\n",
+		__func__, client->addr, device_id);
+
+	if (device_id > 0) {
+		msm8x10_wcd_modules[device_id++].client = client;
+		return ret;
+	}
+
+	dev = &client->dev;
 	if (client->dev.of_node) {
 		dev_dbg(&client->dev, "%s:Platform data from device tree\n",
 			__func__);
@@ -2362,16 +2416,50 @@
 		pdata = client->dev.platform_data;
 	}
 
-	ret = snd_soc_register_codec(&client->dev,
-		&soc_codec_dev_msm8x10_wcd,
-		msm8x10_wcd_i2s_dai, ARRAY_SIZE(msm8x10_wcd_i2s_dai));
-	dev_dbg(&client->dev, "%s:ret = 0x%x\n", __func__, ret);
+	msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
+	if (msm8x10 == NULL) {
+		dev_err(&client->dev,
+			"%s: error, allocation failed\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
 
+	msm8x10->dev = &client->dev;
+	msm8x10_wcd_modules[device_id++].client = client;
+	msm8x10->read_dev = msm8x10_wcd_reg_read;
+	msm8x10->write_dev = msm8x10_wcd_reg_write;
+	ret = msm8x10_wcd_device_init(msm8x10);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s:msm8x10_wcd_device_init failed with error %d\n",
+			__func__, ret);
+		goto fail;
+	}
+	dev_set_drvdata(&client->dev, msm8x10);
+	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
+				     msm8x10_wcd_i2s_dai,
+				     ARRAY_SIZE(msm8x10_wcd_i2s_dai));
+	if (ret)
+		dev_err(&client->dev,
+			"%s:snd_soc_register_codec failed with error %d\n",
+			__func__, ret);
+fail:
 	return ret;
 }
 
+static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
+{
+	mutex_destroy(&msm8x10->pm_lock);
+	mutex_destroy(&msm8x10->io_lock);
+	mutex_destroy(&msm8x10->xfer_lock);
+	kfree(msm8x10);
+}
+
 static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
 {
+	struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
+
+	msm8x10_wcd_device_exit(msm8x10);
 	return 0;
 }
 
@@ -2407,8 +2495,8 @@
 	pr_debug("%s:\n", __func__);
 	ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
 	if (ret != 0)
-		pr_err("%s: Failed to add msm8x10 wcd I2C driver - error code %d\n",
-			   __func__, ret);
+		pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
+		       __func__, ret);
 	return ret;
 }
 
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 365d526..44e8a6d 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -196,6 +196,10 @@
 	u8 version;
 
 	int reset_gpio;
+	int (*read_dev)(struct msm8x10_wcd *msm8x10,
+			unsigned short reg, unsigned int *val);
+	int (*write_dev)(struct msm8x10_wcd *msm8x10,
+			 unsigned short reg, unsigned int val);
 
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
diff --git a/sound/soc/msm/msm-pcm-host-voice.c b/sound/soc/msm/msm-pcm-host-voice.c
index 7cb309e3..36826cc 100644
--- a/sound/soc/msm/msm-pcm-host-voice.c
+++ b/sound/soc/msm/msm-pcm-host-voice.c
@@ -28,7 +28,7 @@
 
 #include "qdsp6/q6voice.h"
 
-#define HPCM_MAX_Q_LEN 2
+#define HPCM_MAX_Q_LEN 10
 #define HPCM_MIN_VOC_PKT_SIZE 320
 #define HPCM_MAX_VOC_PKT_SIZE 640
 
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 981a9a7..4dd85fc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -114,8 +114,8 @@
 		.stream_name = "Primary MI2S Playback",
 		.cpu_dai_name = "msm-dai-q6-mi2s.0",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
+		.codec_name     = "msm8x10-wcd-i2c-core.1-000d",
+		.codec_dai_name = "msm8x10_wcd_i2s_rx1",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_MI2S_RX,
 		.init = &msm_audrx_init,
@@ -127,8 +127,8 @@
 		.stream_name = "Secondary MI2S Capture",
 		.cpu_dai_name = "msm-dai-q6-mi2s.1",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
+		.codec_name     = "msm8x10-wcd-i2c-core.1-000d",
+		.codec_dai_name = "msm8x10_wcd_i2s_tx1",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,