Merge "defconfig: msm8226: Add separate defconfig"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 203730f..439418d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -13,8 +13,10 @@
 Required properties:
 - compatible:			Must be "qcom,cpr-regulator"
 - reg:				Register addresses for RBCPR and efuse
-- reg-names:			Register names. Must be "rbcpr" and "efuse_phys"
+- reg-names:			Register names. Must be "rbcpr", "pvs_efuse"
+				and "cpr_efuse"
 - regulator-name:		A string used to describe the regulator
+- interrupts:			Interrupt line from RBCPR to interrupt controller.
 - regulator-min-microvolt:	Minimum corner value as min constraint, which
 				should be 1 for SVS corner
 - regulator-max-microvolt:	Maximum corner value as max constraint, which
@@ -23,9 +25,6 @@
 				represent total number of PVS bins. It should
 				not exceed a maximum of 5 for total number of
 				32 bins.
-- qcom,efuse-bit-pos:		A list of integers whose length must equal
-				to qcom,num-efuse-bits and each integer indicates
-				bit position in efuse memory from LSB to MSB
 - qcom,pvs-bin-process:		A list of integers whose length is equal to 2 to
 				the power of qcom,num-efuse-bits. The location or
 				0-based index of an element in the list corresponds
@@ -44,8 +43,25 @@
 				  0 (SVS voltage):		1050000 uV
 				  1 (NORMAL voltage):		1150000 uV
 				  2 (TURBO voltage):		1275000 uV
-				  3 (SUPER_TURBO voltage):	1275000 uV
 - vdd-apc-supply:		Regulator to supply VDD APC power
+- qcom,vdd-apc-step-up-limit:	Limit of vdd-apc-supply steps for scaling up.
+- qcom,vdd-apc-step-down-limit:	Limit of vdd-apc-supply steps for scaling down.
+- qcom,cpr-ref-clk:		The reference clock in kHz.
+- qcom,cpr-timer-delay:		The delay in microseconds for the timer interval.
+- qcom,cpr-timer-cons-up:	Consecutive number of timer interval (qcom,cpr-timer-delay)
+				occurred before issuing UP interrupt.
+- qcom,cpr-timer-cons-down:	Consecutive number of timer interval (qcom,cpr-timer-delay)
+				occurred before issuing DOWN interrupt.
+- qcom,cpr-irq-line:		Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
+- qcom,cpr-step-quotient:	Number of CPR quotient (RO count) per vdd-apc-supply step
+				to issue error_steps.
+- qcom,cpr-up-threshold:	The threshold for CPR to issue interrupt when
+				error_steps is greater than it when stepping up.
+- qcom,cpr-down-threshold:	The threshold for CPR to issue interrupt when
+				error_steps is greater than it when stepping down.
+- qcom,cpr-idle-clocks:		Idle clock cycles RO can be in.
+- qcom,cpr-gcnt-time:		The time for gate count in microseconds.
+- qcom,cpr-apc-volt-step:	The voltage in microvolt per CPR step, such as 5000uV.
 
 
 Optional properties:
@@ -61,28 +77,42 @@
 				  2 => equal to slow speed corner ceiling
 				  3 => equal to qcom,vdd-mx-vmax
 				This is required when vdd-mx-supply is present.
+- qcom,cpr-enable:		Present: CPR enabled by default.
+				Not Present: CPR disable by default.
 
 
 Example:
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
 		compatible = "qcom,cpr-regulator";
-		reg = <0xf9018000 0x1000>,
-			<0xfc4b80b0 8>;
-		reg-names = "rbcpr", "efuse_phys";
+		reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+		reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <4>;
+		regulator-max-microvolt = <3>;
 		qcom,num-efuse-bits = <5>;
-		qcom,efuse-bit-pos = <6 7 8 9 10>;
-		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
 					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
-		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
-		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
 		vdd-apc-supply = <&pm8226_s2>;
 		vdd-mx-supply = <&pm8226_l3_ao>;
 		qcom,vdd-mx-vmax = <1350000>;
 		qcom,vdd-mx-vmin-method = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <1>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <15>;
+		qcom,cpr-up-threshold = <1>;
+		qcom,cpr-down-threshold = <2>;
+		qcom,cpr-idle-clocks = <5>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
 	};
 
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
index 76cacd8..2f8d65e 100644
--- a/Documentation/devicetree/bindings/input/gen_vkeys.txt
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -11,7 +11,10 @@
  - qcom,panel-maxx	: Maximum x-coordinate of touch panel
  - qcom,panel-maxy	: Maximum y-coordinate of touch panel
  - qcom,key-codes	: Array of key codes for virtual keys
- - qcom,y-offset	: Offset of y-location for virtual keys
+
+Optional properties:
+ - qcom,y-offset	: Offset of y-location for virtual keys, default 0
+
 Example:
 	gen-vkeys {
 		compatible = "qcom,gen-vkeys";
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index c3d929c..ded8f77 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -12,7 +12,6 @@
 - reg-names:	      Names of the bases for the above registers. "qdsp6_base",
 		      "halt_base", "rmb_base", and "restart_reg" are expected.
 - interrupts:         The modem watchdog interrupt
-- vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - vdd_cx-supply:      Reference to the regulator that supplies the vdd_cx domain.
 - vdd_mx-supply:      Reference to the regulator that supplies the memory rail.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
@@ -23,11 +22,16 @@
 - qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
 
 Optional properties:
+- vdd_mss-supply:     Reference to the regulator that supplies the processor.
+		      This may be a shared regulator that is already voted
+		      on in the PIL proxy voting code (and also managed by the
+		      modem on its own), hence we mark it as as optional.
 - vdd_pll-supply:     Reference to the regulator that supplies the PLL's rail.
 - qcom,vdd_pll:       Voltage to be set for the PLL's rail.
 - reg-names:          "cxrail_bhs_reg" - control register for modem power
 		      domain.
-- qcom,is-loadable:   Boolean- Present if the image needs to be loaded.
+- qcom,is-not-loadable: Boolean- Present if the image does not need to
+			be loaded.
 - qcom,pil-self-auth: Boolean- True if authentication is required.
 
 Example:
@@ -44,7 +48,7 @@
 		vdd_cx-supply = <&pm8841_s2>;
 		vdd_mx-supply = <&pm8841_s1>;
 
-		qcom,is-loadable;
+		qcom,is-not-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth;
 
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 2543c40..7a1bbef 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
+/include/ "skeleton64.dtsi"
 
 / {
 	model = "Qualcomm APQ 8084";
@@ -24,7 +24,7 @@
 &soc {
 	#address-cells = <1>;
 	#size-cells = <1>;
-	ranges;
+	ranges = <0 0 0 0xffffffff>;
 
 	intc: interrupt-controller@f9000000 {
 		compatible = "qcom,msm-qgic2";
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 1cc3c59..b0257d0 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -207,6 +207,7 @@
 		reg = <0xfd880000 0x10000>;
 		interrupts = <0 38 0>;
 		qcom,glb-offset = <0xF000>;
+		qcom,needs-alt-core-clk;
 		label = "gfx_iommu";
 		qcom,iommu-pmu-ngroups = <1>;
 		qcom,iommu-pmu-ncounters = <4>;
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index e4a42fa..7c19bc0 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -355,4 +355,18 @@
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fd828018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfd828018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 7fa9081..6aeaf49 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,23 +30,37 @@
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
 		compatible = "qcom,cpr-regulator";
-		reg = <0xf9018000 0x1000>,
-			<0xfc4b80b0 8>;
-		reg-names = "rbcpr", "efuse_phys";
+		reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+		reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <4>;
+		regulator-max-microvolt = <3>;
 		qcom,num-efuse-bits = <5>;
-		qcom,efuse-bit-pos = <6 7 8 9 10>;
-		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
 					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
-		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
-		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		qcom,pvs-corner-ceiling-slow = <1155000 1160000 1275000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
 		vdd-apc-supply = <&pm8226_s2>;
+
 		vdd-mx-supply = <&pm8226_l3_ao>;
 		qcom,vdd-mx-vmax = <1350000>;
 		qcom,vdd-mx-vmin-method = <1>;
+
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <1>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <15>;
+		qcom,cpr-up-threshold = <1>;
+		qcom,cpr-down-threshold = <2>;
+		qcom,cpr-idle-clocks = <5>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 53e4392..3cd9cb5 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -800,7 +800,6 @@
 			    "restart_reg", "cxrail_bhs_reg";
 
 		interrupts = <0 24 1>;
-		vdd_mss-supply = <&pm8226_s1>;
 		vdd_cx-supply = <&pm8226_s1_corner>;
 		vdd_mx-supply = <&pm8226_l3>;
 		vdd_pll-supply = <&pm8226_l8>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 1bf7c2b..ecedcb0 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -88,6 +88,49 @@
 			};
 		};
 	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "atmel_mxt_ts";
+		qcom,disp-maxx = <480>;
+		qcom,disp-maxy = <800>;
+		qcom,panel-maxx = <508>;
+		qcom,panel-maxy = <880>;
+		qcom,key-codes = <158 102 139>;
+		qcom,y-offset = <35>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 73 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 74 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 72 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 &i2c_cdc  {
@@ -165,38 +208,6 @@
 			};
 		};
 	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&msmgpio 73 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&msmgpio 74 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&msmgpio 72 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
 };
 
 &spmi_bus {
@@ -207,17 +218,6 @@
 			qcom,vib-vtg-level-mV = <3100>;
 		};
 	};
-
-	gen-vkeys {
-		compatible = "qcom,gen-vkeys";
-		label = "atmel_mxt_ts";
-		qcom,disp-maxx = <480>;
-		qcom,disp-maxy = <800>;
-		qcom,panel-maxx = <508>;
-		qcom,panel-maxy = <880>;
-		qcom,key-codes = <158 102 139>;
-		qcom,y-offset = <35>;
-	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 3fbc820..35e8909 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -88,6 +88,49 @@
 			};
 		};
 	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "atmel_mxt_ts";
+		qcom,disp-maxx = <480>;
+		qcom,disp-maxy = <800>;
+		qcom,panel-maxx = <508>;
+		qcom,panel-maxy = <880>;
+		qcom,key-codes = <158 102 139>;
+		qcom,y-offset = <35>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 73 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 74 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 72 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 &i2c_cdc  {
@@ -165,38 +208,6 @@
 			};
 		};
 	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&msmgpio 73 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&msmgpio 74 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&msmgpio 72 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
 };
 
 &spmi_bus {
@@ -207,17 +218,6 @@
 			qcom,vib-vtg-level-mV = <3100>;
 		};
 	};
-
-	gen-vkeys {
-		compatible = "qcom,gen-vkeys";
-		label = "atmel_mxt_ts";
-		qcom,disp-maxx = <480>;
-		qcom,disp-maxy = <800>;
-		qcom,panel-maxx = <508>;
-		qcom,panel-maxy = <880>;
-		qcom,key-codes = <158 102 139>;
-		qcom,y-offset = <35>;
-	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 3df428a..a90f053 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,23 +30,37 @@
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
 		compatible = "qcom,cpr-regulator";
-		reg = <0xf9018000 0x1000>,
-			<0xfc4b80b0 8>;
-		reg-names = "rbcpr", "efuse_phys";
+		reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+		reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <4>;
+		regulator-max-microvolt = <3>;
 		qcom,num-efuse-bits = <5>;
-		qcom,efuse-bit-pos = <6 7 8 9 10>;
-		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
 					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
-		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
-		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
+
 		vdd-mx-supply = <&pm8110_l3_ao>;
 		qcom,vdd-mx-vmax = <1350000>;
 		qcom,vdd-mx-vmin-method = <1>;
+
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <1>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <15>;
+		qcom,cpr-up-threshold = <1>;
+		qcom,cpr-down-threshold = <2>;
+		qcom,cpr-idle-clocks = <5>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 4b861ed..aff8759 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -144,6 +144,11 @@
 		qcom,adsp-state = <0>;
 	};
 
+	qcom,msm-audio-ion {
+		compatible = "qcom,msm-audio-ion";
+		qcom,smmu-enabled;
+	};
+
 	qcom,msm-imem@fe805000 {
 		compatible = "qcom,msm-imem";
 		reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
@@ -676,7 +681,6 @@
 			    "restart_reg", "cxrail_bhs_reg";
 
 		interrupts = <0 24 1>;
-		vdd_mss-supply = <&pm8110_s1>;
 		vdd_cx-supply = <&pm8110_s1_corner>;
 		vdd_mx-supply = <&pm8110_l3>;
 		vdd_pll-supply = <&pm8110_l10>;
@@ -721,14 +725,12 @@
 		qcom,sensors = <2>;
 		qcom,slope = <2901 2846>;
 		qcom,calib-mode = "fuse_map3";
-		qcom,calibration-less-mode;
-		qcom,tsens-local-init;
 		qcom,sensor-id = <0 5>;
 	};
 
 	qcom,msm-thermal {
 		compatible = "qcom,msm-thermal";
-		qcom,sensor-id = <0>;
+		qcom,sensor-id = <5>;
 		qcom,poll-ms = <250>;
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 71bbdc5..825fe8c 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1127,7 +1127,6 @@
 		vdd_mx-supply = <&pm8841_s1>;
 		vdd_pll-supply = <&pm8941_l12>;
 		qcom,vdd_pll = <1800000>;
-		qcom,is-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth;
 
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 8520b19..9b18b72 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -243,4 +243,15 @@
 		coresight-name = "coresight-cti-cpu";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@f9011038 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xf9011038 0x8>,
+		      <0xfd4ab160 0x80>;
+		reg-names = "apcs-mux", "ppss-mux";
+
+		coresight-id = <20>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 5abfab8..6e258b5 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -763,6 +763,7 @@
 	qcom,mss {
 		compatible = "qcom,pil-q6v5-mss";
 		interrupts = <0 24 1>;
+		qcom,is-not-loadable;
 
 		/* GPIO inputs from mss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
diff --git a/arch/arm/boot/dts/skeleton64.dtsi b/arch/arm/boot/dts/skeleton64.dtsi
new file mode 100644
index 0000000..5bf6a82
--- /dev/null
+++ b/arch/arm/boot/dts/skeleton64.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value.  The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	chosen { };
+	aliases { };
+	memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		device_type = "memory";
+		reg = <0 0 0 0>;
+	};
+};
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index e45024e..b385669 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -332,14 +332,6 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_MSM_IOMMU=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index bff59db..5e38ef1 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -336,6 +336,7 @@
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 8ebe7d4..bae4ee9 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -475,3 +475,4 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index fd8a639..8036a44 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -455,6 +455,7 @@
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
 CONFIG_CORESIGHT_EVENT=m
@@ -506,3 +507,4 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 7e92748..7891990 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -285,6 +285,7 @@
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index a6f772d..5793326 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -80,8 +80,8 @@
 	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 3 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
 	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
 	{ 0 }
 };
 
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 6212a4d..ac5efc1 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3123,6 +3123,7 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fd828018.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -3156,6 +3157,9 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd828018.hwevent"),
+
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent"),
 
 	/* HSUSB-OTG Clocks */
 	CLK_LOOKUP("xo",                 cxo_otg_clk.c, "f9a55000.usb"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5e60bd5..aa9368d 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3061,6 +3061,7 @@
 	CLK_DUMMY("core_clk",   NULL, "fd870000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd880000.qcom,iommu", OFF),
 	CLK_DUMMY("core_clk",   NULL, "fd880000.qcom,iommu", OFF),
+	CLK_DUMMY("alt_core_clk",   NULL, "fd880000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd000000.qcom,iommu", OFF),
 	CLK_DUMMY("core_clk",   NULL, "fd000000.qcom,iommu", OFF),
 	CLK_DUMMY("iface_clk",  NULL, "fd010000.qcom,iommu", OFF),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 75919149..ec94f00 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3194,7 +3194,9 @@
 	F_HDMI( 25200000, hdmipll, 1, 0, 0),
 	F_HDMI( 27000000, hdmipll, 1, 0, 0),
 	F_HDMI( 27030000, hdmipll, 1, 0, 0),
+	F_HDMI( 65000000, hdmipll, 1, 0, 0),
 	F_HDMI( 74250000, hdmipll, 1, 0, 0),
+	F_HDMI(108000000, hdmipll, 1, 0, 0),
 	F_HDMI(148500000, hdmipll, 1, 0, 0),
 	F_HDMI(268500000, hdmipll, 1, 0, 0),
 	F_HDMI(297000000, hdmipll, 1, 0, 0),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 313e04c..5bfc4bb 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -1924,6 +1924,7 @@
 	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_clk", qdss_clk.c, "f9011038.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -1945,7 +1946,7 @@
 	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"),
-
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
 };
 
 #define PLL_AUX_OUTPUT_BIT 1
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index d866874..bf95615 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -648,7 +648,49 @@
 		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
 		udelay(200);
 	break;
+	case 65000000:
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x4F, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0xED, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x8A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
 
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
+	break;
 	case 74250000:
 		/*
 		 * 720p60/720p50/1080i60/1080i50
@@ -697,6 +739,50 @@
 		udelay(200);
 	break;
 
+	case 108000000:
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x5B, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x38, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
+	break;
+
 	case 148500000:
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 08923e4..e51a1f5 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -24,26 +24,139 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
 
+/* Register Offsets for RB-CPR and Bit Definitions */
+
+/* RBCPR Gate Count and Target Registers */
+#define REG_RBCPR_GCNT_TARGET(n)	(0x60 + 4 * n)
+
+#define RBCPR_GCNT_TARGET_GCNT_BITS	10
+#define RBCPR_GCNT_TARGET_GCNT_SHIFT	12
+#define RBCPR_GCNT_TARGET_GCNT_MASK	((1<<RBCPR_GCNT_TARGET_GCNT_BITS)-1)
+
+/* RBCPR Timer Control */
+#define REG_RBCPR_TIMER_INTERVAL	0x44
+#define REG_RBIF_TIMER_ADJUST		0x4C
+
+#define RBIF_TIMER_ADJ_CONS_UP_BITS	4
+#define RBIF_TIMER_ADJ_CONS_UP_MASK	((1<<RBIF_TIMER_ADJ_CONS_UP_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_BITS	4
+#define RBIF_TIMER_ADJ_CONS_DOWN_MASK	((1<<RBIF_TIMER_ADJ_CONS_DOWN_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT	4
+
+/* RBCPR Config Register */
+#define REG_RBIF_LIMIT			0x48
+#define REG_RBCPR_STEP_QUOT		0x80
+#define REG_RBIF_SW_VLEVEL		0x94
+
+#define RBIF_LIMIT_CEILING_BITS		6
+#define RBIF_LIMIT_CEILING_MASK		((1<<RBIF_LIMIT_CEILING_BITS)-1)
+#define RBIF_LIMIT_CEILING_SHIFT	6
+#define RBIF_LIMIT_FLOOR_BITS		6
+#define RBIF_LIMIT_FLOOR_MASK		((1<<RBIF_LIMIT_FLOOR_BITS)-1)
+
+#define RBIF_LIMIT_CEILING_DEFAULT	RBIF_LIMIT_CEILING_MASK
+#define RBIF_LIMIT_FLOOR_DEFAULT	0
+#define RBIF_SW_VLEVEL_DEFAULT		0x20
+
+#define RBCPR_STEP_QUOT_STEPQUOT_BITS	8
+#define RBCPR_STEP_QUOT_STEPQUOT_MASK	((1<<RBCPR_STEP_QUOT_STEPQUOT_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_BITS	4
+#define RBCPR_STEP_QUOT_IDLE_CLK_MASK	((1<<RBCPR_STEP_QUOT_IDLE_CLK_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT	8
+
+/* RBCPR Control Register */
+#define REG_RBCPR_CTL			0x90
+
+#define RBCPR_CTL_LOOP_EN			BIT(0)
+#define RBCPR_CTL_TIMER_EN			BIT(3)
+#define RBCPR_CTL_SW_AUTO_CONT_ACK_EN		BIT(5)
+#define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN	BIT(6)
+#define RBCPR_CTL_COUNT_MODE			BIT(10)
+#define RBCPR_CTL_UP_THRESHOLD_BITS	4
+#define RBCPR_CTL_UP_THRESHOLD_MASK	((1<<RBCPR_CTL_UP_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_UP_THRESHOLD_SHIFT	24
+#define RBCPR_CTL_DN_THRESHOLD_BITS	4
+#define RBCPR_CTL_DN_THRESHOLD_MASK	((1<<RBCPR_CTL_DN_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_DN_THRESHOLD_SHIFT	28
+
+/* RBCPR Ack/Nack Response */
+#define REG_RBIF_CONT_ACK_CMD		0x98
+#define REG_RBIF_CONT_NACK_CMD		0x9C
+
+/* RBCPR Result status Register */
+#define REG_RBCPR_RESULT_0		0xA0
+
+#define RBCPR_RESULT0_ERROR_STEPS_SHIFT	2
+#define RBCPR_RESULT0_ERROR_STEPS_BITS	4
+#define RBCPR_RESULT0_ERROR_STEPS_MASK	((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
+
+/* RBCPR Interrupt Control Register */
+#define REG_RBIF_IRQ_EN(n)		(0x100 + 4 * n)
+#define REG_RBIF_IRQ_CLEAR		0x110
+#define REG_RBIF_IRQ_STATUS		0x114
+
+#define CPR_INT_DONE		BIT(0)
+#define CPR_INT_MIN		BIT(1)
+#define CPR_INT_DOWN		BIT(2)
+#define CPR_INT_MID		BIT(3)
+#define CPR_INT_UP		BIT(4)
+#define CPR_INT_MAX		BIT(5)
+#define CPR_INT_CLAMP		BIT(6)
+#define CPR_INT_ALL	(CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
+			CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
+#define CPR_INT_DEFAULT	(CPR_INT_UP | CPR_INT_DOWN)
+
+#define CPR_NUM_RING_OSC	8
+#define CPR_NUM_SAVE_REGS	10
+
+/* CPR eFuse parameters */
+#define CPR_FUSE_TARGET_QUOT_BITS	12
+#define CPR_FUSE_TARGET_QUOT_BITS_MASK	((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
+#define CPR_FUSE_RO_SEL_BITS		3
+#define CPR_FUSE_RO_SEL_BITS_MASK	((1<<CPR_FUSE_RO_SEL_BITS)-1)
+
+#define CPR_FUSE_TARGET_QUOT_TURBO_SHIFT	0
+#define CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT	12
+#define CPR_FUSE_TARGET_QUOT_SVS_SHIFT		24
+
+#define CPR_FUSE_DISABLE_CPR_SHIFT		36
+#define CPR_FUSE_LOCAL_APPROACH_SHIFT		37
+#define CPR_FUSE_REDUNDANT_SHIFT		57
+
+/* PVS eFuse parameters */
+#define PVS_FUSE_REDUNDANT_SHIFT	24
+#define PVS_FUSE_REDUNDANT_BITS		3
+#define PVS_FUSE_REDUNDANT_MASK		((1<<PVS_FUSE_REDUNDANT_BITS)-1)
+
+#define PVS_FUSE_BINS_SHIFT		6
+#define PVS_FUSE_BINS_REDUNDANT_SHIFT	27
+
+enum voltage_change_dir {
+	NO_CHANGE,
+	DOWN,
+	UP,
+};
+
 struct cpr_regulator {
 	struct regulator_desc		rdesc;
 	struct regulator_dev		*rdev;
-	bool				enabled;
+	bool				vreg_enabled;
 	int				corner;
+	int				ceiling_max;
 
 	/* Process voltage parameters */
-	phys_addr_t	efuse_phys;
+	phys_addr_t	pvs_efuse;
 	u32		num_efuse_bits;
-	u32		efuse_bit_pos[CPR_PVS_EFUSE_BITS_MAX];
 	u32		pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
-	u32		pvs_corner_ceiling[NUM_APC_PVS][CPR_CORNER_MAX];
+	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
-	u32		pvs_process;
-	u32		*corner_ceiling;
+	u32		process;
 
 	/* APC voltage regulator */
 	struct regulator	*vdd_apc;
@@ -53,13 +166,499 @@
 	int			vdd_mx_vmax;
 	int			vdd_mx_vmin_method;
 	int			vdd_mx_vmin;
+
+	/* CPR parameters */
+	phys_addr_t	cpr_fuse_addr;
+	u64		cpr_fuse_bits;
+	u64		cpr_fuse_bits_2;
+	bool		cpr_fuse_disable;
+	bool		cpr_fuse_local;
+	bool		cpr_fuse_redundancy;
+	int		cpr_fuse_target_quot[CPR_CORNER_MAX];
+	int		cpr_fuse_ro_sel[CPR_CORNER_MAX];
+	int		gcnt;
+
+	unsigned int	cpr_irq;
+	void __iomem	*rbcpr_base;
+	struct mutex	cpr_mutex;
+
+	int		ceiling_volt[CPR_CORNER_MAX];
+	int		floor_volt[CPR_CORNER_MAX];
+	int		last_volt[CPR_CORNER_MAX];
+	int		step_volt;
+
+	int		save_ctl[CPR_CORNER_MAX];
+	int		save_irq[CPR_CORNER_MAX];
+
+	u32		save_regs[CPR_NUM_SAVE_REGS];
+	u32		save_reg_val[CPR_NUM_SAVE_REGS];
+
+	/* Config parameters */
+	bool		enable;
+	u32		ref_clk_khz;
+	u32		timer_delay_us;
+	u32		timer_cons_up;
+	u32		timer_cons_down;
+	u32		irq_line;
+	u32		step_quotient;
+	u32		up_threshold;
+	u32		down_threshold;
+	u32		idle_clocks;
+	u32		gcnt_time_us;
+	u32		vdd_apc_step_up_limit;
+	u32		vdd_apc_step_down_limit;
 };
 
+static int cpr_debug_enable;
+static int cpr_enable;
+static struct cpr_regulator *the_cpr;
+
+module_param_named(debug_enable, cpr_debug_enable, int, S_IRUGO | S_IWUSR);
+#define cpr_debug(message, ...) \
+	do { \
+		if (cpr_debug_enable) \
+			pr_info(message, ##__VA_ARGS__); \
+	} while (0)
+
+static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
+{
+	if (cpr_vreg->cpr_fuse_disable || !cpr_enable)
+		return false;
+	else
+		return true;
+}
+
+static void cpr_write(struct cpr_regulator *cpr_vreg, u32 offset, u32 value)
+{
+	writel_relaxed(value, cpr_vreg->rbcpr_base + offset);
+}
+
+static u32 cpr_read(struct cpr_regulator *cpr_vreg, u32 offset)
+{
+	return readl_relaxed(cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_masked_write(struct cpr_regulator *cpr_vreg, u32 offset,
+			     u32 mask, u32 value)
+{
+	u32 reg_val;
+
+	reg_val = readl_relaxed(cpr_vreg->rbcpr_base + offset);
+	reg_val &= ~mask;
+	reg_val |= value & mask;
+	writel_relaxed(reg_val, cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_irq_clr(struct cpr_regulator *cpr_vreg)
+{
+	cpr_write(cpr_vreg, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
+}
+
+static void cpr_irq_clr_nack(struct cpr_regulator *cpr_vreg)
+{
+	cpr_irq_clr(cpr_vreg);
+	cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
+}
+
+static void cpr_irq_clr_ack(struct cpr_regulator *cpr_vreg)
+{
+	cpr_irq_clr(cpr_vreg);
+	cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
+}
+
+static void cpr_irq_set(struct cpr_regulator *cpr_vreg, u32 int_bits)
+{
+	cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), int_bits);
+}
+
+static void cpr_ctl_modify(struct cpr_regulator *cpr_vreg, u32 mask, u32 value)
+{
+	cpr_masked_write(cpr_vreg, REG_RBCPR_CTL, mask, value);
+}
+
+static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg)
+{
+	u32 val;
+
+	if (cpr_is_allowed(cpr_vreg))
+		val = RBCPR_CTL_LOOP_EN;
+	else
+		val = 0;
+	cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, val);
+}
+
+static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
+{
+	cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
+}
+
+static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
+{
+	int i, offset;
+
+	for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+		offset = cpr_vreg->save_regs[i];
+		cpr_vreg->save_reg_val[i] = cpr_read(cpr_vreg, offset);
+	}
+}
+
+static void cpr_regs_restore(struct cpr_regulator *cpr_vreg)
+{
+	int i, offset;
+	u32 val;
+
+	for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+		offset = cpr_vreg->save_regs[i];
+		val = cpr_vreg->save_reg_val[i];
+		cpr_write(cpr_vreg, offset, val);
+	}
+}
+
+static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
+{
+	cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+	cpr_vreg->save_irq[corner] =
+		cpr_read(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line));
+}
+
+static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
+{
+	u32 gcnt, ctl, irq, ro_sel;
+
+	ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
+	gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
+	cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
+	ctl = cpr_vreg->save_ctl[corner];
+	cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
+	irq = cpr_vreg->save_irq[corner];
+	cpr_irq_set(cpr_vreg, irq);
+	cpr_debug("gcnt = 0x%08x, ctl = 0x%08x, irq = 0x%08x\n",
+		  gcnt, ctl, irq);
+}
+
+static void cpr_corner_switch(struct cpr_regulator *cpr_vreg, int corner)
+{
+	if (cpr_vreg->corner == corner)
+		return;
+
+	cpr_corner_restore(cpr_vreg, corner);
+}
+
+/* Module parameter ops */
+static int cpr_enable_param_set(const char *val, const struct kernel_param *kp)
+{
+	int rc;
+	int old_cpr_enable;
+
+	if (!the_cpr) {
+		pr_err("the_cpr = NULL\n");
+		return -ENXIO;
+	}
+
+	mutex_lock(&the_cpr->cpr_mutex);
+
+	old_cpr_enable = cpr_enable;
+	rc = param_set_int(val, kp);
+	if (rc) {
+		pr_err("param_set_int: rc = %d\n", rc);
+		goto _exit;
+	}
+
+	cpr_debug("%d -> %d [corner=%d]\n",
+		  old_cpr_enable, cpr_enable, the_cpr->corner);
+
+	if (the_cpr->cpr_fuse_disable) {
+		/* Already disabled */
+		pr_info("CPR disabled by fuse\n");
+		goto _exit;
+	}
+
+	if ((old_cpr_enable != cpr_enable) && the_cpr->corner) {
+		if (cpr_enable) {
+			cpr_ctl_disable(the_cpr);
+			cpr_irq_clr(the_cpr);
+			cpr_corner_restore(the_cpr, the_cpr->corner);
+			cpr_ctl_enable(the_cpr);
+		} else {
+			cpr_ctl_disable(the_cpr);
+			cpr_irq_set(the_cpr, 0);
+		}
+	}
+
+_exit:
+	mutex_unlock(&the_cpr->cpr_mutex);
+	return 0;
+}
+
+static struct kernel_param_ops cpr_enable_ops = {
+	.set = cpr_enable_param_set,
+	.get = param_get_int,
+};
+
+module_param_cb(cpr_enable, &cpr_enable_ops, &cpr_enable, S_IRUGO | S_IWUSR);
+
+static int cpr_apc_set(struct cpr_regulator *cpr_vreg, u32 new_volt)
+{
+	int max_volt, rc;
+
+	max_volt = cpr_vreg->ceiling_max;
+	rc = regulator_set_voltage(cpr_vreg->vdd_apc, new_volt, max_volt);
+	if (rc)
+		pr_err("set: vdd_apc = %d uV: rc=%d\n", new_volt, rc);
+	return rc;
+}
+
+static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
+{
+	int vdd_mx;
+
+	switch (cpr_vreg->vdd_mx_vmin_method) {
+	case VDD_MX_VMIN_APC:
+		vdd_mx = apc_volt;
+		break;
+	case VDD_MX_VMIN_APC_CORNER_CEILING:
+		vdd_mx = cpr_vreg->ceiling_volt[corner];
+		break;
+	case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
+		vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
+						[CPR_CORNER_TURBO];
+		break;
+	case VDD_MX_VMIN_MX_VMAX:
+		vdd_mx = cpr_vreg->vdd_mx_vmax;
+		break;
+	default:
+		vdd_mx = 0;
+		break;
+	}
+
+	return vdd_mx;
+}
+
+static int cpr_mx_set(struct cpr_regulator *cpr_vreg, int corner,
+		      int vdd_mx_vmin)
+{
+	int rc;
+
+	rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
+				   cpr_vreg->vdd_mx_vmax);
+	cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
+	if (!rc)
+		cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
+	else
+		pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
+		       corner, vdd_mx_vmin, rc);
+	return rc;
+}
+
+static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
+			     int new_apc_volt, enum voltage_change_dir dir)
+{
+	int rc = 0, vdd_mx_vmin = 0;
+
+	/* No MX scaling if no vdd_mx */
+	if (cpr_vreg->vdd_mx == NULL)
+		dir = NO_CHANGE;
+
+	if (dir != NO_CHANGE) {
+		/* Determine the vdd_mx voltage */
+		vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);
+	}
+
+	if (vdd_mx_vmin && dir == UP) {
+		if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+			rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+	}
+
+	if (!rc)
+		rc = cpr_apc_set(cpr_vreg, new_apc_volt);
+
+	if (!rc && vdd_mx_vmin && dir == DOWN) {
+		if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+			rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+	}
+
+	return rc;
+}
+
+static void cpr_scale(struct cpr_regulator *cpr_vreg,
+		      enum voltage_change_dir dir)
+{
+	u32 reg_val, error_steps, reg_mask;
+	int last_volt, new_volt, corner;
+
+	corner = cpr_vreg->corner;
+
+	reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
+
+	error_steps = (reg_val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
+				& RBCPR_RESULT0_ERROR_STEPS_MASK;
+	last_volt = cpr_vreg->last_volt[corner];
+
+	cpr_debug("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+
+	if (dir == UP) {
+		cpr_debug("Up: cpr status = 0x%08x (error_steps=%d)\n",
+			  reg_val, error_steps);
+
+		if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
+			cpr_debug("[corn:%d] @ ceiling: %d >= %d: NACK\n",
+				  corner, last_volt,
+				  cpr_vreg->ceiling_volt[corner]);
+			cpr_irq_clr_nack(cpr_vreg);
+
+			/* Maximize the UP threshold */
+			reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+					RBCPR_CTL_UP_THRESHOLD_SHIFT;
+			reg_val = reg_mask;
+			cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+			return;
+		}
+
+		if (error_steps > cpr_vreg->vdd_apc_step_up_limit) {
+			cpr_debug("%d is over up-limit(%d): Clamp\n",
+				  error_steps,
+				  cpr_vreg->vdd_apc_step_up_limit);
+			error_steps = cpr_vreg->vdd_apc_step_up_limit;
+		}
+
+		/* Calculate new voltage */
+		new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
+		if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+			cpr_debug("new_volt(%d) >= ceiling_volt(%d): Clamp\n",
+				  new_volt, cpr_vreg->ceiling_volt[corner]);
+			new_volt = cpr_vreg->ceiling_volt[corner];
+		}
+
+		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+			cpr_irq_clr_nack(cpr_vreg);
+			return;
+		}
+		cpr_vreg->last_volt[corner] = new_volt;
+
+		/* Restore default threshold for DOWN */
+		reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+				RBCPR_CTL_DN_THRESHOLD_SHIFT;
+		reg_val = cpr_vreg->down_threshold <<
+				RBCPR_CTL_DN_THRESHOLD_SHIFT;
+		/* and disable auto nack down */
+		reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+		cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+		/* Re-enable default interrupts */
+		cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+		/* Ack */
+		cpr_irq_clr_ack(cpr_vreg);
+
+		cpr_debug("UP: -> new_volt = %d uV\n", new_volt);
+	} else if (dir == DOWN) {
+		cpr_debug("Down: cpr status = 0x%08x (error_steps=%d)\n",
+			  reg_val, error_steps);
+
+		if (last_volt <= cpr_vreg->floor_volt[corner]) {
+			cpr_debug("[corn:%d] @ floor: %d <= %d: NACK\n",
+				  corner, last_volt,
+				  cpr_vreg->floor_volt[corner]);
+			cpr_irq_clr_nack(cpr_vreg);
+
+			/* Maximize the DOWN threshold */
+			reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+					RBCPR_CTL_DN_THRESHOLD_SHIFT;
+			reg_val = reg_mask;
+
+			/* Enable auto nack down */
+			reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+			reg_val |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+			cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+			/* Disable DOWN interrupt */
+			cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
+
+			return;
+		}
+
+		if (error_steps > cpr_vreg->vdd_apc_step_down_limit) {
+			cpr_debug("%d is over down-limit(%d): Clamp\n",
+				  error_steps,
+				  cpr_vreg->vdd_apc_step_down_limit);
+			error_steps = cpr_vreg->vdd_apc_step_down_limit;
+		}
+
+		/* Calculte new voltage */
+		new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
+		if (new_volt < cpr_vreg->floor_volt[corner]) {
+			cpr_debug("new_volt(%d) < floor_volt(%d): Clamp\n",
+				  new_volt, cpr_vreg->floor_volt[corner]);
+			new_volt = cpr_vreg->floor_volt[corner];
+		}
+
+		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+			cpr_irq_clr_nack(cpr_vreg);
+			return;
+		}
+		cpr_vreg->last_volt[corner] = new_volt;
+
+		/* Restore default threshold for UP */
+		reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+				RBCPR_CTL_UP_THRESHOLD_SHIFT;
+		reg_val = cpr_vreg->up_threshold <<
+				RBCPR_CTL_UP_THRESHOLD_SHIFT;
+		cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+		/* Ack */
+		cpr_irq_clr_ack(cpr_vreg);
+
+		cpr_debug("DOWN: -> new_volt = %d uV\n", new_volt);
+	}
+}
+
+static irqreturn_t cpr_irq_handler(int irq, void *dev)
+{
+	struct cpr_regulator *cpr_vreg = dev;
+	u32 reg_val;
+
+	mutex_lock(&cpr_vreg->cpr_mutex);
+
+	reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+	cpr_debug("IRQ_STATUS = 0x%02X\n", reg_val);
+
+	if (!cpr_is_allowed(cpr_vreg)) {
+		reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+		pr_err("Interrupt broken? RBCPR_CTL = 0x%02X\n", reg_val);
+		goto _exit;
+	}
+
+	/* Following sequence of handling is as per each IRQ's priority */
+	if (reg_val & CPR_INT_UP) {
+		cpr_scale(cpr_vreg, UP);
+	} else if (reg_val & CPR_INT_DOWN) {
+		cpr_scale(cpr_vreg, DOWN);
+	} else if (reg_val & CPR_INT_MIN) {
+		cpr_irq_clr_nack(cpr_vreg);
+	} else if (reg_val & CPR_INT_MAX) {
+		cpr_irq_clr_nack(cpr_vreg);
+	} else if (reg_val & CPR_INT_MID) {
+		/* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
+		cpr_debug("IRQ occured for Mid Flag\n");
+	} else {
+		pr_err("IRQ occured for unknown flag (0x%08x)\n", reg_val);
+	}
+
+	/* Save register values for the corner */
+	cpr_corner_save(cpr_vreg, cpr_vreg->corner);
+
+_exit:
+	mutex_unlock(&cpr_vreg->cpr_mutex);
+	return IRQ_HANDLED;
+}
+
 static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
 {
 	struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
 
-	return cpr_vreg->enabled;
+	return cpr_vreg->vreg_enabled;
 }
 
 static int cpr_regulator_enable(struct regulator_dev *rdev)
@@ -78,7 +677,7 @@
 
 	rc = regulator_enable(cpr_vreg->vdd_apc);
 	if (!rc)
-		cpr_vreg->enabled = true;
+		cpr_vreg->vreg_enabled = true;
 	else
 		pr_err("regulator_enable: vdd_apc: rc=%d\n", rc);
 
@@ -98,7 +697,7 @@
 		if (rc)
 			pr_err("regulator_disable: vdd_mx: rc=%d\n", rc);
 		else
-			cpr_vreg->enabled = false;
+			cpr_vreg->vreg_enabled = false;
 	} else {
 		pr_err("regulator_disable: vdd_apc: rc=%d\n", rc);
 	}
@@ -107,90 +706,44 @@
 }
 
 static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
-		int min_uV, int max_uV, unsigned *selector)
+		int corner, int corner_max, unsigned *selector)
 {
 	struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
 	int rc;
-	int vdd_apc_min, vdd_apc_max, vdd_mx_vmin = 0;
-	int change_dir = 0;
+	int new_volt;
+	enum voltage_change_dir change_dir = NO_CHANGE;
 
-	if (cpr_vreg->vdd_mx) {
-		if (min_uV > cpr_vreg->corner)
-			change_dir = 1;
-		else if (min_uV < cpr_vreg->corner)
-			change_dir = -1;
-	}
+	mutex_lock(&cpr_vreg->cpr_mutex);
 
-	vdd_apc_min = cpr_vreg->corner_ceiling[min_uV];
-	vdd_apc_max = cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO];
-
-	if (change_dir) {
-		/* Determine the vdd_mx voltage */
-		switch (cpr_vreg->vdd_mx_vmin_method) {
-		case VDD_MX_VMIN_APC:
-			vdd_mx_vmin = vdd_apc_min;
-			break;
-		case VDD_MX_VMIN_APC_CORNER_CEILING:
-			vdd_mx_vmin = vdd_apc_min;
-			break;
-		case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
-			vdd_mx_vmin = cpr_vreg->pvs_corner_ceiling
-					[APC_PVS_SLOW][min_uV];
-			break;
-		case VDD_MX_VMIN_MX_VMAX:
-		default:
-			vdd_mx_vmin = cpr_vreg->vdd_mx_vmax;
-			break;
-		}
-	}
-
-	if (change_dir > 0) {
-		if (vdd_mx_vmin < cpr_vreg->vdd_mx_vmin) {
-			/* Check and report the value in case */
-			pr_err("Up: but new %d < old %d uV\n", vdd_mx_vmin,
-					cpr_vreg->vdd_mx_vmin);
-		}
-
-		rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
-					   cpr_vreg->vdd_mx_vmax);
-		if (!rc) {
-			cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
-		} else {
-			pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
-			       min_uV, vdd_mx_vmin, rc);
-			return rc;
-		}
-	}
-
-	rc = regulator_set_voltage(cpr_vreg->vdd_apc,
-				   vdd_apc_min, vdd_apc_max);
-	if (!rc) {
-		cpr_vreg->corner = min_uV;
+	if (cpr_is_allowed(cpr_vreg)) {
+		cpr_ctl_disable(cpr_vreg);
+		new_volt = cpr_vreg->last_volt[corner];
 	} else {
-		pr_err("set: vdd_apc [%d] = %d uV: rc=%d\n",
-		       min_uV, vdd_apc_min, rc);
-		return rc;
+		new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
 	}
 
-	if (change_dir < 0) {
-		if (vdd_mx_vmin > cpr_vreg->vdd_mx_vmin) {
-			/* Check and report the value in case */
-			pr_err("Down: but new %d >= old %d uV\n", vdd_mx_vmin,
-			       cpr_vreg->vdd_mx_vmin);
-		}
+	cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
 
-		rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
-					   cpr_vreg->vdd_mx_vmax);
-		if (!rc) {
-			cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
-		} else {
-			pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
-			       min_uV, vdd_mx_vmin, rc);
-			return rc;
-		}
+	if (corner > cpr_vreg->corner)
+		change_dir = UP;
+	else if (corner < cpr_vreg->corner)
+		change_dir = DOWN;
+
+	rc = cpr_scale_voltage(cpr_vreg, corner, new_volt, change_dir);
+	if (rc)
+		goto _exit;
+
+	if (cpr_is_allowed(cpr_vreg)) {
+		cpr_irq_clr(cpr_vreg);
+		cpr_corner_switch(cpr_vreg, corner);
+		cpr_ctl_enable(cpr_vreg);
 	}
 
-	pr_debug("set [corner:%d] = %d uV: rc=%d\n", min_uV, vdd_apc_min, rc);
+	cpr_vreg->corner = corner;
+
+_exit:
+	mutex_unlock(&cpr_vreg->cpr_mutex);
+
 	return rc;
 }
 
@@ -209,56 +762,202 @@
 	.get_voltage		= cpr_regulator_get_voltage,
 };
 
-static int __init cpr_regulator_pvs_init(struct cpr_regulator *cpr_vreg)
+#ifdef CONFIG_PM
+static int cpr_suspend(struct cpr_regulator *cpr_vreg)
+{
+	cpr_debug("suspend\n");
+
+	cpr_ctl_disable(cpr_vreg);
+	disable_irq(cpr_vreg->cpr_irq);
+
+	cpr_irq_clr(cpr_vreg);
+	cpr_regs_save(cpr_vreg);
+
+	return 0;
+}
+
+static int cpr_resume(struct cpr_regulator *cpr_vreg)
+
+{
+	cpr_debug("resume\n");
+
+	cpr_regs_restore(cpr_vreg);
+	cpr_irq_clr(cpr_vreg);
+
+	enable_irq(cpr_vreg->cpr_irq);
+	cpr_ctl_enable(cpr_vreg);
+
+	return 0;
+}
+
+static int cpr_regulator_suspend(struct platform_device *pdev,
+				 pm_message_t state)
+{
+	struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+	if (cpr_is_allowed(cpr_vreg))
+		return cpr_suspend(cpr_vreg);
+	else
+		return 0;
+}
+
+static int cpr_regulator_resume(struct platform_device *pdev)
+{
+	struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+	if (cpr_is_allowed(cpr_vreg))
+		return cpr_resume(cpr_vreg);
+	else
+		return 0;
+}
+#else
+#define cpr_regulator_suspend NULL
+#define cpr_regulator_resume NULL
+#endif
+
+static void cpr_config(struct cpr_regulator *cpr_vreg)
+{
+	int i;
+	u32 val, gcnt;
+
+	/* Disable interrupt and CPR */
+	cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
+	cpr_write(cpr_vreg, REG_RBCPR_CTL, 0);
+
+	/* Program the default HW Ceiling, Floor and vlevel */
+	val = ((RBIF_LIMIT_CEILING_DEFAULT & RBIF_LIMIT_CEILING_MASK)
+			<< RBIF_LIMIT_CEILING_SHIFT)
+		| (RBIF_LIMIT_FLOOR_DEFAULT & RBIF_LIMIT_FLOOR_MASK);
+	cpr_write(cpr_vreg, REG_RBIF_LIMIT, val);
+	cpr_write(cpr_vreg, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
+
+	/* Clear the target quotient value and gate count of all ROs */
+	for (i = 0; i < CPR_NUM_RING_OSC; i++)
+		cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
+
+	/* Init and save gcnt */
+	gcnt = (cpr_vreg->ref_clk_khz * cpr_vreg->gcnt_time_us) / 1000;
+	gcnt = (gcnt & RBCPR_GCNT_TARGET_GCNT_MASK) <<
+			RBCPR_GCNT_TARGET_GCNT_SHIFT;
+	cpr_vreg->gcnt = gcnt;
+
+	/* Program the step quotient and idle clocks */
+	val = ((cpr_vreg->idle_clocks & RBCPR_STEP_QUOT_IDLE_CLK_MASK)
+			<< RBCPR_STEP_QUOT_IDLE_CLK_SHIFT) |
+		(cpr_vreg->step_quotient & RBCPR_STEP_QUOT_STEPQUOT_MASK);
+	cpr_write(cpr_vreg, REG_RBCPR_STEP_QUOT, val);
+
+	/* Program the delay count for the timer */
+	val = (cpr_vreg->ref_clk_khz * cpr_vreg->timer_delay_us) / 1000;
+	cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, val);
+	pr_info("Timer count: 0x%0x (for %d us)\n", val,
+		cpr_vreg->timer_delay_us);
+
+	/* Program Consecutive Up & Down */
+	val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
+			<< RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
+		(cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
+	cpr_write(cpr_vreg, REG_RBIF_TIMER_ADJUST, val);
+
+	/* Program the control register */
+	cpr_vreg->up_threshold &= RBCPR_CTL_UP_THRESHOLD_MASK;
+	cpr_vreg->down_threshold &= RBCPR_CTL_DN_THRESHOLD_MASK;
+	val = (cpr_vreg->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT)
+		| (cpr_vreg->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT);
+	val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
+	val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
+	cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
+
+	/* Registers to save & restore for suspend */
+	cpr_vreg->save_regs[0] = REG_RBCPR_TIMER_INTERVAL;
+	cpr_vreg->save_regs[1] = REG_RBCPR_STEP_QUOT;
+	cpr_vreg->save_regs[2] = REG_RBIF_TIMER_ADJUST;
+	cpr_vreg->save_regs[3] = REG_RBIF_LIMIT;
+	cpr_vreg->save_regs[4] = REG_RBIF_SW_VLEVEL;
+	cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
+	cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
+	cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+	cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+	cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+
+	cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+	cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
+	cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
+	cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+}
+
+static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
 {
 	void __iomem *efuse_base;
-	u32 efuse_bits;
-	int i, bit_pos;
-	u32 vmax;
+	u32 efuse_bits, redundant, shift, mask;
+	int i, process;
 
-	efuse_base = ioremap(cpr_vreg->efuse_phys, 4);
+	efuse_base = ioremap(cpr_vreg->pvs_efuse, 4);
 	if (!efuse_base) {
-		pr_err("Unable to map efuse_phys 0x%x\n",
-				cpr_vreg->efuse_phys);
+		pr_err("Unable to map pvs_efuse 0x%08x\n",
+				cpr_vreg->pvs_efuse);
 		return -EINVAL;
 	}
 
 	efuse_bits = readl_relaxed(efuse_base);
 
 	/* Construct PVS process # from the efuse bits */
-	for (i = 0; i < cpr_vreg->num_efuse_bits; i++) {
-		bit_pos = cpr_vreg->efuse_bit_pos[i];
-		cpr_vreg->pvs_bin |= (efuse_bits & BIT(bit_pos)) ? BIT(i) : 0;
-	}
+	redundant = (efuse_bits >> PVS_FUSE_REDUNDANT_SHIFT)
+			& PVS_FUSE_REDUNDANT_MASK;
+	if (redundant == 2)
+		shift = PVS_FUSE_BINS_REDUNDANT_SHIFT;
+	else
+		shift = PVS_FUSE_BINS_SHIFT;
+	mask = (1 << cpr_vreg->num_efuse_bits) - 1;
+	cpr_vreg->pvs_bin = (efuse_bits >> shift) & mask;
 
-	cpr_vreg->pvs_process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	if (cpr_vreg->pvs_process >= NUM_APC_PVS)
-		cpr_vreg->pvs_process = APC_PVS_NO;
-
-	/* Use ceiling voltage of Turbo@Slow for all corners of APC_PVS_NO
-	   but use SuperTurbo@Slow for its SuperTurbo */
-	vmax = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_TURBO];
-	for (i = CPR_CORNER_SVS; i <= CPR_CORNER_TURBO; i++)
-		cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][i] = vmax;
-	cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][CPR_CORNER_SUPER_TURBO]
-		= cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW]
-					[CPR_CORNER_SUPER_TURBO];
-
-	cpr_vreg->corner_ceiling =
-		cpr_vreg->pvs_corner_ceiling[cpr_vreg->pvs_process];
+	/* Set ceiling max and use it for APC_PVS_NO */
+	cpr_vreg->ceiling_max =
+		cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
 
 	iounmap(efuse_base);
 
-	pr_info("PVS Info: efuse_phys=0x%08X, n_bits=%d\n",
-		cpr_vreg->efuse_phys, cpr_vreg->num_efuse_bits);
-	pr_info("PVS Info: efuse=0x%08X, bin=%d, process=%d\n",
-		efuse_bits, cpr_vreg->pvs_bin, cpr_vreg->pvs_process);
+	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
+	pr_info("[0x%08X] = 0x%08X, n_bits=%d, bin=%d (%d) [redundant=%d]\n",
+		cpr_vreg->pvs_efuse, efuse_bits, cpr_vreg->num_efuse_bits,
+		cpr_vreg->pvs_bin, process, redundant);
+	for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
+		pr_info("[%d] [%d %d %d] uV\n", i,
+			cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
+			cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
+			cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+	}
+
+	if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
+		pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
+		       cpr_vreg->pvs_bin, process);
+		process = APC_PVS_SLOW;
+	}
+
+	cpr_vreg->process = process;
 
 	return 0;
 }
 
-static int __init cpr_regulator_apc_init(struct platform_device *pdev,
-					 struct cpr_regulator *cpr_vreg)
+#define CPR_PROP_READ_U32(of_node, cpr_property, cpr_config, rc)	\
+do {									\
+	if (!rc) {							\
+		rc = of_property_read_u32(of_node,			\
+				"qcom," cpr_property,			\
+				cpr_config);				\
+		if (rc) {						\
+			pr_err("Missing " #cpr_property			\
+				": rc = %d\n", rc);			\
+		}							\
+	}								\
+} while (0)
+
+static int __init cpr_apc_init(struct platform_device *pdev,
+			       struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
 	int rc;
@@ -308,9 +1007,9 @@
 	return 0;
 }
 
-static void cpr_regulator_apc_exit(struct cpr_regulator *cpr_vreg)
+static void cpr_apc_exit(struct cpr_regulator *cpr_vreg)
 {
-	if (cpr_vreg->enabled) {
+	if (cpr_vreg->vreg_enabled) {
 		regulator_disable(cpr_vreg->vdd_apc);
 
 		if (cpr_vreg->vdd_mx)
@@ -318,8 +1017,231 @@
 	}
 }
 
-static int __init cpr_regulator_parse_dt(struct platform_device *pdev,
-					 struct cpr_regulator *cpr_vreg)
+static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
+{
+	void __iomem *efuse_base;
+	u32 ro_sel, val;
+	u64 fuse_bits;
+	int ro_sel_shift[CPR_CORNER_MAX];
+
+	efuse_base = ioremap(cpr_vreg->cpr_fuse_addr, 16);
+	if (!efuse_base) {
+		pr_err("Unable to map cpr_fuse_addr 0x%08x\n",
+				cpr_vreg->cpr_fuse_addr);
+		return -EINVAL;
+	}
+
+	cpr_vreg->cpr_fuse_bits = readll_relaxed(efuse_base);
+	cpr_vreg->cpr_fuse_bits_2 = readll_relaxed(efuse_base + 8);
+
+	iounmap(efuse_base);
+
+	/* Read the control bits of eFuse */
+	cpr_vreg->cpr_fuse_disable = (cpr_vreg->cpr_fuse_bits >>
+				      CPR_FUSE_DISABLE_CPR_SHIFT) & 0x01;
+	cpr_vreg->cpr_fuse_local = (cpr_vreg->cpr_fuse_bits >>
+				    CPR_FUSE_LOCAL_APPROACH_SHIFT) & 0x01;
+	cpr_vreg->cpr_fuse_redundancy = (cpr_vreg->cpr_fuse_bits >>
+					 CPR_FUSE_REDUNDANT_SHIFT) & 0x01;
+
+	pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr,
+		cpr_vreg->cpr_fuse_bits);
+	pr_info("disable = %d, local = %d, redundancy = %d\n",
+			cpr_vreg->cpr_fuse_disable,
+			cpr_vreg->cpr_fuse_local,
+			cpr_vreg->cpr_fuse_redundancy);
+	pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr + 8,
+		cpr_vreg->cpr_fuse_bits_2);
+
+	if (cpr_vreg->cpr_fuse_redundancy == 0) {
+		fuse_bits = cpr_vreg->cpr_fuse_bits;
+		ro_sel_shift[CPR_CORNER_SVS] = 54;
+		ro_sel_shift[CPR_CORNER_NORMAL] = 38;
+		ro_sel_shift[CPR_CORNER_TURBO] = 41;
+	} else {
+		fuse_bits = cpr_vreg->cpr_fuse_bits_2;
+		ro_sel_shift[CPR_CORNER_SVS] = 46;
+		ro_sel_shift[CPR_CORNER_NORMAL] = 36;
+		ro_sel_shift[CPR_CORNER_TURBO] = 39;
+	}
+
+	/* SVS */
+	ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_SVS])
+				& CPR_FUSE_RO_SEL_BITS_MASK;
+	val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_SVS_SHIFT)
+				& CPR_FUSE_TARGET_QUOT_BITS_MASK;
+	cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_SVS] = val;
+	cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS] = ro_sel;
+	pr_info("SVS: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+	/* Nominal */
+	ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_NORMAL])
+				& CPR_FUSE_RO_SEL_BITS_MASK;
+	val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT)
+				& CPR_FUSE_TARGET_QUOT_BITS_MASK;
+	cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_NORMAL] = val;
+	cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL] = ro_sel;
+	pr_info("Nominal: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+	/* Turbo */
+	ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_TURBO])
+				& CPR_FUSE_RO_SEL_BITS_MASK;
+	val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_TURBO_SHIFT)
+				& CPR_FUSE_TARGET_QUOT_BITS_MASK;
+	cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_TURBO] = val;
+	cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO] = ro_sel;
+	pr_info("Turbo: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+	if (!cpr_vreg->cpr_fuse_bits) {
+		cpr_vreg->cpr_fuse_disable = 1;
+		pr_err("cpr_fuse_bits = 0: set cpr_fuse_disable = 1\n");
+	}
+
+	return 0;
+}
+
+static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+{
+	int i;
+
+	/* Construct CPR voltage limits */
+	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+		cpr_vreg->floor_volt[i] =
+			cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
+		cpr_vreg->ceiling_volt[i] =
+			cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
+		cpr_vreg->last_volt[i] =
+			cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+	}
+
+	return 0;
+}
+
+static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
+					  struct cpr_regulator *cpr_vreg)
+{
+	struct device_node *of_node = pdev->dev.of_node;
+	int rc = 0;
+
+	CPR_PROP_READ_U32(of_node, "cpr-ref-clk",
+			  &cpr_vreg->ref_clk_khz, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-timer-delay",
+			  &cpr_vreg->timer_delay_us, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-timer-cons-up",
+			  &cpr_vreg->timer_cons_up, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-timer-cons-down",
+			  &cpr_vreg->timer_cons_down, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-irq-line",
+			  &cpr_vreg->irq_line, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-step-quotient",
+			  &cpr_vreg->step_quotient, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-up-threshold",
+			  &cpr_vreg->up_threshold, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-down-threshold",
+			  &cpr_vreg->down_threshold, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-idle-clocks",
+			  &cpr_vreg->idle_clocks, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-gcnt-time",
+			  &cpr_vreg->gcnt_time_us, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "vdd-apc-step-up-limit",
+			  &cpr_vreg->vdd_apc_step_up_limit, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "vdd-apc-step-down-limit",
+			  &cpr_vreg->vdd_apc_step_down_limit, rc);
+	if (rc)
+		return rc;
+	CPR_PROP_READ_U32(of_node, "cpr-apc-volt-step",
+			  &cpr_vreg->step_volt, rc);
+	if (rc)
+		return rc;
+
+	/* Init module parameter with the DT value */
+	cpr_vreg->enable = of_property_read_bool(of_node, "qcom,cpr-enable");
+	cpr_enable = (int) cpr_vreg->enable;
+	pr_info("CPR is %s by default.\n",
+		cpr_vreg->enable ? "enabled" : "disabled");
+
+	return rc;
+}
+
+static int __init cpr_init_cpr(struct platform_device *pdev,
+			       struct cpr_regulator *cpr_vreg)
+{
+	struct resource *res;
+	int rc = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "cpr_efuse");
+	if (!res || !res->start) {
+		pr_err("cpr_efuse missing: res=%p\n", res);
+		return -EINVAL;
+	}
+	cpr_vreg->cpr_fuse_addr = res->start;
+
+	rc = cpr_init_cpr_efuse(cpr_vreg);
+	if (rc)
+		return rc;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr");
+	if (!res || !res->start) {
+		pr_err("missing rbcpr address: res=%p\n", res);
+		return -EINVAL;
+	}
+	cpr_vreg->rbcpr_base = devm_ioremap(&pdev->dev, res->start,
+					    resource_size(res));
+
+	/* Init all voltage set points of APC regulator for CPR */
+	cpr_init_cpr_voltages(cpr_vreg);
+
+	/* Init CPR configuration parameters */
+	rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
+	if (rc)
+		return rc;
+
+	/* Get and Init interrupt */
+	cpr_vreg->cpr_irq = platform_get_irq(pdev, 0);
+	if (!cpr_vreg->cpr_irq) {
+		pr_err("missing CPR IRQ\n");
+		return -EINVAL;
+	}
+
+	/* Configure CPR HW but keep it disabled */
+	cpr_config(cpr_vreg);
+
+	rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
+				  IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
+	if (rc) {
+		pr_err("CPR: request irq failed for IRQ %d\n",
+				cpr_vreg->cpr_irq);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
+				   struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
 	struct resource *res;
@@ -327,13 +1249,12 @@
 	size_t pvs_bins;
 
 	/* Parse process voltage parameters */
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-					   "efuse_phys");
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pvs_efuse");
 	if (!res || !res->start) {
-		pr_err("efuse_phys missing: res=%p\n", res);
+		pr_err("pvs_efuse missing: res=%p\n", res);
 		return -EINVAL;
 	}
-	cpr_vreg->efuse_phys = res->start;
+	cpr_vreg->pvs_efuse = res->start;
 
 	rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
 				&cpr_vreg->num_efuse_bits);
@@ -349,14 +1270,6 @@
 		return -EINVAL;
 	}
 
-	rc = of_property_read_u32_array(of_node, "qcom,efuse-bit-pos",
-					cpr_vreg->efuse_bit_pos,
-					cpr_vreg->num_efuse_bits);
-	if (rc < 0) {
-		pr_err("efuse-bit-pos missing: rc=%d\n", rc);
-		return rc;
-	}
-
 	pvs_bins = 1 << cpr_vreg->num_efuse_bits;
 	rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
 					cpr_vreg->pvs_bin_process,
@@ -368,7 +1281,7 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qcom,pvs-corner-ceiling-slow",
-		&cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_SVS],
+		&cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
 		CPR_CORNER_MAX - CPR_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
@@ -377,7 +1290,7 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qcom,pvs-corner-ceiling-nom",
-		&cpr_vreg->pvs_corner_ceiling[APC_PVS_NOM][CPR_CORNER_SVS],
+		&cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
 		CPR_CORNER_MAX - CPR_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
@@ -386,7 +1299,7 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qcom,pvs-corner-ceiling-fast",
-		&cpr_vreg->pvs_corner_ceiling[APC_PVS_FAST][CPR_CORNER_SVS],
+		&cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
 		CPR_CORNER_MAX - CPR_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
@@ -426,25 +1339,33 @@
 		return -ENOMEM;
 	}
 
-	rc = cpr_regulator_parse_dt(pdev, cpr_vreg);
+	rc = cpr_pvs_parse_dt(pdev, cpr_vreg);
 	if (rc) {
 		pr_err("Wrong DT parameter specified: rc=%d\n", rc);
 		return rc;
 	}
 
-	rc = cpr_regulator_pvs_init(cpr_vreg);
+	rc = cpr_pvs_init(cpr_vreg);
 	if (rc) {
 		pr_err("Initialize PVS wrong: rc=%d\n", rc);
 		return rc;
 	}
 
-	rc = cpr_regulator_apc_init(pdev, cpr_vreg);
+	rc = cpr_apc_init(pdev, cpr_vreg);
 	if (rc) {
 		if (rc != -EPROBE_DEFER)
 			pr_err("Initialize APC wrong: rc=%d\n", rc);
 		return rc;
 	}
 
+	rc = cpr_init_cpr(pdev, cpr_vreg);
+	if (rc) {
+		pr_err("Initialize CPR failed: rc=%d\n", rc);
+		return rc;
+	}
+
+	mutex_init(&cpr_vreg->cpr_mutex);
+
 	rdesc			= &cpr_vreg->rdesc;
 	rdesc->owner		= THIS_MODULE;
 	rdesc->type		= REGULATOR_VOLTAGE;
@@ -457,17 +1378,12 @@
 		rc = PTR_ERR(cpr_vreg->rdev);
 		pr_err("regulator_register failed: rc=%d\n", rc);
 
-		cpr_regulator_apc_exit(cpr_vreg);
+		cpr_apc_exit(cpr_vreg);
 		return rc;
 	}
 
 	platform_set_drvdata(pdev, cpr_vreg);
-
-	pr_info("PVS [%d %d %d %d] uV\n",
-		cpr_vreg->corner_ceiling[CPR_CORNER_SVS],
-		cpr_vreg->corner_ceiling[CPR_CORNER_NORMAL],
-		cpr_vreg->corner_ceiling[CPR_CORNER_TURBO],
-		cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO]);
+	the_cpr = cpr_vreg;
 
 	return 0;
 }
@@ -478,7 +1394,13 @@
 
 	cpr_vreg = platform_get_drvdata(pdev);
 	if (cpr_vreg) {
-		cpr_regulator_apc_exit(cpr_vreg);
+		/* Disable CPR */
+		if (cpr_is_allowed(cpr_vreg)) {
+			cpr_ctl_disable(cpr_vreg);
+			cpr_irq_set(cpr_vreg, 0);
+		}
+
+		cpr_apc_exit(cpr_vreg);
 		regulator_unregister(cpr_vreg->rdev);
 	}
 
@@ -498,6 +1420,8 @@
 	},
 	.probe		= cpr_regulator_probe,
 	.remove		= __devexit_p(cpr_regulator_remove),
+	.suspend	= cpr_regulator_suspend,
+	.resume		= cpr_regulator_resume,
 };
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 893db0b..35b1f76 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -41,7 +41,8 @@
  * @powerup: Start a subsystem
  * @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
  * @ramdump: Collect a ramdump of the subsystem
- * @is_loadable: Indicate if subsystem firmware is loadable via pil framework
+ * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil
+ * framework
  */
 struct subsys_desc {
 	const char *name;
@@ -57,7 +58,7 @@
 	void (*crash_shutdown)(const struct subsys_desc *desc);
 	int (*ramdump)(int, const struct subsys_desc *desc);
 	unsigned int err_ready_irq;
-	int is_loadable;
+	int is_not_loadable;
 };
 
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9e0be63..1a919fc 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.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
@@ -1026,6 +1026,9 @@
 	uint32_t ret1;
 	uint32_t ret2;
 
+	if (!msm_dcvs_enabled)
+		return ret;
+
 	offset = get_core_offset(type, type_core_num);
 	if (offset < 0)
 		return ret;
@@ -1277,6 +1280,9 @@
 	struct kobject *module_kobj = NULL;
 	int ret = 0;
 
+	if (!msm_dcvs_enabled)
+		return ret;
+
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
 	if (!module_kobj) {
 		pr_err("%s: cannot find kobject for module %s\n",
@@ -1343,6 +1349,7 @@
 	ret = msm_dcvs_scm_init(SZ_32K);
 	if (ret) {
 		__err("Unable to initialize DCVS err=%d\n", ret);
+		msm_dcvs_enabled = 0;
 		goto done;
 	}
 
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index e993282..979458e 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -104,13 +104,15 @@
 
 static int pil_mss_power_up(struct q6v5_data *drv)
 {
-	int ret;
+	int ret = 0;
 	struct device *dev = drv->desc.dev;
 	u32 regval;
 
-	ret = regulator_enable(drv->vreg);
-	if (ret)
-		dev_err(dev, "Failed to enable modem regulator.\n");
+	if (drv->vreg) {
+		ret = regulator_enable(drv->vreg);
+		if (ret)
+			dev_err(dev, "Failed to enable modem regulator.\n");
+	}
 
 	if (drv->cxrail_bhs) {
 		regval = readl_relaxed(drv->cxrail_bhs);
@@ -134,7 +136,10 @@
 		writel_relaxed(regval, drv->cxrail_bhs);
 	}
 
-	return regulator_disable(drv->vreg);
+	if (drv->vreg)
+		return regulator_disable(drv->vreg);
+
+	return 0;
 }
 
 static int pil_mss_enable_clks(struct q6v5_data *drv)
@@ -501,7 +506,7 @@
 {
 	struct mba_data *drv = subsys_to_drv(subsys);
 
-	if (!subsys->is_loadable)
+	if (subsys->is_not_loadable)
 		return 0;
 	pil_shutdown(&drv->desc);
 	pil_shutdown(&drv->q6->desc);
@@ -513,7 +518,7 @@
 	struct mba_data *drv = subsys_to_drv(subsys);
 	int ret;
 
-	if (!subsys->is_loadable)
+	if (subsys->is_not_loadable)
 		return 0;
 	/*
 	 * At this time, the modem is shutdown. Therefore this function cannot
@@ -600,7 +605,7 @@
 	int ret;
 	struct mba_data *drv = subsys_to_drv(desc);
 
-	if (!desc->is_loadable)
+	if (desc->is_not_loadable)
 		return 0;
 
 	ret = pil_boot(&drv->q6->desc);
@@ -623,7 +628,7 @@
 {
 	struct mba_data *drv = subsys_to_drv(desc);
 
-	if (!desc->is_loadable)
+	if (desc->is_not_loadable)
 		return;
 
 	pil_shutdown(&drv->desc);
@@ -724,6 +729,7 @@
 	struct q6v5_data *q6;
 	struct pil_desc *q6_desc, *mba_desc;
 	struct resource *res;
+	struct property *prop;
 	int ret;
 
 	int clk_ready = of_get_named_gpio(pdev->dev.of_node,
@@ -761,31 +767,36 @@
 	if (!q6->restart_reg)
 		return -ENOMEM;
 
-	q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
-	if (IS_ERR(q6->vreg))
-		return PTR_ERR(q6->vreg);
+	q6->vreg = NULL;
+
+	prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
+	if (prop) {
+		q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+		if (IS_ERR(q6->vreg))
+			return PTR_ERR(q6->vreg);
+
+		ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV,
+						MAX_VDD_MSS_UV);
+		if (ret)
+			dev_err(&pdev->dev, "Failed to set vreg voltage.\n");
+
+		ret = regulator_set_optimum_mode(q6->vreg, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Failed to set vreg mode.\n");
+			return ret;
+		}
+	}
 
 	q6->vreg_mx = devm_regulator_get(&pdev->dev, "vdd_mx");
 	if (IS_ERR(q6->vreg_mx))
 		return PTR_ERR(q6->vreg_mx);
 
-	ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV, MAX_VDD_MSS_UV);
-	if (ret)
-		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
-
-	ret = regulator_set_optimum_mode(q6->vreg, 100000);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
-		return ret;
-	}
-
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 		"cxrail_bhs_reg");
 	if (res)
 		q6->cxrail_bhs = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 
-
 	q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
 	if (IS_ERR(q6->ahb_clk))
 		return PTR_ERR(q6->ahb_clk);
@@ -825,17 +836,18 @@
 static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
 {
 	struct mba_data *drv;
-	int ret, err_fatal_gpio, is_loadable;
+	int ret, err_fatal_gpio, is_not_loadable;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	is_loadable = of_property_read_bool(pdev->dev.of_node,
-							"qcom,is-loadable");
-	if (is_loadable) {
-		drv->subsys_desc.is_loadable = 1;
+	is_not_loadable = of_property_read_bool(pdev->dev.of_node,
+							"qcom,is-not-loadable");
+	if (is_not_loadable) {
+		drv->subsys_desc.is_not_loadable = 1;
+	} else {
 		ret = pil_mss_loadable_init(drv, pdev);
 		if (ret)
 			return ret;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ea22c12..b5ccc31 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -786,7 +786,7 @@
 		goto done;
 	}
 
-	if (size <= 0) {
+	if ((size <= 0) || (size > sizeof(data))) {
 		pr_err("%s: Invalid size sent to driver: %d\n",
 			__func__, size);
 		result = -EFAULT;
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index c9bc3d7..5303009 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -22,10 +22,15 @@
 #include <linux/of_device.h>
 #include <linux/msm_audio_ion.h>
 
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+
 struct msm_audio_ion_private {
 	bool smmu_enabled;
-	/*u32 group_id;*/
-	/*u32 domain_id;*/
+	bool audioheap_enabled;
+	struct iommu_group *group;
+	u32 domain_id;
+	struct iommu_domain *domain;
 };
 
 static struct msm_audio_ion_private msm_audio_ion_data = {0,};
@@ -49,10 +54,22 @@
 		goto err;
 	}
 
-	*handle = ion_alloc(*client, bufsz, SZ_4K, (0x1<<ION_AUDIO_HEAP_ID), 0);
+	*handle = ion_alloc(*client, bufsz, SZ_4K,
+			ION_HEAP(ION_AUDIO_HEAP_ID), 0);
 	if (IS_ERR_OR_NULL((void *) (*handle))) {
-		pr_err("%s: ION memory allocation for AUDIO failed\n",
-			__func__);
+		pr_debug("system heap is used");
+		msm_audio_ion_data.audioheap_enabled = 0;
+		*handle = ion_alloc(*client, bufsz, SZ_4K,
+				ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+
+	} else {
+		pr_debug("audio heap is used");
+		msm_audio_ion_data.audioheap_enabled = 1;
+	}
+
+	if (IS_ERR_OR_NULL((void *) (*handle))) {
+		pr_err("%s: ION memory allocation for AUDIO failed rc=%d, smmu_enabled=%d\n",
+			__func__, rc, msm_audio_ion_data.smmu_enabled);
 		goto err_ion_client;
 	}
 
@@ -63,15 +80,17 @@
 		goto err_ion_handle;
 	}
 
-	/*Need to add condition SMMU enable or not */
 	*vaddr = ion_map_kernel(*client, *handle);
 	if (IS_ERR_OR_NULL((void *)*vaddr)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
 		goto err_ion_handle;
 	}
+	pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
 
-	if (bufsz != 0)
+	if (bufsz != 0) {
+		pr_debug("%s: memset to 0 %p %d\n", __func__, *vaddr, bufsz);
 		memset((void *)*vaddr, 0, bufsz);
+	}
 
 	return 0;
 
@@ -81,7 +100,6 @@
 	msm_audio_ion_client_destroy(*client);
 err:
 	return -EINVAL;
-
 }
 
 int msm_audio_ion_import(const char *name, struct ion_client **client,
@@ -125,13 +143,6 @@
 		goto err_ion_handle;
 	}
 
-	/*Need to add condition SMMU enable or not */
-	*vaddr = ion_map_kernel(*client, *handle);
-	if (IS_ERR_OR_NULL((void *)*vaddr)) {
-		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
-		goto err_ion_handle;
-	}
-
 	if (bufsz != 0)
 		memset((void *)*vaddr, 0, bufsz);
 
@@ -142,12 +153,20 @@
 	msm_audio_ion_client_destroy(*client);
 err:
 	return -EINVAL;
-
 }
 
 int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
 {
-	/* add condition for SMMU enabled */
+	if (msm_audio_ion_data.smmu_enabled) {
+		/* Need to populate book kept infomation */
+		pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+			client, msm_audio_ion_data.domain,
+			msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+		ion_unmap_iommu(client, handle,
+				msm_audio_ion_data.domain_id, 0);
+	}
+
 	ion_unmap_kernel(client, handle);
 
 	ion_free(client, handle);
@@ -155,6 +174,91 @@
 	return 0;
 }
 
+int msm_audio_ion_mmap(struct audio_buffer *ab,
+		       struct vm_area_struct *vma)
+{
+	struct sg_table *table;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+	struct scatterlist *sg;
+	unsigned int i;
+	struct page *page;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+
+	table = ion_sg_table(ab->client, ab->handle);
+
+	if (IS_ERR(table)) {
+		pr_err("%s: Unable to get sg_table from ion: %ld\n",
+			__func__, PTR_ERR(table));
+		return PTR_ERR(table);
+	} else if (!table) {
+		pr_err("%s: sg_list is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	/* uncached */
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	/* We need to check if a page is associated with this sg list because:
+	 * If the allocation came from a carveout we currently don't have
+	 * pages associated with carved out memory. This might change in the
+	 * future and we can remove this check and the else statement.
+	 */
+	page = sg_page(table->sgl);
+	if (page) {
+		pr_debug("%s: page is NOT null\n", __func__);
+		for_each_sg(table->sgl, sg, table->nents, i) {
+			unsigned long remainder = vma->vm_end - addr;
+			unsigned long len = sg_dma_len(sg);
+
+			page = sg_page(sg);
+
+			if (offset >= sg_dma_len(sg)) {
+				offset -= sg_dma_len(sg);
+				continue;
+			} else if (offset) {
+				page += offset / PAGE_SIZE;
+				len = sg_dma_len(sg) - offset;
+				offset = 0;
+			}
+			len = min(len, remainder);
+			pr_debug("vma=%p, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+				vma, (unsigned int)addr, len,
+				(unsigned int)vma->vm_start,
+				(unsigned int)vma->vm_end,
+				(unsigned long int)vma->vm_page_prot);
+			remap_pfn_range(vma, addr, page_to_pfn(page), len,
+					vma->vm_page_prot);
+			addr += len;
+			if (addr >= vma->vm_end)
+				return 0;
+		}
+	} else {
+		ion_phys_addr_t phys_addr;
+		size_t phys_len;
+		pr_debug("%s: page is NULL\n", __func__);
+
+		ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
+		if (ret) {
+			pr_err("%s: Unable to get phys address from ION buffer: %d\n"
+				, __func__ , ret);
+			return ret;
+		}
+		pr_debug("phys=%x len=%d\n", (unsigned int)phys_addr, phys_len);
+		pr_debug("vma=%p, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
+			vma, (unsigned int)vma->vm_start,
+			(unsigned int)vma->vm_end, vma->vm_pgoff,
+			(unsigned long int)vma->vm_page_prot);
+		ret =  remap_pfn_range(vma, vma->vm_start,
+				__phys_to_pfn(phys_addr) + vma->vm_pgoff,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot);
+	}
+	return 0;
+}
+
 
 bool msm_audio_ion_is_smmu_available(void)
 {
@@ -165,18 +269,17 @@
 struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
 					const char *name)
 {
-	pr_debug("%s: smmu_enabled = %d\n", __func__,
-					msm_audio_ion_data.smmu_enabled);
-
-
-	return msm_ion_client_create(heap_mask, name);
+	struct ion_client *pclient = NULL;
+	/*IOMMU group and domain are moved to probe()*/
+	pclient = msm_ion_client_create(heap_mask, name);
+	return pclient;
 }
 
 
 void msm_audio_ion_client_destroy(struct ion_client *client)
 {
-	pr_debug("%s: smmu_enabled = %d\n", __func__,
-		msm_audio_ion_data.smmu_enabled);
+	pr_debug("%s: client = %p smmu_enabled = %d\n", __func__,
+		client, msm_audio_ion_data.smmu_enabled);
 
 	ion_client_destroy(client);
 }
@@ -192,9 +295,9 @@
 	bufsz should be 0 and fd shouldn't be 0 as of now
 	*/
 	*handle = ion_import_dma_buf(client, fd);
-	pr_err("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
+	pr_debug("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
 							name, fd, *handle);
-	if (IS_ERR_OR_NULL((void *) (*handle))) {
+	if (IS_ERR_OR_NULL((void *)(*handle))) {
 		pr_err("%s: ion import dma buffer failed\n",
 			__func__);
 		goto err_ion_handle;
@@ -245,6 +348,41 @@
 	return 0;
 }
 
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
+{
+	unsigned long ionflag = 0;
+	int rc = 0;
+	int msm_cache_ops = 0;
+
+	if (!abuff) {
+		pr_err("Invalid params: %p, %p\n", __func__, abuff);
+		return -EINVAL;
+	}
+	rc = ion_handle_get_flags(abuff->client, abuff->handle,
+		&ionflag);
+	if (rc) {
+		pr_err("ion_handle_get_flags failed: %d\n", rc);
+		goto cache_op_failed;
+	}
+
+	/* has to be CACHED */
+	if (ION_IS_CACHED(ionflag)) {
+		/* ION_IOC_INV_CACHES or ION_IOC_CLEAN_CACHES */
+		msm_cache_ops = cache_op;
+		rc = msm_ion_do_cache_op(abuff->client,
+				abuff->handle,
+				(unsigned long *) abuff->data,
+				(unsigned long)abuff->size,
+				msm_cache_ops);
+		if (rc) {
+			pr_err("cache operation failed %d\n", rc);
+			goto cache_op_failed;
+		}
+	}
+cache_op_failed:
+	return rc;
+}
+
 
 static int msm_audio_ion_get_phys(struct ion_client *client,
 		struct ion_handle *handle,
@@ -255,18 +393,25 @@
 		msm_audio_ion_data.smmu_enabled);
 
 	if (msm_audio_ion_data.smmu_enabled) {
-		/* SMMU enabled case ion_map_iommu()*/
+		rc = ion_map_iommu(client, handle, msm_audio_ion_data.domain_id,
+			0 /*partition_num*/, SZ_4K /*align*/, 0/*iova_length*/,
+			addr, (unsigned long *)len,
+			0, 0);
+		if (rc) {
+			pr_err("%s: ION map iommu failed %d\n", __func__, rc);
+			return rc;
+		}
+		pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+			client, msm_audio_ion_data.domain,
+			msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
 	} else {
 		/* SMMU is disabled*/
 		rc = ion_phys(client, handle, addr, len);
 	}
-	pr_debug("%s: addr= 0x%p, len= %d\n", __func__, addr, *len);
+	pr_debug("phys=%x, len=%d, rc=%d\n", (unsigned int)*addr, *len, rc);
 	return rc;
 }
 
-
-
-
 static int msm_audio_ion_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -283,13 +428,53 @@
 					     msm_audio_ion_dt);
 	msm_audio_ion_data.smmu_enabled = smmu_enabled;
 
+	if (smmu_enabled) {
+		msm_audio_ion_data.group = iommu_group_find("lpass_audio");
+		if (!msm_audio_ion_data.group) {
+			pr_debug("Failed to find group lpass_audio deferred\n");
+			goto fail_group;
+		}
+		msm_audio_ion_data.domain =
+			iommu_group_get_iommudata(msm_audio_ion_data.group);
+		if (IS_ERR_OR_NULL(msm_audio_ion_data.domain)) {
+			pr_err("Failed to get domain data for group %p",
+					msm_audio_ion_data.group);
+			goto fail_group;
+		}
+		msm_audio_ion_data.domain_id =
+				msm_find_domain_no(msm_audio_ion_data.domain);
+		if (msm_audio_ion_data.domain_id < 0) {
+			pr_err("Failed to get domain index for domain %p",
+					msm_audio_ion_data.domain);
+			goto fail_group;
+		}
+		pr_debug("domain=%p, domain_id=%d, group=%p",
+			msm_audio_ion_data.domain,
+			msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+		/* iommu_attach_group() will make AXI clock ON. For future PL
+		this will require to be called in once per session */
+		rc = iommu_attach_group(msm_audio_ion_data.domain,
+					msm_audio_ion_data.group);
+		if (rc) {
+			pr_err("%s:ION attach group failed %d\n", __func__, rc);
+			return rc;
+		}
+
+	}
+
 	pr_debug("%s: SMMU-Enabled = %d\n", __func__, smmu_enabled);
 	return rc;
+
+fail_group:
+	return -EPROBE_DEFER;
 }
 
 static int msm_audio_ion_remove(struct platform_device *pdev)
 {
-	pr_debug("%s: msm audio ion is unloaded\n", __func__);
+	pr_debug("%s: msm audio ion is unloaded, domain=%p, group=%p\n",
+		__func__, msm_audio_ion_data.domain, msm_audio_ion_data.group);
+	iommu_detach_group(msm_audio_ion_data.domain, msm_audio_ion_data.group);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 12a3ceb..d316496 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -279,6 +279,8 @@
 	/* 8974 IDs */
 	[126] = MSM_CPU_8974,
 	[184] = MSM_CPU_8974,
+	[185] = MSM_CPU_8974,
+	[186] = MSM_CPU_8974,
 
 	/* 8625 IDs */
 	[127] = MSM_CPU_8625,
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 9479d46c..26f0210 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -495,7 +495,7 @@
 	if (ret)
 		return ret;
 
-	if (!subsys->desc->is_loadable)
+	if (subsys->desc->is_not_loadable)
 		return 0;
 
 	ret = wait_for_err_ready(subsys);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index c3ff7dc..2776c58 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -69,7 +69,7 @@
 		type = *(uint32_t *)(buf);
 		data_len = *(uint32_t *)(buf + 4);
 		if (type < DIAG_CTRL_MSG_REG ||
-				 type > DIAG_CTRL_MSG_F3_MASK_V2) {
+				 type > DIAG_CTRL_MSG_LAST) {
 			pr_alert("diag: In %s, Invalid Msg type %d proc %d",
 				 __func__, type, smd_info->peripheral);
 			break;
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 9c2c691..f58ab24 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -29,6 +29,12 @@
 #define DIAG_CTRL_MSG_EVENT_MASK_V2	10
 /* Send Diag F3 mask */
 #define DIAG_CTRL_MSG_F3_MASK_V2	11
+#define DIAG_CTRL_MSG_NUM_PRESETS	12
+#define DIAG_CTRL_MSG_SET_PRESET_ID	13
+#define DIAG_CTRL_MSG_LOG_MASK_WITH_PRESET_ID	14
+#define DIAG_CTRL_MSG_EVENT_MASK_WITH_PRESET_ID	15
+#define DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID	16
+#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
 
 /* Denotes that we support sending/receiving the feature mask */
 #define F_DIAG_INT_FEATURE_MASK	0x01
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d95c12b..f071801 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -813,7 +813,8 @@
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
 	if (!adreno_dev->drawctxt_active ||
-		KGSL_STATE_ACTIVE != device->state) {
+		KGSL_STATE_ACTIVE != device->state ||
+		!device->active_cnt) {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
 		return;
 	}
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 967e4ab..144c3d6 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -822,7 +822,8 @@
 			int remain, void *priv)
 {
 	struct kgsl_snapshot_replay_mem_list *header = snapshot;
-	struct kgsl_process_private *private;
+	struct kgsl_process_private *private = NULL;
+	struct kgsl_process_private *tmp_private;
 	unsigned int ptbase;
 	struct rb_node *node;
 	struct kgsl_mem_entry *entry = NULL;
@@ -831,10 +832,12 @@
 
 	ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
 	mutex_lock(&kgsl_driver.process_mutex);
-	list_for_each_entry(private, &kgsl_driver.process_list, list) {
-		if (kgsl_mmu_pt_equal(&device->mmu, private->pagetable,
-			ptbase))
+	list_for_each_entry(tmp_private, &kgsl_driver.process_list, list) {
+		if (kgsl_mmu_pt_equal(&device->mmu, tmp_private->pagetable,
+			ptbase)) {
+			private = tmp_private;
 			break;
+		}
 	}
 	mutex_unlock(&kgsl_driver.process_mutex);
 	if (!private) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index d81a8f1..07f8ef5 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -308,16 +308,28 @@
 
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
 {
+	bool had_gpuaddr = false;
+
 	if (entry == NULL)
 		return;
 
+	/*
+	 * Unmap the entry first so that there isn't a period of
+	 * time where kgsl doesn't know about the address range
+	 * but it is still present in the pagetable. Unmapping will
+	 * clear the gpuaddr field, so remember if we had a mapping,
+	 * and an rbtree entry for later.
+	 */
+	had_gpuaddr = entry->memdesc.gpuaddr != 0;
+	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
+
 	spin_lock(&entry->priv->mem_lock);
 
 	if (entry->id != 0)
 		idr_remove(&entry->priv->mem_idr, entry->id);
 	entry->id = 0;
 
-	if (entry->memdesc.gpuaddr != 0)
+	if (had_gpuaddr)
 		rb_erase(&entry->node, &entry->priv->mem_rb);
 
 	spin_unlock(&entry->priv->mem_lock);
@@ -325,7 +337,6 @@
 	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
 	entry->priv = NULL;
 
-	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
 
 	kgsl_mem_entry_put(entry);
 }
@@ -666,78 +677,44 @@
 }
 EXPORT_SYMBOL(kgsl_late_resume_driver);
 
-/* file operations */
-static struct kgsl_process_private *
-kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+/**
+ * kgsl_destroy_process_private() - Cleanup function to free process private
+ * @kref: - Pointer to object being destroyed's kref struct
+ * Free struct object and all other resources attached to it.
+ * Since the function can be used when not all resources inside process
+ * private have been allocated, there is a check to (before each resource
+ * cleanup) see if the struct member being cleaned is in fact allocated or not.
+ * If the value is not NULL, resource is freed.
+ */
+static void kgsl_destroy_process_private(struct kref *kref)
 {
-	struct kgsl_process_private *private;
 
-	mutex_lock(&kgsl_driver.process_mutex);
-	list_for_each_entry(private, &kgsl_driver.process_list, list) {
-		if (private->pid == task_tgid_nr(current)) {
-			private->refcnt++;
-			goto out;
-		}
-	}
-
-	/* no existing process private found for this dev_priv, create one */
-	private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
-	if (private == NULL) {
-		KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
-			sizeof(struct kgsl_process_private));
-		goto out;
-	}
-
-	spin_lock_init(&private->mem_lock);
-	private->refcnt = 1;
-	private->pid = task_tgid_nr(current);
-	private->mem_rb = RB_ROOT;
-
-	idr_init(&private->mem_idr);
-
-	if (kgsl_mmu_enabled())
-	{
-		unsigned long pt_name;
-		struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
-
-		pt_name = task_tgid_nr(current);
-		private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
-		if (private->pagetable == NULL) {
-			kfree(private);
-			private = NULL;
-			goto out;
-		}
-	}
-
-	list_add(&private->list, &kgsl_driver.process_list);
-
-	kgsl_process_init_sysfs(private);
-	kgsl_process_init_debugfs(private);
-
-out:
-	mutex_unlock(&kgsl_driver.process_mutex);
-	return private;
-}
-
-static void
-kgsl_put_process_private(struct kgsl_device *device,
-			 struct kgsl_process_private *private)
-{
 	struct kgsl_mem_entry *entry = NULL;
 	int next = 0;
 
-	if (!private)
+
+	struct kgsl_process_private *private = container_of(kref,
+			struct kgsl_process_private, refcount);
+
+	/*
+	 * Remove this process from global process list
+	 * We do not acquire a lock first as it is expected that
+	 * kgsl_destroy_process_private() is only going to be called
+	 * through kref_put() which is only called after acquiring
+	 * the lock.
+	 */
+	if (!private) {
+		KGSL_CORE_ERR("Cannot destroy null process private\n");
+		mutex_unlock(&kgsl_driver.process_mutex);
 		return;
-
-	mutex_lock(&kgsl_driver.process_mutex);
-
-	if (--private->refcnt)
-		goto unlock;
-
-	kgsl_process_uninit_sysfs(private);
-	debugfs_remove_recursive(private->debug_root);
-
+	}
 	list_del(&private->list);
+	mutex_unlock(&kgsl_driver.process_mutex);
+
+	if (private->kobj.parent)
+		kgsl_process_uninit_sysfs(private);
+	if (private->debug_root)
+		debugfs_remove_recursive(private->debug_root);
 
 	while (1) {
 		rcu_read_lock();
@@ -755,9 +732,110 @@
 	}
 	kgsl_mmu_putpagetable(private->pagetable);
 	idr_destroy(&private->mem_idr);
+
 	kfree(private);
-unlock:
+	return;
+}
+
+static void
+kgsl_put_process_private(struct kgsl_device *device,
+			 struct kgsl_process_private *private)
+{
+	mutex_lock(&kgsl_driver.process_mutex);
+
+	/*
+	 * kref_put() returns 1 when the refcnt has reached 0 and the destroy
+	 * function is called. Mutex is released in the destroy function if
+	 * its called, so only release mutex if kref_put() return 0
+	 */
+	if (!kref_put(&private->refcount, kgsl_destroy_process_private))
+		mutex_unlock(&kgsl_driver.process_mutex);
+	return;
+}
+
+/**
+ * find_process_private() - Helper function to search for process private
+ * @cur_dev_priv: Pointer to device private structure which contains pointers
+ * to device and process_private structs.
+ * Returns: Pointer to the found/newly created private struct
+ */
+static struct kgsl_process_private *
+kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+	struct kgsl_process_private *private;
+
+	/* Search in the process list */
+	mutex_lock(&kgsl_driver.process_mutex);
+	list_for_each_entry(private, &kgsl_driver.process_list, list) {
+		if (private->pid == task_tgid_nr(current)) {
+			kref_get(&private->refcount);
+			goto done;
+		}
+	}
+
+	/* no existing process private found for this dev_priv, create one */
+	private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
+	if (private == NULL) {
+		KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
+			sizeof(struct kgsl_process_private));
+		goto done;
+	}
+
+	kref_init(&private->refcount);
+
+	private->pid = task_tgid_nr(current);
+	spin_lock_init(&private->mem_lock);
+	mutex_init(&private->process_private_mutex);
+	/* Add the newly created process struct obj to the process list */
+	list_add(&private->list, &kgsl_driver.process_list);
+done:
 	mutex_unlock(&kgsl_driver.process_mutex);
+	return private;
+}
+
+/**
+ * kgsl_get_process_private() - Used to find the process private structure
+ * @cur_dev_priv: Current device pointer
+ * Finds or creates a new porcess private structire and initializes its members
+ * Returns: Pointer to the private process struct obj found/created or
+ * NULL if pagetable creation for this process private obj failed.
+ */
+static struct kgsl_process_private *
+kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+	struct kgsl_process_private *private;
+
+	private = kgsl_find_process_private(cur_dev_priv);
+
+	mutex_lock(&private->process_private_mutex);
+
+	if (!private->mem_rb.rb_node) {
+		private->mem_rb = RB_ROOT;
+		idr_init(&private->mem_idr);
+	}
+
+	if ((!private->pagetable) && kgsl_mmu_enabled()) {
+		unsigned long pt_name;
+		struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
+
+		pt_name = task_tgid_nr(current);
+		private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
+		if (private->pagetable == NULL) {
+			mutex_unlock(&private->process_private_mutex);
+			kgsl_put_process_private(cur_dev_priv->device,
+						private);
+			return NULL;
+		}
+	}
+
+	if (!private->kobj.parent)
+		kgsl_process_init_sysfs(private);
+	if (!private->debug_root)
+		kgsl_process_init_debugfs(private);
+
+	mutex_unlock(&private->process_private_mutex);
+
+	return private;
 }
 
 static int kgsl_release(struct inode *inodep, struct file *filep)
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index debba18..94cc551 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -46,7 +46,11 @@
 #define KGSL_PAGETABLE_ENTRY_SIZE  4
 
 /* Pagetable Virtual Address base */
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
 #define KGSL_PAGETABLE_BASE	0x10000000
+#else
+#define KGSL_PAGETABLE_BASE	0xE0000000
+#endif
 
 /* Extra accounting entries needed in the pagetable */
 #define KGSL_PT_EXTRA_ENTRIES      16
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ac82820..42c1475 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -280,6 +280,12 @@
 	unsigned int refcnt;
 	pid_t pid;
 	spinlock_t mem_lock;
+
+	/* General refcount for process private struct obj */
+	struct kref refcount;
+	/* Mutex to synchronize access to each process_private struct obj */
+	struct mutex process_private_mutex;
+
 	struct rb_root mem_rb;
 	struct idr mem_idr;
 	struct kgsl_pagetable *pagetable;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 3057723..513fb90 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1345,13 +1345,27 @@
 	 * we're better off with extra room.
 	 */
 	if (mmu->pt_per_process) {
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
 		mmu->pt_base = PAGE_OFFSET;
 		mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE
 				- kgsl_mmu_get_base_addr(mmu) - SZ_1M;
 		mmu->use_cpu_map = true;
+#else
+		mmu->pt_base = KGSL_PAGETABLE_BASE;
+		mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+				KGSL_IOMMU_GLOBAL_MEM_SIZE -
+				KGSL_PAGETABLE_BASE;
+		mmu->use_cpu_map = false;
+#endif
 	} else {
 		mmu->pt_base = KGSL_PAGETABLE_BASE;
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
 		mmu->pt_size = SZ_2G;
+#else
+		mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+				KGSL_IOMMU_GLOBAL_MEM_SIZE -
+				KGSL_PAGETABLE_BASE;
+#endif
 		mmu->use_cpu_map = false;
 	}
 
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index ef5b0f4..02cde94 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -410,7 +410,7 @@
  */
 static inline int kgsl_mmu_use_cpu_map(struct kgsl_mmu *mmu)
 {
-	return mmu->pt_per_process;
+	return mmu->use_cpu_map;
 }
 
 /*
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
index 21e4829..efddf61 100644
--- a/drivers/input/touchscreen/gen_vkeys.c
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -24,6 +24,8 @@
 #define HEIGHT_SCALE_NUM 8
 #define HEIGHT_SCALE_DENOM 10
 
+#define VKEY_Y_OFFSET_DEFAULT 0
+
 /* numerator and denomenator for border equations */
 #define BORDER_ADJUST_NUM 3
 #define BORDER_ADJUST_DENOM 4
@@ -59,7 +61,7 @@
 {
 	struct device_node *np = dev->of_node;
 	struct property *prop;
-	int rc;
+	int rc, val;
 
 	rc = of_property_read_string(np, "label", &pdata->name);
 	if (rc) {
@@ -106,10 +108,13 @@
 		}
 	}
 
-	rc = of_property_read_u32(np, "qcom,y-offset", &pdata->y_offset);
-	if (rc) {
+	pdata->y_offset = VKEY_Y_OFFSET_DEFAULT;
+	rc = of_property_read_u32(np, "qcom,y-offset", &val);
+	if (!rc)
+		pdata->y_offset = val;
+	else if (rc != -EINVAL) {
 		dev_err(dev, "Failed to read y position offset\n");
-		return -EINVAL;
+		return rc;
 	}
 	return 0;
 }
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 59b9746..509567c 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -70,7 +70,7 @@
 }
 
 static struct msm_cam_clk_info jpeg_8x_clk_info[] = {
-	{"core_clk", 228570000},
+	{"core_clk", JPEG_CLK_RATE},
 	{"iface_clk", -1},
 	{"bus_clk0", -1},
 	{"camss_top_ahb_clk", -1},
@@ -135,8 +135,8 @@
 	{
 		.src = MSM_BUS_MASTER_JPEG,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 1027648000,
-		.ib  = 1105920000,
+		.ab  = JPEG_CLK_RATE * 2.5,
+		.ib  = JPEG_CLK_RATE * 2.5,
 	},
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
index cd80d2e..a14b8ee 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.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
@@ -19,6 +19,7 @@
 #include <linux/iommu.h>
 #include <mach/iommu.h>
 #include "msm_jpeg_sync.h"
+#define JPEG_CLK_RATE 266670000
 
 void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
 	struct ion_handle **ionhandle, int domain_num);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 17f4590..ade8597 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -61,8 +61,29 @@
 		if (inst->session_type == type &&
 			inst->state >= MSM_VIDC_OPEN_DONE &&
 			inst->state < MSM_VIDC_STOP_DONE) {
-			num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
-					inst->prop.width, inst->prop.fps);
+			int stride, scanlines, rc;
+			struct hfi_device *hdev;
+
+			hdev = inst->core->device;
+			if (!hdev) {
+				dprintk(VIDC_ERR,
+						"No hdev (probably in bad state)\n");
+				return -EINVAL;
+			}
+
+			rc = call_hfi_op(hdev, get_stride_scanline,
+					COLOR_FMT_NV12,
+					inst->prop.width, inst->prop.height,
+					&stride, &scanlines);
+			if (rc) {
+				dprintk(VIDC_WARN,
+						"Failed to determine stride/scan when getting load. Perf. might be affected\n");
+				stride = inst->prop.width;
+				scanlines = inst->prop.height;
+			}
+
+			num_mbs_per_sec += NUM_MBS_PER_SEC(stride, scanlines,
+					inst->prop.fps);
 		}
 		mutex_unlock(&inst->lock);
 	}
@@ -678,6 +699,8 @@
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 7e6cd4f..59a6b68 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -172,16 +172,13 @@
 		}
 
 		/* NV bit is set to indicate that platform driver is capable
-		 * of doing NV download. SSR should not set NV bit; during
-		 * SSR NV bin is downloaded by WLAN driver.
+		 * of doing NV download.
 		 */
-		if (!wcnss_cold_boot_done()) {
-			pr_debug("wcnss: Indicate NV bin download\n");
-			spare_reg = msm_wcnss_base + spare_offset;
-			reg = readl_relaxed(spare_reg);
-			reg |= NVBIN_DLND_BIT;
-			writel_relaxed(reg, spare_reg);
-		}
+		pr_debug("wcnss: Indicate NV bin download\n");
+		spare_reg = msm_wcnss_base + spare_offset;
+		reg = readl_relaxed(spare_reg);
+		reg |= NVBIN_DLND_BIT;
+		writel_relaxed(reg, spare_reg);
 
 		pmu_conf_reg = msm_wcnss_base + pmu_offset;
 		writel_relaxed(0, pmu_conf_reg);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 1a175c9..f837a06 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -28,6 +28,9 @@
 #include <linux/of_gpio.h>
 #include <linux/clk.h>
 #include <linux/ratelimit.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -48,6 +51,10 @@
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
 
+static int has_calibrated_data = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
+
 static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
 module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -92,20 +99,27 @@
 #define CCU_PRONTO_LAST_ADDR2_OFFSET		0x14
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
-#define WCNSS_MAX_FRAME_SIZE		500
+#define WCNSS_MAX_FRAME_SIZE		(4*1024)
 #define WCNSS_VERSION_LEN			30
 
 /* message types */
 #define WCNSS_CTRL_MSG_START	0x01000000
-#define	WCNSS_VERSION_REQ		(WCNSS_CTRL_MSG_START + 0)
-#define	WCNSS_VERSION_RSP		(WCNSS_CTRL_MSG_START + 1)
-#define	WCNSS_NVBIN_DNLD_REQ		(WCNSS_CTRL_MSG_START + 2)
-#define	WCNSS_NVBIN_DNLD_RSP		(WCNSS_CTRL_MSG_START + 3)
+#define	WCNSS_VERSION_REQ             (WCNSS_CTRL_MSG_START + 0)
+#define	WCNSS_VERSION_RSP             (WCNSS_CTRL_MSG_START + 1)
+#define	WCNSS_NVBIN_DNLD_REQ          (WCNSS_CTRL_MSG_START + 2)
+#define	WCNSS_NVBIN_DNLD_RSP          (WCNSS_CTRL_MSG_START + 3)
+#define	WCNSS_CALDATA_UPLD_REQ        (WCNSS_CTRL_MSG_START + 4)
+#define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
+#define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
+#define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
 
 
 #define VALID_VERSION(version) \
 	((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
 
+#define FW_CALDATA_CAPABLE() \
+	((penv->fw_major >= 1) && (penv->fw_minor >= 5) ? 1 : 0)
+
 struct smd_msg_hdr {
 	unsigned int msg_type;
 	unsigned int msg_len;
@@ -126,6 +140,13 @@
  * header, so NV fragment size as next multiple of 1Kb is 3Kb.
  */
 #define NV_FRAGMENT_SIZE  3072
+#define MAX_CALIBRATED_DATA_SIZE  (64*1024)
+#define LAST_FRAGMENT        (1 << 0)
+#define MESSAGE_TO_FOLLOW    (1 << 1)
+#define CAN_RECEIVE_CALDATA  (1 << 15)
+#define WCNSS_RESP_SUCCESS   1
+#define WCNSS_RESP_FAIL      0
+
 
 /* Macro to find the total number fragments of the NV bin Image */
 #define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \
@@ -144,11 +165,14 @@
 	unsigned short frag_number;
 
 	/*
-	 * When set to 1 it indicates that no more fragments will
-	 * be sent. Receiver shall send back response message after
-	 * the last fragment.
+	 * bit 0: When set to 1 it indicates that no more fragments will
+	 * be sent.
+	 * bit 1: When set, a new message will be followed by this message
+	 * bit 2- bit 14:  Reserved
+	 * bit 15: when set, it indicates that the sender is capable of
+	 * receiving Calibrated data.
 	 */
-	unsigned short is_last_fragment;
+	unsigned short msg_flags;
 
 	/* NV Image size (number of bytes) */
 	unsigned int nvbin_buffer_size;
@@ -160,6 +184,7 @@
 	 */
 };
 
+
 struct nvbin_dnld_req_msg {
 	/*
 	 * Note: The length specified in nvbin_dnld_req_msg messages
@@ -170,6 +195,39 @@
 	struct nvbin_dnld_req_params dnld_req_params;
 };
 
+struct cal_data_params {
+
+	/* The total size of the calibrated data, including all the
+	 * fragments.
+	 */
+	unsigned int total_size;
+	unsigned short frag_number;
+	/*
+	 * bit 0: When set to 1 it indicates that no more fragments will
+	 * be sent.
+	 * bit 1: When set, a new message will be followed by this message
+	 * bit 2- bit 15: Reserved
+	 */
+	unsigned short msg_flags;
+	/*
+	 * fragment size
+	 */
+	unsigned int frag_size;
+	/*
+	 * Following the frag_size, frag_size of fragmented
+	 * data will be followed.
+	 */
+};
+
+struct cal_data_msg {
+	/*
+	 * The length specified in cal_data_msg should be
+	 * hdr.msg_len = sizeof(cal_data_msg) + frag_size
+	 */
+	struct smd_msg_hdr hdr;
+	struct cal_data_params cal_params;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -180,9 +238,10 @@
 	const struct dev_pm_ops *pm_ops;
 	int		triggered;
 	int		smd_channel_ready;
-	int		cold_boot_done;
 	smd_channel_t	*smd_ch;
 	unsigned char	wcnss_version[WCNSS_VERSION_LEN];
+	unsigned char   fw_major;
+	unsigned char   fw_minor;
 	unsigned int	serial_number;
 	int		thermal_mitigation;
 	enum wcnss_hw_type	wcnss_hw_type;
@@ -198,6 +257,20 @@
 	void __iomem *pronto_a2xb_base;
 	void __iomem *pronto_ccpu_base;
 	void __iomem *fiq_reg;
+	int	ssr_boot;
+	int	nv_downloaded;
+	unsigned char *fw_cal_data;
+	unsigned char *user_cal_data;
+	int	fw_cal_rcvd;
+	int	fw_cal_exp_frag;
+	int	fw_cal_available;
+	int	user_cal_read;
+	int	user_cal_available;
+	int	user_cal_rcvd;
+	int	user_cal_exp_size;
+	int	device_opened;
+	struct mutex dev_lock;
+	wait_queue_head_t read_wait;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -459,21 +532,26 @@
 	switch (event) {
 	case SMD_EVENT_DATA:
 		len = smd_read_avail(penv->smd_ch);
-		if (len < 0)
+		if (len < 0) {
 			pr_err("wcnss: failed to read from smd %d\n", len);
+			return;
+		}
 		schedule_work(&penv->wcnssctrl_rx_work);
 		break;
 
 	case SMD_EVENT_OPEN:
 		pr_debug("wcnss: opening WCNSS SMD channel :%s",
 				WCNSS_CTRL_CHANNEL);
-		if (!VALID_VERSION(penv->wcnss_version))
-			schedule_work(&penv->wcnssctrl_version_work);
+		schedule_work(&penv->wcnssctrl_version_work);
+
 		break;
 
 	case SMD_EVENT_CLOSE:
 		pr_debug("wcnss: closing WCNSS SMD channel :%s",
 				WCNSS_CTRL_CHANNEL);
+		/* This SMD is closed only during SSR */
+		penv->ssr_boot = true;
+		penv->nv_downloaded = 0;
 		break;
 
 	default:
@@ -658,6 +736,15 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_config);
 
+int wcnss_device_ready(void)
+{
+	if (penv && penv->pdev && penv->nv_downloaded)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_device_ready);
+
+
 struct resource *wcnss_wlan_get_memory_map(struct device *dev)
 {
 	if (penv && dev && (dev == &penv->pdev->dev) && penv->smd_channel_ready)
@@ -837,15 +924,13 @@
 }
 EXPORT_SYMBOL(wcnss_hardware_type);
 
-int wcnss_cold_boot_done(void)
+int fw_cal_data_available(void)
 {
 	if (penv)
-		return penv->cold_boot_done;
+		return penv->fw_cal_available;
 	else
 		return -ENODEV;
 }
-EXPORT_SYMBOL(wcnss_cold_boot_done);
-
 
 static int wcnss_smd_tx(void *data, int len)
 {
@@ -864,14 +949,145 @@
 	return ret;
 }
 
+static unsigned char wcnss_fw_status(void)
+{
+	int len = 0;
+	int rc = 0;
+
+	unsigned char fw_status = 0xFF;
+
+	len = smd_read_avail(penv->smd_ch);
+	if (len < 1) {
+		pr_err("%s: invalid firmware status", __func__);
+		return fw_status;
+	}
+
+	rc = smd_read(penv->smd_ch, &fw_status, 1);
+	if (rc < 0) {
+		pr_err("%s: incomplete data read from smd\n", __func__);
+		return fw_status;
+	}
+	return fw_status;
+}
+
+static void wcnss_send_cal_rsp(unsigned char fw_status)
+{
+	struct smd_msg_hdr *rsphdr;
+	unsigned char *msg = NULL;
+	int rc;
+
+	msg = kmalloc((sizeof(struct smd_msg_hdr) + 1), GFP_KERNEL);
+	if (NULL == msg) {
+		pr_err("wcnss: %s: failed to get memory\n", __func__);
+		return;
+	}
+
+	rsphdr = (struct smd_msg_hdr *)msg;
+	rsphdr->msg_type = WCNSS_CALDATA_UPLD_RSP;
+	rsphdr->msg_len = sizeof(struct smd_msg_hdr) + 1;
+	memcpy(msg+sizeof(struct smd_msg_hdr), &fw_status, 1);
+
+	rc = wcnss_smd_tx(msg, rsphdr->msg_len);
+	if (rc < 0)
+		pr_err("wcnss: smd tx failed\n");
+}
+
+/* Collect calibrated data from WCNSS */
+void extract_cal_data(int len)
+{
+	int rc;
+	struct cal_data_params calhdr;
+	unsigned char fw_status = WCNSS_RESP_FAIL;
+
+	if (len < sizeof(struct cal_data_params)) {
+		pr_err("wcnss: incomplete cal header length\n");
+		return;
+	}
+
+	rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
+			sizeof(struct cal_data_params));
+	if (rc < sizeof(struct cal_data_params)) {
+		pr_err("wcnss: incomplete cal header read from smd\n");
+		return;
+	}
+
+	if (penv->fw_cal_exp_frag != calhdr.frag_number) {
+		pr_err("wcnss: Invalid frgament");
+		goto exit;
+	}
+
+	if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
+		pr_err("wcnss: Invalid fragment size");
+		goto exit;
+	}
+
+	if (0 == calhdr.frag_number) {
+		if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
+			pr_err("wcnss: Invalid cal data size %d",
+				calhdr.total_size);
+			goto exit;
+		}
+		kfree(penv->fw_cal_data);
+		penv->fw_cal_rcvd = 0;
+		penv->fw_cal_data = kmalloc(calhdr.total_size,
+				GFP_KERNEL);
+		if (penv->fw_cal_data == NULL) {
+			smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+			goto exit;
+		}
+	}
+
+	mutex_lock(&penv->dev_lock);
+	if (penv->fw_cal_rcvd + calhdr.frag_size >
+			MAX_CALIBRATED_DATA_SIZE) {
+		pr_err("calibrated data size is more than expected %d",
+				penv->fw_cal_rcvd + calhdr.frag_size);
+		penv->fw_cal_exp_frag = 0;
+		penv->fw_cal_rcvd = 0;
+		smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+		goto unlock_exit;
+	}
+
+	rc = smd_read(penv->smd_ch, penv->fw_cal_data + penv->fw_cal_rcvd,
+			calhdr.frag_size);
+	if (rc < calhdr.frag_size)
+		goto unlock_exit;
+
+	penv->fw_cal_exp_frag++;
+	penv->fw_cal_rcvd += calhdr.frag_size;
+
+	if (calhdr.msg_flags & LAST_FRAGMENT) {
+		penv->fw_cal_exp_frag = 0;
+		penv->fw_cal_available = true;
+		pr_info("wcnss: cal data collection completed\n");
+	}
+	mutex_unlock(&penv->dev_lock);
+	wake_up(&penv->read_wait);
+
+	if (penv->fw_cal_available) {
+		fw_status = WCNSS_RESP_SUCCESS;
+		wcnss_send_cal_rsp(fw_status);
+	}
+	return;
+
+unlock_exit:
+	mutex_unlock(&penv->dev_lock);
+
+exit:
+	wcnss_send_cal_rsp(fw_status);
+	return;
+}
+
+
 static void wcnssctrl_rx_handler(struct work_struct *worker)
 {
 	int len = 0;
 	int rc = 0;
-	unsigned char buf[WCNSS_MAX_FRAME_SIZE];
+	unsigned char buf[sizeof(struct wcnss_version)];
 	struct smd_msg_hdr *phdr;
 	struct wcnss_version *pversion;
 	int hw_type;
+	unsigned char fw_status = 0;
 
 	len = smd_read_avail(penv->smd_ch);
 	if (len > WCNSS_MAX_FRAME_SIZE) {
@@ -882,23 +1098,33 @@
 	if (len <= 0)
 		return;
 
-	rc = smd_read(penv->smd_ch, buf, len);
-	if (rc < len) {
-		pr_err("wcnss: incomplete data read from smd\n");
+	rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr));
+	if (rc < sizeof(struct smd_msg_hdr)) {
+		pr_err("wcnss: incomplete header read from smd\n");
 		return;
 	}
+	len -= sizeof(struct smd_msg_hdr);
 
 	phdr = (struct smd_msg_hdr *)buf;
 
 	switch (phdr->msg_type) {
 
 	case WCNSS_VERSION_RSP:
-		pversion = (struct wcnss_version *)buf;
-		if (len != sizeof(struct wcnss_version)) {
+		if (len != sizeof(struct wcnss_version)
+				- sizeof(struct smd_msg_hdr)) {
 			pr_err("wcnss: invalid version data from wcnss %d\n",
-				len);
+					len);
 			return;
 		}
+		rc = smd_read(penv->smd_ch, buf+sizeof(struct smd_msg_hdr),
+				len);
+		if (rc < len) {
+			pr_err("wcnss: incomplete data read from smd\n");
+			return;
+		}
+		pversion = (struct wcnss_version *)buf;
+		penv->fw_major = pversion->major;
+		penv->fw_minor = pversion->minor;
 		snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
 			"%02x%02x%02x%02x", pversion->major, pversion->minor,
 					pversion->version, pversion->revision);
@@ -930,7 +1156,22 @@
 		break;
 
 	case WCNSS_NVBIN_DNLD_RSP:
-		pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n");
+		penv->nv_downloaded = true;
+		fw_status = wcnss_fw_status();
+		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
+			fw_status);
+		break;
+
+	case WCNSS_CALDATA_DNLD_RSP:
+		penv->nv_downloaded = true;
+		fw_status = wcnss_fw_status();
+		pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
+			fw_status);
+		break;
+
+	case WCNSS_CALDATA_UPLD_REQ:
+		penv->fw_cal_available = 0;
+		extract_cal_data(len);
 		break;
 
 	default:
@@ -953,7 +1194,8 @@
 	return;
 }
 
-static void wcnss_nvbin_dnld_req(struct work_struct *worker)
+
+static void wcnss_nvbin_dnld(void)
 {
 	int ret = 0;
 	struct nvbin_dnld_req_msg *dnld_req_msg;
@@ -970,8 +1212,8 @@
 	ret = request_firmware(&nv, NVBIN_FILE, dev);
 
 	if (ret || !nv || !nv->data || !nv->size) {
-		pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n",
-			NVBIN_FILE);
+		pr_err("wcnss: %s: request_firmware failed for %s\n",
+			__func__, NVBIN_FILE);
 		return;
 	}
 
@@ -992,13 +1234,14 @@
 		NV_FRAGMENT_SIZE), GFP_KERNEL);
 
 	if (NULL == outbuffer) {
-		pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n");
+		pr_err("wcnss: %s: failed to get buffer\n", __func__);
 		goto err_free_nv;
 	}
 
 	dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer;
 
 	dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ;
+	dnld_req_msg->dnld_req_params.msg_flags = 0;
 
 	for (count = 0; count < total_fragments; count++) {
 		dnld_req_msg->dnld_req_params.frag_number = count;
@@ -1009,10 +1252,14 @@
 			if (!cur_frag_size)
 				cur_frag_size = NV_FRAGMENT_SIZE;
 
-			dnld_req_msg->dnld_req_params.is_last_fragment = 1;
+			dnld_req_msg->dnld_req_params.msg_flags |=
+				LAST_FRAGMENT;
+			dnld_req_msg->dnld_req_params.msg_flags |=
+				CAN_RECEIVE_CALDATA;
 		} else {
 			cur_frag_size = NV_FRAGMENT_SIZE;
-			dnld_req_msg->dnld_req_params.is_last_fragment = 0;
+			dnld_req_msg->dnld_req_params.msg_flags &=
+				~LAST_FRAGMENT;
 		}
 
 		dnld_req_msg->dnld_req_params.nvbin_buffer_size =
@@ -1030,7 +1277,8 @@
 
 		retry_count = 0;
 		while ((ret == -ENOSPC) && (retry_count <= 3)) {
-			pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n");
+			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+				__func__);
 			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
 				count, dnld_req_msg->hdr.msg_len,
 				total_fragments, retry_count);
@@ -1043,7 +1291,7 @@
 		}
 
 		if (ret < 0) {
-			pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n");
+			pr_err("wcnss: %s: smd tx failed\n", __func__);
 			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
 				count, dnld_req_msg->hdr.msg_len,
 				total_fragments, retry_count);
@@ -1062,6 +1310,138 @@
 	return;
 }
 
+
+static void wcnss_caldata_dnld(const void *cal_data,
+		unsigned int cal_data_size, bool msg_to_follow)
+{
+	int ret = 0;
+	struct cal_data_msg *cal_msg;
+	unsigned short total_fragments = 0;
+	unsigned short count = 0;
+	unsigned short retry_count = 0;
+	unsigned short cur_frag_size = 0;
+	unsigned char *outbuffer = NULL;
+
+	total_fragments = TOTALFRAGMENTS(cal_data_size);
+
+	outbuffer = kmalloc((sizeof(struct cal_data_msg) +
+		NV_FRAGMENT_SIZE), GFP_KERNEL);
+
+	if (NULL == outbuffer) {
+		pr_err("wcnss: %s: failed to get buffer\n", __func__);
+		return;
+	}
+
+	cal_msg = (struct cal_data_msg *)outbuffer;
+
+	cal_msg->hdr.msg_type = WCNSS_CALDATA_DNLD_REQ;
+	cal_msg->cal_params.msg_flags = 0;
+
+	for (count = 0; count < total_fragments; count++) {
+		cal_msg->cal_params.frag_number = count;
+
+		if (count == (total_fragments - 1)) {
+			cur_frag_size = cal_data_size % NV_FRAGMENT_SIZE;
+			if (!cur_frag_size)
+				cur_frag_size = NV_FRAGMENT_SIZE;
+
+			cal_msg->cal_params.msg_flags
+			    |= LAST_FRAGMENT;
+			if (msg_to_follow)
+				cal_msg->cal_params.msg_flags |=
+					MESSAGE_TO_FOLLOW;
+		} else {
+			cur_frag_size = NV_FRAGMENT_SIZE;
+			cal_msg->cal_params.msg_flags &=
+				~LAST_FRAGMENT;
+		}
+
+		cal_msg->cal_params.total_size = cal_data_size;
+		cal_msg->cal_params.frag_size =
+			cur_frag_size;
+
+		cal_msg->hdr.msg_len =
+			sizeof(struct cal_data_msg) + cur_frag_size;
+
+		memcpy((outbuffer + sizeof(struct cal_data_msg)),
+			(cal_data + count * NV_FRAGMENT_SIZE),
+			cur_frag_size);
+
+		ret = wcnss_smd_tx(outbuffer, cal_msg->hdr.msg_len);
+
+		retry_count = 0;
+		while ((ret == -ENOSPC) && (retry_count <= 3)) {
+			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+					__func__);
+			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, cal_msg->hdr.msg_len,
+				total_fragments, retry_count);
+
+			/* wait and try again */
+			msleep(20);
+			retry_count++;
+			ret = wcnss_smd_tx(outbuffer,
+				cal_msg->hdr.msg_len);
+		}
+
+		if (ret < 0) {
+			pr_err("wcnss: %s: smd tx failed\n", __func__);
+			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
+				count, cal_msg->hdr.msg_len,
+				total_fragments, retry_count);
+			goto err_dnld;
+		}
+	}
+
+
+err_dnld:
+	/* free buffer */
+	kfree(outbuffer);
+
+	return;
+}
+
+
+static void wcnss_nvbin_dnld_main(struct work_struct *worker)
+{
+	int retry = 0;
+
+	if (!FW_CALDATA_CAPABLE())
+		goto nv_download;
+
+	if (!penv->fw_cal_available && WCNSS_CONFIG_UNSPECIFIED
+		!= has_calibrated_data && !penv->user_cal_available) {
+		while (!penv->user_cal_available && retry++ < 5)
+			msleep(500);
+	}
+
+	/* only cal data is sent during ssr (if available) */
+	if (penv->fw_cal_available && penv->ssr_boot) {
+		pr_info_ratelimited("wcnss: cal download during SSR, using fw cal");
+		wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, false);
+		return;
+
+	} else if (penv->user_cal_available && penv->ssr_boot) {
+		pr_info_ratelimited("wcnss: cal download during SSR, using user cal");
+		wcnss_caldata_dnld(penv->user_cal_data,
+		penv->user_cal_rcvd, false);
+		return;
+
+	} else if (penv->user_cal_available) {
+		pr_info_ratelimited("wcnss: cal download during cold boot, using user cal");
+		wcnss_caldata_dnld(penv->user_cal_data,
+		penv->user_cal_rcvd, true);
+	}
+
+nv_download:
+	pr_info_ratelimited("wcnss: NV download");
+	wcnss_nvbin_dnld();
+
+	return;
+}
+
+
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
@@ -1146,7 +1526,7 @@
 	}
 	INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
 	INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
-	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req);
+	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
 
@@ -1201,7 +1581,6 @@
 			goto fail_ioremap3;
 		}
 	}
-	penv->cold_boot_done = 1;
 
 	return 0;
 
@@ -1229,20 +1608,128 @@
 	return ret;
 }
 
-#ifndef MODULE
 static int wcnss_node_open(struct inode *inode, struct file *file)
 {
 	struct platform_device *pdev;
 
-	pr_info(DEVICE " triggered by userspace\n");
+	/* first open is only to trigger WCNSS platform driver */
+	if (!penv->triggered) {
+		pr_info(DEVICE " triggered by userspace\n");
+		pdev = penv->pdev;
+		return wcnss_trigger_config(pdev);
 
-	pdev = penv->pdev;
-	return wcnss_trigger_config(pdev);
+	} else if (penv->device_opened) {
+		pr_info(DEVICE " already opened\n");
+		return -EBUSY;
+	}
+
+	mutex_lock(&penv->dev_lock);
+	penv->user_cal_rcvd = 0;
+	penv->user_cal_read = 0;
+	penv->user_cal_available = false;
+	penv->user_cal_data = NULL;
+	penv->device_opened = 1;
+	mutex_unlock(&penv->dev_lock);
+
+	return 0;
 }
 
+static ssize_t wcnss_wlan_read(struct file *fp, char __user
+			*buffer, size_t count, loff_t *position)
+{
+	int rc = 0;
+
+	if (!penv->device_opened)
+		return -EFAULT;
+
+	rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
+			> penv->user_cal_read || penv->fw_cal_available);
+
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&penv->dev_lock);
+
+	if (penv->fw_cal_available && penv->fw_cal_rcvd
+			== penv->user_cal_read) {
+		rc = 0;
+		goto exit;
+	}
+
+	if (count > penv->fw_cal_rcvd - penv->user_cal_read)
+		count = penv->fw_cal_rcvd - penv->user_cal_read;
+
+	rc = copy_to_user(buffer, penv->fw_cal_data +
+			penv->user_cal_read, count);
+	if (rc == 0) {
+		penv->user_cal_read += count;
+		rc = count;
+	}
+
+exit:
+	mutex_unlock(&penv->dev_lock);
+	return rc;
+}
+
+/* first (valid) write to this device should be 4 bytes cal file size */
+static ssize_t wcnss_wlan_write(struct file *fp, const char __user
+			*user_buffer, size_t count, loff_t *position)
+{
+	int rc = 0;
+	int size = 0;
+
+	if (!penv->device_opened || penv->user_cal_available)
+		return -EFAULT;
+
+	if (penv->user_cal_rcvd == 0 && count >= 4
+			&& !penv->user_cal_data) {
+		rc = copy_from_user((void *)&size, user_buffer, 4);
+		if (size > MAX_CALIBRATED_DATA_SIZE) {
+			pr_err(DEVICE " invalid size to write %d\n", size);
+			return -EFAULT;
+		}
+
+		rc += count;
+		count -= 4;
+		penv->user_cal_exp_size =  size;
+		penv->user_cal_data = kmalloc(size, GFP_KERNEL);
+		if (penv->user_cal_data == NULL) {
+			pr_err(DEVICE " no memory to write\n");
+			return -ENOMEM;
+		}
+		if (0 == count)
+			goto exit;
+
+	} else if (penv->user_cal_rcvd == 0 && count < 4)
+		return -EFAULT;
+
+	if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+		pr_err(DEVICE " invalid size to write %d\n", count +
+				penv->user_cal_rcvd);
+		rc = -ENOMEM;
+		goto exit;
+	}
+	rc = copy_from_user((void *)penv->user_cal_data +
+			penv->user_cal_rcvd, user_buffer, count);
+	if (0 == rc) {
+		penv->user_cal_rcvd += count;
+		rc += count;
+	}
+	if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
+		penv->user_cal_available = true;
+		pr_info_ratelimited("wcnss: user cal written");
+	}
+
+exit:
+	return rc;
+}
+
+
 static const struct file_operations wcnss_node_fops = {
 	.owner = THIS_MODULE,
 	.open = wcnss_node_open,
+	.read = wcnss_wlan_read,
+	.write = wcnss_wlan_write,
 };
 
 static struct miscdevice wcnss_misc = {
@@ -1250,8 +1737,6 @@
 	.name = DEVICE,
 	.fops = &wcnss_node_fops,
 };
-#endif /* ifndef MODULE */
-
 
 static int __devinit
 wcnss_wlan_probe(struct platform_device *pdev)
@@ -1279,18 +1764,8 @@
 		return -ENOENT;
 	}
 
-
-#ifdef MODULE
-
-	/* Since we were built as a module, we are running because
-	 * the module was loaded, therefore we assume userspace
-	 * applications are available to service PIL, so we can
-	 * trigger the WCNSS configuration now
-	 */
-	pr_info(DEVICE " probed in MODULE mode\n");
-	return wcnss_trigger_config(pdev);
-
-#else
+	mutex_init(&penv->dev_lock);
+	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
 	 * of kernel initialization.  We don't know if userspace
@@ -1303,7 +1778,6 @@
 	pr_info(DEVICE " probed in built-in mode\n");
 	return misc_register(&wcnss_misc);
 
-#endif
 }
 
 static int __devexit
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 67728c2..76aaad0 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -187,6 +187,7 @@
 	int inactive_cycles = 0;
 	int cnt;
 
+	ipa_inc_client_enable_clks();
 	do {
 		cnt = ipa_handle_tx_core(sys, true, true);
 		if (cnt == 0) {
@@ -199,6 +200,7 @@
 	} while (inactive_cycles <= POLLING_INACTIVITY_TX);
 
 	ipa_tx_switch_to_intr_mode(sys);
+	ipa_dec_client_disable_clks();
 }
 
 static void ipa_wq_handle_tx(struct work_struct *work)
@@ -914,6 +916,7 @@
 	int inactive_cycles = 0;
 	int cnt;
 
+	ipa_inc_client_enable_clks();
 	do {
 		cnt = ipa_handle_rx_core(sys, true, true);
 		if (cnt == 0) {
@@ -926,6 +929,7 @@
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
 	ipa_rx_switch_to_intr_mode(sys);
+	ipa_dec_client_disable_clks();
 }
 
 static void switch_to_intr_rx_work_func(struct work_struct *work)
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 0fc4826..8655d89 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -336,27 +336,28 @@
 int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
 {
 	struct ipa_rm_resource *consumer, *producer;
-	int i, result = 0;
+	int peers_index, result = 0, list_size;
 
-	IPADBG("IPA RM: %s ENTER\n", __func__);
-
+	IPADBG("ipa_rm_resource_delete ENTER with resource %d\n",
+					resource->name);
 	if (!resource) {
 		IPADBG("ipa_rm_resource_delete ENTER with invalid param\n");
 		return -EINVAL;
 	}
 	if (resource->type == IPA_RM_PRODUCER) {
 		if (resource->peers_list) {
-			for (i = IPA_RM_RESOURCE_PROD_MAX;
-					i < IPA_RM_RESOURCE_MAX;
-						++i) {
+			list_size = ipa_rm_peers_list_get_size(
+				resource->peers_list);
+			for (peers_index = 0;
+				peers_index < list_size;
+				peers_index++) {
 				consumer = ipa_rm_peers_list_get_resource(
-						i,
+						peers_index,
 						resource->peers_list);
-				if (consumer) {
+				if (consumer)
 					ipa_rm_resource_delete_dependency(
 						resource,
 						consumer);
-				}
 			}
 			ipa_rm_peers_list_delete(resource->peers_list);
 		}
@@ -365,9 +366,13 @@
 		kfree((struct ipa_rm_resource_prod *) resource);
 	} else if (resource->type == IPA_RM_CONSUMER) {
 		if (resource->peers_list) {
-			for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; ++i) {
+			list_size = ipa_rm_peers_list_get_size(
+				resource->peers_list);
+			for (peers_index = 0;
+					peers_index < list_size;
+					peers_index++){
 				producer = ipa_rm_peers_list_get_resource(
-							i,
+							peers_index,
 							resource->peers_list);
 				if (producer)
 					ipa_rm_resource_delete_dependency(
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 9062ab8..add9522 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -128,8 +128,10 @@
  * @teth_wq: dedicated workqueue, used for setting up the HW bridge and for
  * sending packets using the SW bridge when the system is waking up from power
  * collapse
- * @a2_ipa_hdr_len: A2 to IPA header length, used to configure the A2 endpoint
- * for header removal
+ * @a2_ipa_hdr_len: A2 to IPA header length, used for configuring the A2
+ * endpoint for header removal
+ * @ipa_a2_hdr_len: IPA to A2 header length, used for configuring the A2
+ * endpoint for header removal
  * @hdr_del: array to store the headers handles in order to delete them later
  * @routing_del: array of routing rules handles, one array for IPv4 and one for
  * IPv6
@@ -160,6 +162,7 @@
 	struct stats stats;
 	struct workqueue_struct *teth_wq;
 	u16 a2_ipa_hdr_len;
+	u16 ipa_a2_hdr_len;
 	struct ipa_ioc_del_hdr *hdr_del;
 	struct ipa_ioc_del_rt_rule *routing_del[TETH_IP_FAMILIES];
 	struct ipa_ioc_del_flt_rule *filtering_del[TETH_IP_FAMILIES];
@@ -287,6 +290,7 @@
 	}
 
 	hdr_cfg.hdr_len = ipa_a2_hdr_len;
+	teth_ctx->ipa_a2_hdr_len = ipa_a2_hdr_len;
 	res = ipa_cfg_ep_hdr(teth_ctx->ipa_a2_pipe_hdl, &hdr_cfg);
 	if (res) {
 		TETH_ERR("Header insertion config for IPA->A2 pipe failed\n");
@@ -1225,6 +1229,28 @@
 				  enum ipa_rm_event event,
 				  unsigned long data)
 {
+	switch (event) {
+	case IPA_RM_RESOURCE_GRANTED:
+		complete(&teth_ctx->is_bridge_prod_up);
+		break;
+
+	case IPA_RM_RESOURCE_RELEASED:
+		complete(&teth_ctx->is_bridge_prod_down);
+		break;
+
+	default:
+		TETH_ERR("Unsupported notification!\n");
+		WARN_ON(1);
+		break;
+	}
+
+	return;
+}
+
+static void a2_prod_notify_cb(void *notify_cb_data,
+			      enum ipa_rm_event event,
+			      unsigned long data)
+{
 	int res;
 	struct ipa_ep_cfg ipa_ep_cfg;
 
@@ -1243,15 +1269,15 @@
 
 		/* Reset the various endpoints configuration */
 		memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+		ipa_ep_cfg.hdr.hdr_len = teth_ctx->ipa_a2_hdr_len;
 		ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
 
+		memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
 		ipa_ep_cfg.hdr.hdr_len = teth_ctx->a2_ipa_hdr_len;
 		ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
-		complete(&teth_ctx->is_bridge_prod_up);
 		break;
 
 	case IPA_RM_RESOURCE_RELEASED:
-		complete(&teth_ctx->is_bridge_prod_down);
 		break;
 
 	default:
@@ -1283,6 +1309,7 @@
 int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
 {
 	int res = 0;
+	struct ipa_rm_register_params a2_prod_reg_params;
 
 	TETH_DBG_FUNC_ENTRY();
 	if (usb_notify_cb_ptr == NULL) {
@@ -1323,10 +1350,22 @@
 		goto fail_add_dependency_3;
 	}
 
+	/* Register for A2_PROD resource notifications */
+	a2_prod_reg_params.user_data = NULL;
+	a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+	res = ipa_rm_register(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+	if (res) {
+		TETH_ERR("ipa_rm_register() failed\n");
+		goto fail_add_dependency_4;
+	}
+
 	/* Return 0 as EINPROGRESS is a valid return value at this point */
 	res = 0;
 	goto bail;
 
+fail_add_dependency_4:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+				 IPA_RM_RESOURCE_USB_CONS);
 fail_add_dependency_3:
 	ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
 				 IPA_RM_RESOURCE_A2_CONS);
@@ -1368,6 +1407,7 @@
 	teth_ctx->comp_hw_bridge_in_progress = false;
 	memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
 	teth_ctx->a2_ipa_hdr_len = 0;
+	teth_ctx->ipa_a2_hdr_len = 0;
 	memset(teth_ctx->hdr_del,
 	       0,
 	       sizeof(struct ipa_ioc_del_hdr) + TETH_TOTAL_HDR_ENTRIES *
@@ -1402,6 +1442,7 @@
 int teth_bridge_disconnect(void)
 {
 	int res;
+	struct ipa_rm_register_params a2_prod_reg_params;
 
 	TETH_DBG_FUNC_ENTRY();
 	if (!teth_ctx->is_connected) {
@@ -1478,6 +1519,13 @@
 		TETH_ERR(
 			"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
 
+	/* Deregister from A2_PROD notifications */
+	a2_prod_reg_params.user_data = NULL;
+	a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+	res = ipa_rm_deregister(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+	if (res)
+		TETH_ERR("Failed deregistering from A2_prod notifications.\n");
+
 	teth_ctx->is_connected = false;
 bail:
 	TETH_DBG_FUNC_EXIT();
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 2d1b763..64e8d7a 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -1744,10 +1744,12 @@
 
 			spin_lock(&usb_bam_lock);
 
-			ctx.inactivity_timer_ms[bam] = timer_d;
 			/* Apply new timer setting if bam has running pipes */
-			if (ctx.pipes_enabled_per_bam[bam] > 0)
-				usb_bam_set_inactivity_timer(bam);
+			if (ctx.inactivity_timer_ms[bam] != timer_d) {
+				ctx.inactivity_timer_ms[bam] = timer_d;
+				if (ctx.pipes_enabled_per_bam[bam] > 0)
+					usb_bam_set_inactivity_timer(bam);
+			}
 
 			spin_unlock(&usb_bam_lock);
 		}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 419499d..eec6d39 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1100,8 +1100,7 @@
 	if (rtc == NULL) {
 		pr_err("%s: unable to open rtc device (%s)\n",
 			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
-		rc = -EINVAL;
-		goto close_time;
+		return -EINVAL;
 	}
 
 	rc = rtc_read_time(rtc, &tm);
@@ -1523,10 +1522,6 @@
 		pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
 						vbat_uv, chip->v_cutoff_uv);
 		return 1;
-	} else if (soc > 0 && vbat_uv < chip->v_cutoff_uv) {
-		pr_debug("forcing soc to 0, vbat (%d) < cutoff (%d)\n",
-						vbat_uv, chip->v_cutoff_uv);
-		return 0;
 	} else {
 		pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
 				soc, vbat_uv, chip->v_cutoff_uv);
@@ -2564,10 +2559,20 @@
 	return 0;
 }
 
+static int bms_suspend(struct device *dev)
+{
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
+	chip->last_soc_unbound = true;
+	return 0;
+}
+
 static int bms_resume(struct device *dev)
 {
 	int rc;
-	unsigned long soc_calc_period;
+	int soc_calc_period;
+	int time_until_next_recalc;
 	unsigned long time_since_last_recalc;
 	unsigned long tm_now_sec;
 	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -2580,7 +2585,6 @@
 		 * unbind the last soc so that the next
 		 * recalculation is not limited to changing by 1%
 		 */
-		chip->last_soc_unbound = true;
 		time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
 		pr_debug("Time since last recalc: %lu\n",
 				time_since_last_recalc);
@@ -2589,16 +2593,19 @@
 		else
 			soc_calc_period = chip->calculate_soc_ms;
 
-		if (time_since_last_recalc >= soc_calc_period) {
-			chip->last_recalc_time = tm_now_sec;
-			recalculate_soc(chip);
-		}
+		time_until_next_recalc = max(0, soc_calc_period
+				- (int)(time_since_last_recalc * 1000));
+
+		schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(time_until_next_recalc)));
 	}
 	return 0;
 }
 
 static const struct dev_pm_ops qpnp_bms_pm_ops = {
 	.resume		= bms_resume,
+	.suspend	= bms_suspend,
 };
 
 static struct spmi_driver qpnp_bms_driver = {
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 991cf2e..f01a078 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -199,8 +199,8 @@
 #define TSENS0_8X10_POINT1_SHIFT	16
 #define TSENS0_8X10_POINT2_SHIFT	22
 #define TSENS1_8X10_POINT2_SHIFT	6
-#define TSENS_8X10_BASE0_MASK		0xf
-#define TSENS_8X10_BASE1_MASK		0xf0
+#define TSENS_8X10_BASE0_MASK		0xff
+#define TSENS_8X10_BASE1_MASK		0xff00
 #define TSENS0_8X10_POINT1_MASK		0x3f0000
 #define TSENS0_8X10_POINT2_MASK		0xfc00000
 #define TSENS_8X10_TSENS_CAL_SEL	0x70000000
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index f695870..890a897 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2739,7 +2739,7 @@
 
 		/* SPS driver wll handle the UART BAM IRQ */
 		bam.irq = (u32)msm_uport->bam_irq;
-		bam.manage = SPS_BAM_MGR_LOCAL;
+		bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 
 		pr_debug("msm_serial_hs: bam physical base=0x%x\n",
 							(u32)bam.phys_addr);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 01d8be1..38f08fc 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -338,14 +338,17 @@
  */
 static int hw_device_reset(struct ci13xxx *udc)
 {
+	int delay_count = 25; /* 250 usec */
+
 	/* should flush & stop before reset */
 	hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
 	hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
 
 	hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
-	while (hw_cread(CAP_USBCMD, USBCMD_RST))
-		udelay(10);             /* not RTOS friendly */
-
+	while (delay_count--  && hw_cread(CAP_USBCMD, USBCMD_RST))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("USB controller reset failed\n");
 
 	if (udc->udc_driver->notify_event)
 		udc->udc_driver->notify_event(udc,
@@ -814,6 +817,8 @@
  */
 static int hw_usb_reset(void)
 {
+	int delay_count = 10; /* 100 usec delay */
+
 	hw_usb_set_address(0);
 
 	/* ESS flushes only at end?!? */
@@ -826,8 +831,10 @@
 	hw_cwrite(CAP_ENDPTCOMPLETE,  0,  0);   /* writes its content */
 
 	/* wait until all bits cleared */
-	while (hw_cread(CAP_ENDPTPRIME, ~0))
-		udelay(10);             /* not RTOS friendly */
+	while (delay_count-- && hw_cread(CAP_ENDPTPRIME, ~0))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("ENDPTPRIME is not cleared during bus reset\n");
 
 	/* reset all endpoints ? */
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index e87f028..1876057 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -119,6 +119,12 @@
 	 89909, 119880, 148352, 119880, false},
 	{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
 	 90000, 120000, 148500, 120000, false},
+	{HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, false, 1688, 408, 1066, 42,
+	 63981, 60020, 108000, 60000, false},
+
+	/* All 1024 H Active */
+	{HDMI_VFRMT_1024x768p60_4_3, 1024, 768, false, 1344, 320, 806, 38,
+	 48363, 60004, 65000, 60000, false},
 
 	/* All 1440 H Active */
 	{HDMI_VFRMT_1440x576i50_4_3, 1440, 576, true,  1728, 288, 625, 24,
@@ -1016,7 +1022,7 @@
 static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
 	const u8 *data_buf, u32 num_of_cea_blocks)
 {
-	u8 i = 0;
+	u8 i = 0, offset = 0, std_blk = 0;
 	u32 video_format = HDMI_VFRMT_640x480p60_4_3;
 	u32 has480p = false;
 	u8 len;
@@ -1175,6 +1181,72 @@
 		}
 	}
 
+	std_blk = 0;
+	offset  = 0;
+	while (std_blk < 8) {
+		if ((edid_blk0[0x26 + offset] == 0x81) &&
+		    (edid_blk0[0x26 + offset + 1] == 0x80)) {
+			pr_debug("%s: 108MHz: off=[%x] stdblk=[%x]\n",
+				 __func__, offset, std_blk);
+			hdmi_edid_add_sink_video_format(sink_data,
+				HDMI_VFRMT_1280x1024p60_5_4);
+		}
+		if ((edid_blk0[0x26 + offset] == 0x61) &&
+		    (edid_blk0[0x26 + offset + 1] == 0x40)) {
+			pr_debug("%s: 65MHz: off=[%x] stdblk=[%x]\n",
+				 __func__, offset, std_blk);
+			hdmi_edid_add_sink_video_format(sink_data,
+				HDMI_VFRMT_1024x768p60_4_3);
+			break;
+		} else {
+			offset += 2;
+		}
+		std_blk++;
+	}
+	/* check if the EDID revision is 4 (version 1.4) */
+	if (edid_blk0[0x13] == 4) {
+		u8  start = 0x36;
+		i = 0;
+		/* Check each of 4 - 18 bytes descriptors */
+		while (i < 4) {
+			u8  iter   = start;
+			u32 header_1 = 0;
+			u8  header_2 = 0;
+			header_1 = edid_blk0[iter++];
+			header_1 = header_1 << 8 | edid_blk0[iter++];
+			header_1 = header_1 << 8 | edid_blk0[iter++];
+			header_1 = header_1 << 8 | edid_blk0[iter++];
+			header_2 = edid_blk0[iter];
+			if (header_1 == 0x000000F7 &&
+			    header_2 == 0x00) {
+				iter++;
+				/* VESA DMT Standard Version (0x0A)*/
+				iter++;
+				/* First set of supported formats */
+				iter++;
+				/* Second set of supported formats */
+				if (edid_blk0[iter] & 0x02) {
+					pr_debug("%s: DMT 1280x1024@60\n",
+						 __func__);
+					hdmi_edid_add_sink_video_format(
+						sink_data,
+						HDMI_VFRMT_1280x1024p60_5_4);
+					break;
+				}
+			}
+			i++;
+			start += 0x12;
+		}
+	}
+
+	/* Established Timing I and II */
+	if (edid_blk0[0x24] & BIT(3)) {
+		pr_debug("%s: 65MHz: off=[%x] stdblk=[%x]\n",
+			 __func__, offset, std_blk);
+		hdmi_edid_add_sink_video_format(sink_data,
+				HDMI_VFRMT_1024x768p60_4_3);
+	}
+
 	hdmi_edid_get_extended_video_formats(edid_ctrl, data_buf+0x80);
 
 	/* mandaroty 3d format */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 42cc356..12552bc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -190,6 +190,14 @@
 		{20480, 247500} } },
 };
 
+static bool is_cea_format(int mode)
+{
+	if ((mode > 0) && (mode < HDMI_EVFRMT_END))
+		return true;
+	else
+		return false;
+}
+
 const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
 {
 	switch (module) {
@@ -2100,7 +2108,8 @@
 		return rc;
 	}
 
-	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
+	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
+	    is_cea_format(hdmi_ctrl->video_resolution)) {
 		rc = hdmi_tx_audio_setup(hdmi_ctrl);
 		if (rc) {
 			DEV_ERR("%s: hdmi_msm_audio_setup failed. rc=%d\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 0c8b0f8..53dfc71 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -109,8 +109,8 @@
 		hdmi_supported_video_mode_lut, MSM_HDMI_MODES_XTND);
 
 	/* Add any other specific DVI timings (DVI modes, etc.) */
-	MSM_HDMI_MODES_SET_TIMING(hdmi_supported_video_mode_lut,
-		HDMI_VFRMT_2560x1600p60_16_9);
+	MSM_HDMI_MODES_SET_SUPP_TIMINGS(
+		hdmi_supported_video_mode_lut, MSM_HDMI_MODES_DVI);
 } /* hdmi_setup_video_mode_lut */
 
 const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 26c6934..3cb23f3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -65,11 +65,19 @@
 {
 	u32 xres, yres;
 	u32 min_src_size, min_dst_size;
+	int content_secure;
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
+	content_secure = (req->flags & MDP_SECURE_OVERLAY_SESSION);
+	if (!ctl->is_secure && content_secure &&
+				 (mfd->panel.type == WRITEBACK_PANEL)) {
+		pr_debug("return due to security concerns\n");
+		return -EPERM;
+	}
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
 		min_src_size = fmt->is_yuv ? 2 : 1;
 		min_dst_size = 1;
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
index a7f9e4a..8e5e23a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9304_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.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
@@ -473,17 +473,17 @@
 #define SITAR_A_CDC_TX3_DMIC_CTL		(0x235)
 #define SITAR_A_CDC_TX3_DMIC_CTL__POR			(0x00000000)
 
-#define SITAR_A_CDC_TX4_VOL_CTL_TIMER		(0x239)
+#define SITAR_A_CDC_TX4_VOL_CTL_TIMER		(0x238)
 #define SITAR_A_CDC_TX4_VOL_CTL_TIMER__POR		(0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_GAIN		(0x23A)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN		(0x239)
 #define SITAR_A_CDC_TX4_VOL_CTL_GAIN__POR		(0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_CFG		(0x23B)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG		(0x23A)
 #define SITAR_A_CDC_TX4_VOL_CTL_CFG__POR		(0x00000000)
-#define SITAR_A_CDC_TX4_MUX_CTL			(0x23C)
+#define SITAR_A_CDC_TX4_MUX_CTL			(0x23B)
 #define SITAR_A_CDC_TX4_MUX_CTL__POR			(0x00000008)
-#define SITAR_A_CDC_TX4_CLK_FS_CTL		(0x23D)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL		(0x23C)
 #define SITAR_A_CDC_TX4_CLK_FS_CTL__POR			(0x00000003)
-#define SITAR_A_CDC_TX4_DMIC_CTL		(0x23E)
+#define SITAR_A_CDC_TX4_DMIC_CTL		(0x23D)
 #define SITAR_A_CDC_TX4_DMIC_CTL__POR			(0x00000000)
 
 #define SITAR_A_CDC_TX5_VOL_CTL_TIMER		(0x240)
diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h
index 83e5dff..38b27bf 100644
--- a/include/linux/msm_audio_ion.h
+++ b/include/linux/msm_audio_ion.h
@@ -13,7 +13,12 @@
 
 #ifndef _LINUX_MSM_AUDIO_ION_H
 #define _LINUX_MSM_AUDIO_ION_H
-
+#ifdef CONFIG_SND_SOC_QDSP6V2
+#include <sound/q6asm-v2.h>
+#else
+#include <sound/q6asm.h>
+#endif
+#include <sound/pcm.h>
 #include <linux/msm_ion.h>
 
 
@@ -26,9 +31,11 @@
 			unsigned long *ionflag, size_t bufsz,
 			ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
 int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle);
-
+int msm_audio_ion_mmap(struct audio_buffer *substream,
+		       struct vm_area_struct *vma);
 
 bool msm_audio_ion_is_smmu_available(void);
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op);
 
 #ifdef CONFIG_SND_SOC_QDSP6V2
 struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 2ad040e..e8de769 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -769,7 +769,7 @@
 struct kgsl_perfcounter_read_group {
 	unsigned int groupid;
 	unsigned int countable;
-	uint64_t value;
+	unsigned long long value;
 };
 
 struct kgsl_perfcounter_read {
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index b6fc091..6387913 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -35,7 +35,6 @@
 	CPR_CORNER_SVS = 1,
 	CPR_CORNER_NORMAL,
 	CPR_CORNER_TURBO,
-	CPR_CORNER_SUPER_TURBO,
 	CPR_CORNER_MAX,
 };
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 26d4ada..323f1e7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -702,6 +702,7 @@
 #define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
 #define V4L2_QCOM_BUF_FLAG_IDRFRAME	0x20000	/* Image is a IDR-frame */
 #define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
+#define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
 
 /*
  *	O V E R L A Y   P R E V I E W
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2319c48..da56df6 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,7 @@
 #define WCNSS_WLAN_IRQ_INVALID -1
 #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
 #define HAVE_WCNSS_RESET_INTR 1
+#define HAVE_WCNSS_CAL_DOWNLOAD 1
 
 struct device *wcnss_wlan_get_device(void);
 struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -65,7 +66,7 @@
 void wcnss_resume_notify(void);
 void wcnss_riva_log_debug_regs(void);
 void wcnss_pronto_log_debug_regs(void);
-int wcnss_cold_boot_done(void);
+int wcnss_device_ready(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 2d34d70..2138689 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -165,6 +165,8 @@
 	wait_queue_head_t      cmd_wait;
 	wait_queue_head_t      time_wait;
 	bool                   perf_mode;
+	/* audio cache operations fptr*/
+	int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
 };
 
 void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/include/video/msm_hdmi_modes.h b/include/video/msm_hdmi_modes.h
index a15272b..ced6acb 100644
--- a/include/video/msm_hdmi_modes.h
+++ b/include/video/msm_hdmi_modes.h
@@ -122,9 +122,10 @@
 #define HDMI_EVFRMT_END			HDMI_VFRMT_4096x2160p24_16_9
 
 /* VESA DMT TIMINGS */
-#define HDMI_VFRMT_2560x1600p60_16_9	(HDMI_EVFRMT_END + 1)
+#define HDMI_VFRMT_1024x768p60_4_3	(HDMI_EVFRMT_END + 1)
 #define HDMI_VFRMT_1280x1024p60_5_4	(HDMI_EVFRMT_END + 2)
-#define VESA_DMT_VFRMT_END		HDMI_VFRMT_1280x1024p60_5_4
+#define HDMI_VFRMT_2560x1600p60_16_9	(HDMI_EVFRMT_END + 3)
+#define VESA_DMT_VFRMT_END		HDMI_VFRMT_2560x1600p60_16_9
 #define HDMI_VFRMT_MAX			(VESA_DMT_VFRMT_END + 1)
 #define HDMI_VFRMT_FORCE_32BIT		0x7FFFFFFF
 
@@ -183,6 +184,9 @@
 #define HDMI_VFRMT_1920x1080p30_16_9_TIMING				\
 	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false,	\
 	 1080, 4, 5, 36, false, 74250, 30000, false, true}
+#define HDMI_VFRMT_1024x768p60_4_3_TIMING                               \
+	{HDMI_VFRMT_1024x768p60_4_3, 1024, 24, 136, 160, false,         \
+	768, 2, 6, 29, false, 65000, 60000, false, true}
 #define HDMI_VFRMT_1280x1024p60_5_4_TIMING				\
 	{HDMI_VFRMT_1280x1024p60_5_4, 1280, 48, 112, 248, false,	\
 	1024, 1, 3, 38, false, 108000, 60000, false, true}
@@ -249,6 +253,7 @@
 	}
 
 	if (type & MSM_HDMI_MODES_DVI) {
+		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1024x768p60_4_3);
 		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1280x1024p60_5_4);
 		MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_2560x1600p60_16_9);
 	}
@@ -326,8 +331,9 @@
 	case HDMI_VFRMT_3840x2160p25_16_9:	return "3840x2160 p25 16/9";
 	case HDMI_VFRMT_3840x2160p24_16_9:	return "3840x2160 p24 16/9";
 	case HDMI_VFRMT_4096x2160p24_16_9:	return "4096x2160 p24 16/9";
+	case HDMI_VFRMT_1024x768p60_4_3:	return "1024x768 p60 4/3";
+	case HDMI_VFRMT_1280x1024p60_5_4:	return "1280x1024 p60 5/4";
 	case HDMI_VFRMT_2560x1600p60_16_9:	return "2560x1600 p60 16/9";
-	case HDMI_VFRMT_1280x1024p60_5_4:	return "1280x1042 p60 5/4";
 	default:				return "???";
 	}
 }
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 59debb7..2356791 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -137,6 +137,8 @@
 static DEFINE_RWLOCK(nl_table_lock);
 static atomic_t nl_table_users = ATOMIC_INIT(0);
 
+#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
+
 static ATOMIC_NOTIFIER_HEAD(netlink_chain);
 
 static inline u32 netlink_group_mask(u32 group)
@@ -330,6 +332,11 @@
 	struct hlist_node *node;
 	unsigned long mask;
 	unsigned int i;
+	struct listeners *listeners;
+
+	listeners = nl_deref_protected(tbl->listeners);
+	if (!listeners)
+		return;
 
 	for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
 		mask = 0;
@@ -337,7 +344,7 @@
 			if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
 				mask |= nlk_sk(sk)->groups[i];
 		}
-		tbl->listeners->masks[i] = mask;
+		listeners->masks[i] = mask;
 	}
 	/* this function is only called with the netlink table "grabbed", which
 	 * makes sure updates are visible before bind or setsockopt return. */
@@ -518,7 +525,11 @@
 	if (netlink_is_kernel(sk)) {
 		BUG_ON(nl_table[sk->sk_protocol].registered == 0);
 		if (--nl_table[sk->sk_protocol].registered == 0) {
-			kfree(nl_table[sk->sk_protocol].listeners);
+			struct listeners *old;
+
+			old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
+			RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
+			kfree_rcu(old, rcu);
 			nl_table[sk->sk_protocol].module = NULL;
 			nl_table[sk->sk_protocol].registered = 0;
 		}
@@ -948,7 +959,7 @@
 	rcu_read_lock();
 	listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
 
-	if (group - 1 < nl_table[sk->sk_protocol].groups)
+	if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
 		res = test_bit(group - 1, listeners->masks);
 
 	rcu_read_unlock();
@@ -1579,7 +1590,7 @@
 		new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
 		if (!new)
 			return -ENOMEM;
-		old = rcu_dereference_protected(tbl->listeners, 1);
+		old = nl_deref_protected(tbl->listeners);
 		memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
 		rcu_assign_pointer(tbl->listeners, new);
 
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 51334f2..2a60b88 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2388,7 +2388,7 @@
 {
 	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	int ret;
-	if (pdata->us_euro_gpio) {
+	if (pdata->us_euro_gpio >= 0) {
 		dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
 			pdata->us_euro_gpio);
 		ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
@@ -2524,7 +2524,7 @@
 	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,us-euro-gpios", 0);
 	if (pdata->us_euro_gpio < 0) {
-		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+		dev_info(&pdev->dev, "property %s not detected in node %s",
 			"qcom,us-euro-gpios",
 			pdev->dev.of_node->full_name);
 	} else {
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 9dbbf20..ec5359c 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -29,6 +29,7 @@
 #include <sound/pcm_params.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
 
 #include <sound/timer.h>
 
@@ -728,25 +729,14 @@
 static int msm_compr_mmap(struct snd_pcm_substream *substream,
 				struct vm_area_struct *vma)
 {
-	int result = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-
-	pr_debug("%s\n", __func__);
+	struct msm_audio *prtd = runtime->private_data;
+	struct audio_client *ac = prtd->audio_client;
+	struct audio_port_data *apd = ac->port;
+	struct audio_buffer *ab = &(apd[IN].buf[0]);
 	prtd->mmap_flag = 1;
-	runtime->render_flag = SNDRV_NON_DMA_MODE;
-	if (runtime->dma_addr && runtime->dma_bytes) {
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		result = remap_pfn_range(vma, vma->vm_start,
-				runtime->dma_addr >> PAGE_SHIFT,
-				runtime->dma_bytes,
-				vma->vm_page_prot);
-	} else {
-		pr_err("Physical address or size of buf is NULL");
-		return -EINVAL;
-	}
-	return result;
+
+	return msm_audio_ion_mmap(ab, vma);
 }
 
 static int msm_compr_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 27b3f56..7055c57 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -29,6 +29,8 @@
 #include <linux/dma-mapping.h>
 
 #include <linux/of_device.h>
+#include <linux/msm_audio_ion.h>
+
 #include <sound/compress_params.h>
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
@@ -421,24 +423,14 @@
 static int msm_pcm_mmap(struct snd_pcm_substream *substream,
 				struct vm_area_struct *vma)
 {
-	int result = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
-
-	pr_debug("%s\n", __func__);
+	struct audio_client *ac = prtd->audio_client;
+	struct audio_port_data *apd = ac->port;
+	struct audio_buffer *ab = &(apd[IN].buf[0]);
 	prtd->mmap_flag = 1;
 
-	if (runtime->dma_addr && runtime->dma_bytes) {
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		result = remap_pfn_range(vma, vma->vm_start,
-				runtime->dma_addr >> PAGE_SHIFT,
-				runtime->dma_bytes,
-				vma->vm_page_prot);
-	} else {
-		pr_err("Physical address or size of buf is NULL");
-		return -EINVAL;
-	}
-	return result;
+	return msm_audio_ion_mmap(ab, vma);
 }
 
 static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 9fbf749..f4ca5b8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -27,6 +27,7 @@
 #include <sound/control.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
 
 #include <linux/of_device.h>
 #include <sound/pcm_params.h>
@@ -628,25 +629,14 @@
 static int msm_pcm_mmap(struct snd_pcm_substream *substream,
 				struct vm_area_struct *vma)
 {
-	int result = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
-
-	pr_debug("%s\n", __func__);
+	struct audio_client *ac = prtd->audio_client;
+	struct audio_port_data *apd = ac->port;
+	struct audio_buffer *ab = &(apd[IN].buf[0]);
 	prtd->mmap_flag = 1;
 
-	if (runtime->dma_addr && runtime->dma_bytes) {
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		result = remap_pfn_range(vma, vma->vm_start,
-				runtime->dma_addr >> PAGE_SHIFT,
-				runtime->dma_bytes,
-				vma->vm_page_prot);
-	} else {
-		pr_err("Physical address or size of buf is NULL");
-		return -EINVAL;
-	}
-
-	return result;
+	return msm_audio_ion_mmap(ab, vma);
 }
 
 static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index af8e873..c2fd2d7 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -331,6 +331,7 @@
 	mutex_unlock(&session_lock);
 	ac->session = 0;
 	ac->perf_mode = 0;
+	ac->fptr_cache_ops = NULL;
 	return;
 }
 
@@ -610,6 +611,7 @@
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
 	ac->perf_mode = false;
+	ac->fptr_cache_ops = NULL;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\