Merge "msm: mdss: Reveal finer error details for Assertive Display"
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
index 6ac80f1..b6fc45a 100644
--- a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -6,11 +6,6 @@
 devices require that the offlined core is power collapsed before turning off
 the resources that are used by the offlined core.
 
-This device is dependent on the pm-8x60 device, which configures the low power
-mode of respective cores. The sleep status is only valid when the core enters
-a low power mode. The device is a child node to pm-8x60 node which is documented
-in Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
-
 The required properties of sleep status device are:
 
 - compatible: qcom,cpu-sleep-status
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
index 094acb1..a979c56 100644
--- a/Documentation/devicetree/bindings/dma/sps/sps.txt
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -14,6 +14,9 @@
         1 - With BAM DMA and without pipe memory
         2 - With BAM DMA and with pipe memory
         3 - Without BAM DMA and without pipe memory
+  - qcom,pipe-attr-ee: BAM pipes are attributed to a specific EE, with
+    which we can know the pipes belong to apps side and can have the
+    error interrupts at the pipe level.
 
 Example:
 
@@ -24,4 +27,5 @@
 		      <0xfe803000 0x4800>;
 		interrupts = <0 94 0>;
 		qcom,device-type = <2>;
+		qcom,pipe-attr-ee;
 	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 7ed873f..8c87eac 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -4,7 +4,10 @@
 are compatable with MIPI display serial interface specification.
 
 Required properties:
-- compatible:				Must be "qcom,mdss-dsi-panel"
+- compatible:				Specifies the version for DSI HW. that
+					this panel will be worked with
+					"qcom,mdss-dsi-panel" = DSI v6.0
+					"qcom,dsi-panel-v2" = DSI V2.0
 - status:        			A string that has to be set to "okay/ok" to enable
 					the panel driver. By default this property will be
 					set to "disable". Will be set to "ok/okay" status
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index b350e24..3cac311 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -67,6 +67,16 @@
 - qcom,tm-temp-margin: if the pmic die temperature changes by more than this
 			value, recalibrate the ADCs. The unit of this property
 			is in millidegrees celsius.
+- qcom,min-fcc-learning-soc: An interger value which defines the minimum SOC
+			to start FCC learning. This is applicable only if
+			FCC learning is enabled.
+- qcom,min-fcc-ocv-pc:	An interger value which defines the minimum PC-lookup(OCV)
+			to start FCC learning. This is applicable only if
+			FCC learning is enabled.
+- qcom,min-fcc-learning-samples: An interger value which defines the minimum
+			number of the FCC measurement cycles required to
+			generate an FCC update. This is applicable only
+			if the FCC learning is enabled.
 
 Parent node optional properties:
 - qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -81,6 +91,8 @@
 			RDS of the batfet.
 - qcom,use-ocv-thresholds : A boolean that controls whether BMS will take
 			new OCVs only between the defined thresholds.
+- qcom,enable-fcc-learning: A boolean that defines if FCC learning is enabled.
+
 
 All sub node required properties:
 - reg : offset and length of the PMIC peripheral register map.
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index d58fa90..37140b7 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -12,9 +12,12 @@
 Optional properties:
  - parent-supply:   phandle to the parent supply/regulator node
  - qcom,clock-names: List of string names for core clocks
- - qcom,retain-mems: Presence denotes a hardware requirement to leave the
-		     forced memory retention signals in the core's clock
-		     branch control register asserted.
+ - qcom,retain-mem:  Presence denotes a hardware requirement to leave the
+		     forced core memory retention signals in the core's clock
+		     branch control registers asserted.
+ - qcom,retain-periph: Presence denotes a hardware requirement to leave the
+		     forced periph memory retention signal in the core's clock
+		     branch control registers asserted.
  - qcom,skip-logic-collapse: Presence denotes a requirement to leave power to
                              the core's logic enabled.
 
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 4b912f3..f16bcbc 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -23,6 +23,12 @@
 - qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
   value is non-zero, the value is the number of words in maximum transfer
   length.
+ - qcom,active-only : Vote for core clock when the application processor goes
+  to active state and remove that vote when it goes to idle state. This flag may
+  improve service time of first spi request at the expense of power consumption.
+  When this entry is not present, voting is done by the runtime-pm callbacks.
+ - qcom,master-id : Master endpoint number used for voting on clocks using the
+  bus-scaling driver.
 
 Optional properties which are required for support of BAM-mode:
 - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
@@ -81,4 +87,5 @@
 		qcom,bam-consumer-pipe-index = <12>;
 		qcom,bam-producer-pipe-index = <13>;
 		qcom,ver-reg-exists;
+		qcom,master-id = <86>;
 	};
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 6b4d1d3..a8b3065 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -21,6 +21,7 @@
 
 	qcom,mdss_dsi_sharp_qhd_video {
 		status = "ok";
+		qcom,cont-splash-enabled;
 	};
 
 	qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index c74e59d..b39f569 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -117,6 +117,14 @@
 		status = "disabled";
 	};
 
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		interrupts = <0 94 0>;
+		qcom,pipe-attr-ee;
+	};
+
 	spmi_bus: qcom,spmi@fc4c0000 {
 		cell-index = <0>;
 		compatible = "qcom,spmi-pmic-arb";
@@ -136,6 +144,21 @@
 		#interrupt-cells = <3>;
 	};
 
+	i2c_0: i2c@f9925000 { /* BLSP1 QUP3 */
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0xf9925000 0x1000>;
+		interrupt-names = "qup_err_intr";
+		interrupts = <0 97 0>;
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <50000000>;
+		qcom,sda-gpio = <&msmgpio 10 0>;
+		qcom,scl-gpio = <&msmgpio 11 0>;
+	};
+
 	usb3: qcom,ssusb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
 		reg = <0xf9200000 0xfc000>,
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
new file mode 100644
index 0000000..b9ed050
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -0,0 +1,117 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,dsi_v2_hx8379a_wvga_video {
+		compatible = "qcom,dsi-panel-v2";
+		label = "HX8379A WVGA video mode dsi panel";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 41 0>;
+		vdda-supply = <&pm8110_l19>;
+		vddio-supply=<&pm8110_l14>;
+		qcom,mdss-pan-res = <480 800>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <90 17 90 2 3 11>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <2>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+		qcom,mdss-pan-dsi-dlane-swap = <1>;
+		qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+		qcom,panel-phy-timingSettings = [5D 12 0C  00 33 39
+						 10 16 15  03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+		qcom,panel-phy-laneConfig =
+					[80 45 00 00 01 66 /*lane0**/
+					80 45 00 00 01 66 /*lane1*/
+					80 45 00 00 01 66 /*lane2*/
+					80 45 00 00 01 66 /*lane3*/
+					40 67 00 00 01 88]; /*Clk*/
+
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-on-cmds = [
+					29 01 00 00 01 04
+						B9 FF 83 79
+					23 01 00 00 01 02
+						BA 51
+					29 01 00 00 01 14
+						B1 00 50 44
+						EA 8D 08 11
+						0F 0F 24 2C
+						9A 1A 42 0B
+						6E F1 00 E6
+					29 01 00 00 01 0e
+						B2 00 00 3C
+						08 04 19 22
+						00 FF 08 04
+						19 20
+					29 01 00 00 01 20
+						B4 80 08 00
+						32 10 03 32
+						13 70 32 10
+						08 37 01 28
+						05 37 08 3C
+						20 44 44 08
+						00 40 08 28
+						08 30 30 04
+					23 01 00 00 01 02
+						cc 02
+					29 01 00 00 01 30
+						D5 00 00 08
+						00 01 05 00
+						03 00 88 88
+						88 88 23 01
+						67 45 02 13
+						88 88 88 88
+						88 88 88 88
+						88 88 54 76
+						10 32 31 20
+						88 88 88 88
+						88 88 00 00
+						00 00 00 00
+					29 01 00 00 01 24
+						E0 79 00 00
+						02 1C 1F 33
+						28 3E 07 0E
+						0F 15 17 16
+						16 13 19 00
+						00 02 1C 1F
+						33 28 3E 07
+						0E 0F 15 17
+						16 16 13 19
+					29 01 00 00 01 05
+						B6 00 A6 00 A6
+					05 01 00 00 96 02
+						11 00
+					05 01 00 00 78 02
+						29 00
+					];
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
new file mode 100644
index 0000000..1abaf55
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "mpq8092.dtsi"
+/include/ "mpq8092-rumi.dtsi"
+
+/ {
+	model = "Qualcomm MPQ8092 RUMI";
+	compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
+	qcom,msm-id = <146 16 0>;
+};
+
+&soc {
+	serial@f9922000 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dtsi b/arch/arm/boot/dts/mpq8092-rumi.dtsi
new file mode 100644
index 0000000..2016998
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-rumi.dtsi
@@ -0,0 +1,134 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	timer {
+		clock-frequency = <5000000>;
+	};
+
+	timer@f9020000 {
+		clock-frequency = <5000000>;
+	};
+
+	usb@f9a55000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9824000 {
+		status = "disabled";
+                qcom,clk-rates = <400000 19200000>;
+        };
+
+        qcom,sdcc@f98a4000 {
+		status = "disabled";
+                qcom,clk-rates = <400000 19200000>;
+        };
+
+	qcom,sps@f998000 {
+		status = "disable";
+	};
+
+	spi@f9924000 {
+		status = "disable";
+	};
+
+	spi@f9923000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9923000 0x1000>;
+		interrupts = <0 95 0>;
+		spi-max-frequency = <24000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+
+		ethernet-switch@2 {
+			compatible = "simtec,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <90 0>;
+			spi-max-frequency = <5000000>;
+		};
+	};
+
+	i2c@f9966000 {
+		status = "disable";
+	};
+
+	i2c@f9967000 {
+		status = "disable";
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9967000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 105 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		gpios = <&msmgpio 83 0>,/* DAT  */
+			<&msmgpio 84 0>;/* CLK */
+	};
+
+	slim@fe12f000 {
+		status = "disable";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		status = "disable";
+	};
+
+	qcom,spmi@fc4c0000 {
+		status = "disable";
+	};
+
+	qcom,ssusb@F9200000 {
+		status = "disable";
+	};
+
+	qcom,lpass@fe200000 {
+		status = "disable";
+	};
+
+	qcom,pronto@fb21b000 {
+		status = "disable";
+	};
+
+	qcom,mss@fc880000 {
+		status = "disable";
+	};
+
+        qcom,kgsl-3d0@fdb00000 {
+		status = "disabled";
+	};
+};
+
+&gdsc_venus {
+        status = "disabled";
+};
+
+&gdsc_jpeg {
+        status = "disabled";
+};
+
+&gdsc_oxili_gx {
+        status = "disabled";
+};
+
+&gdsc_oxili_cx {
+        status = "disabled";
+};
+
+&gdsc_usb_hsic {
+        status = "disabled";
+};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index cc19cce..e8674a0 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -55,6 +55,65 @@
 		clock-frequency = <19200000>;
 	};
 
+	timer@f9020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xf9020000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@f9021000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xf9021000 0x1000>,
+			      <0xf9022000 0x1000>;
+		};
+
+		frame@f9023000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xf9023000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9024000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xf9024000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9025000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xf9025000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9026000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xf9026000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9027000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xf9027000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@f9028000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xf9028000 0x1000>;
+			status = "disabled";
+		};
+	};
+
 	serial@f991f000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
@@ -62,6 +121,13 @@
 		status = "disabled";
 	};
 
+	serial@f9922000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf9922000 0x1000>;
+		interrupts = <0 112 0>;
+		status = "disabled";
+	};
+
 	serial@f995e000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf995e000 0x1000>;
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 65075e5..2cfc5cf 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -326,16 +326,8 @@
 			compatible = "qcom,msm-smmu-v0-ctx";
 			reg = <0xfd890000 0x1000>;
 			interrupts = <0 65 0>;
-			qcom,iommu-ctx-mids = <0>;
+			qcom,iommu-ctx-mids = <0 1 2 3 4 5 6 7 8 9>;
 			label = "vfe0";
 		};
-
-		qcom,iommu-ctx@fd891000 {
-			compatible = "qcom,msm-smmu-v0-ctx";
-			reg = <0xfd891000 0x1000>;
-			interrupts = <0 65 0>;
-			qcom,iommu-ctx-mids = <1>;
-			label = "vfe1";
-		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index e489dbb..2f3fae2 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -167,8 +167,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -204,8 +202,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -258,13 +254,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
-				qcom,mode = "lpg";
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,pwm-channel = <0>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 
@@ -278,13 +276,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,source-sel = <10>;
-				qcom,mode = "lpg";
 				qcom,pwm-channel = <5>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index ae57797..acab5e4 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -173,8 +173,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -207,8 +205,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -261,13 +257,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
-				qcom,mode = "lpg";
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,pwm-channel = <0>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 
@@ -281,13 +279,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,source-sel = <10>;
-				qcom,mode = "lpg";
 				qcom,pwm-channel = <5>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 3240efb..703ba4b 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,spm@f9089000 {
 		compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index a60ff26..7018c6a 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -159,8 +159,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -196,8 +194,6 @@
 	qcom,vdd-current-level = <9000 800000>;
 
 	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <6 22000>;
 
@@ -250,13 +246,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
-				qcom,mode = "lpg";
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,pwm-channel = <0>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 
@@ -270,13 +268,15 @@
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
 				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
 				qcom,mode-ctrl = <0x60>;
 				qcom,source-sel = <10>;
-				qcom,mode = "lpg";
 				qcom,pwm-channel = <5>;
 				qcom,start-idx = <1>;
 				qcom,duty-pcts = [00 00 00 00 64
 						 64 00 00 00 00];
+				qcom,use-blink;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 3254d17..e1a0f0b 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -51,17 +51,19 @@
 
 		qcom,cpr-ref-clk = <19200>;
 		qcom,cpr-timer-delay = <5000>;
-		qcom,cpr-timer-cons-up = <1>;
+		qcom,cpr-timer-cons-up = <0>;
 		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-up-threshold = <0>;
+		qcom,cpr-down-threshold = <10>;
+		qcom,cpr-idle-clocks = <0>;
 		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>;
+
+		qcom,cpr-enable;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index 938b2aa..faa7a41 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,spm@f9089000 {
 		compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index deeb051..5f9365a 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 /include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610 QRD";
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index f5a19fe..a62df58 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -412,6 +412,10 @@
 		rpm-standalone;
 	};
 
+	qcom,bcl {
+		compatible = "qcom,bcl";
+	};
+
 	qcom,msm-mem-hole {
 		compatible = "qcom,msm-mem-hole";
 		qcom,memblock-remove = <0x07B00000 0x6400000>; /* Address and Size of Hole */
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 786e9e3..456b079 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -11,8 +11,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,msm-cam@fd8C0000 {
 		compatible = "qcom,msm-cam";
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 2114686..7c191fc 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -380,7 +380,7 @@
 		status = "okay";
 		pm8941_l19: regulator-l19 {
 			regulator-min-microvolt = <2900000>;
-			regulator-max-microvolt = <2900000>;
+			regulator-max-microvolt = <3300000>;
 			qcom,init-voltage = <2900000>;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index cebc99a..288a703 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,spm@f9089000 {
 		compatible = "qcom,spm-v2";
@@ -427,13 +425,13 @@
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
+	};
 
-		qcom,cpu-sleep-status@f9088008 {
-			compatible = "qcom,cpu-sleep-status";
-			reg = <0xf9088008 0x4>;
-			qcom,cpu-alias-addr = <0x10000>;
-			qcom,sleep-status-mask= <0x80000>;
-		};
+	qcom,cpu-sleep-status@f9088008 {
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x4>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index d3a0bc8..178a1ee 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,spm@f9089000 {
 		compatible = "qcom,spm-v2";
@@ -125,9 +123,9 @@
 		qcom,vctl-port = <0x0>;
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
-		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 32 b0 11 42 07 01 b0 44
 				50 02 32 50 0f];
 	};
 
@@ -423,13 +421,13 @@
 				<54 585 0 0>,
 				<54 585 0 800000>;
 		};
+	};
 
-		qcom,cpu-sleep-status@f9088008{
-			compatible = "qcom,cpu-sleep-status";
-			reg = <0xf9088008 0x100>;
-			qcom,cpu-alias-addr = <0x10000>;
-			qcom,sleep-status-mask= <0x80000>;
-		};
+	qcom,cpu-sleep-status@f9088008{
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x100>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 5ae8808..fc0636e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -589,6 +589,7 @@
 			<&msmgpio 54 0>, /* MISO */
 			<&msmgpio 53 0>; /* MOSI */
 		cs-gpios = <&msmgpio 55 0>;
+		qcom,master-id = <84>;
 	};
 
 	tspp: msm_tspp@f99d8000 {
@@ -822,6 +823,7 @@
 			<&msmgpio 1 0>, /* MISO */
 			<&msmgpio 0 0>; /* MOSI */
 		cs-gpios = <&msmgpio 9 0>;
+		qcom,master-id = <86>;
 	};
 
 	qcom,acpuclk@f9000000 {
@@ -1633,6 +1635,7 @@
 
 &gdsc_mdss {
 	qcom,clock-names = "core_clk", "lut_clk";
+	qcom,retain-periph;
 	status = "ok";
 };
 
@@ -1649,7 +1652,8 @@
 
 &gdsc_oxili_gx {
 	qcom,clock-names = "core_clk";
-	qcom,retain-mems;
+	qcom,retain-mem;
+	qcom,retain-periph;
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 673b640..8eb1119 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "skeleton.dtsi"
-
 &soc {
 	qcom,spm@f9009000 {
 		compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f654545..d617c27 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -244,9 +244,9 @@
 			qcom,dst-bam-physical-address = <0xf9a44000>;
 			qcom,dst-bam-pipe-index = <2>;
 			qcom,data-fifo-offset = <0x4100>;
-			qcom,data-fifo-size = <0x400>;
+			qcom,data-fifo-size = <0x700>;
 			qcom,descriptor-fifo-offset = <0x4000>;
-			qcom,descriptor-fifo-size = <0x400>;
+			qcom,descriptor-fifo-size = <0x100>;
 		};
 		qcom,pipe3 {
 			label = "hsic-ipa-in-0";
@@ -516,6 +516,25 @@
 		qcom,calib-mode = "fuse_map1";
 	};
 
+	qcom,msm-thermal {
+		compatible = "qcom,msm-thermal";
+		qcom,sensor-id = <0>;
+		qcom,poll-ms = <250>;
+		qcom,limit-temp = <60>;
+		qcom,temp-hysteresis = <10>;
+		qcom,freq-step = <2>;
+		qcom,freq-control-mask = <0x0>;
+		qcom,vdd-restriction-temp = <5>;
+		qcom,vdd-restriction-temp-hysteresis = <10>;
+		vdd_dig-supply = <&pm8019_l10_corner>;
+
+		qcom,vdd-dig-rstr{
+			qcom,vdd-rstr-reg = "vdd_dig";
+			qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+			qcom,min-level = <1>; /* No Request */
+		};
+	};
+
 	qcom,msm-rng@f9bff000 {
                 compatible = "qcom,msm-rng";
                 reg = <0xf9bff000 0x200>;
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index a004835..33e1923 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -22,7 +22,6 @@
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
-CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
 CONFIG_KPROBES=y
@@ -50,7 +49,6 @@
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 CONFIG_MSM_IPC_ROUTER_SECURITY=y
 CONFIG_MSM_QMI_INTERFACE=y
-# CONFIG_MSM_HW3D is not set
 CONFIG_MSM_RPM_REGULATOR_SMD=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_SYSMON_COMM=y
@@ -88,7 +86,6 @@
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -101,7 +98,6 @@
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
 CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -210,8 +206,6 @@
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_SYNC=y
-CONFIG_SW_SYNC=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -249,6 +243,7 @@
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
 CONFIG_I2C=y
@@ -315,6 +310,9 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -328,10 +326,6 @@
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_SDHCI_MSM=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_DWC3_MSM=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_DIAG_CHAR=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -343,6 +337,7 @@
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
 CONFIG_ANDROID_LOGGER=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 10414e1..37c9554 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -152,13 +152,6 @@
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DEBUG=y
 CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index aa3befa..f9295b2 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -151,13 +151,6 @@
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DEBUG=y
 CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index d58f7fb..7420092 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -212,6 +212,12 @@
 CONFIG_DUMMY=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
@@ -237,6 +243,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -303,7 +310,6 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
@@ -311,18 +317,6 @@
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -339,6 +333,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
@@ -365,15 +360,6 @@
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
 CONFIG_MSM_IOMMU_V1=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_HWEVENT=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -413,12 +399,3 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPPOE=y
-CONFIG_N_HDLC=y
-CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 07378b2..3798987 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -213,6 +213,12 @@
 CONFIG_TUN=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
@@ -238,6 +244,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -328,7 +335,6 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
@@ -336,18 +342,6 @@
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -364,6 +358,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
@@ -438,12 +433,3 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPPOE=y
-CONFIG_N_HDLC=y
-CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 3bbff5c..fc34d53 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -224,6 +224,7 @@
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
@@ -239,6 +240,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -276,7 +278,6 @@
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
 CONFIG_MSM_ISPIF=y
-# CONFIG_MSM_ISPIF_V1 is not set
 CONFIG_MSMB_CAMERA=y
 CONFIG_OV9724=y
 CONFIG_MSMB_JPEG=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index d11773f..d3c8b77 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -222,6 +222,7 @@
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
@@ -237,6 +238,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -268,15 +270,13 @@
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
 CONFIG_MSM_CAMERA_SENSOR=y
-# CONFIG_MSM_CPP is not set
 CONFIG_MSM_CCI=y
-CONFIG_MSM_CSI22_HEADER=y
 CONFIG_MSM_CSI20_HEADER=y
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
 CONFIG_MSM_ISPIF=y
-# CONFIG_MSM_ISPIF_V1 is not set
 CONFIG_MSMB_CAMERA=y
+CONFIG_MSM_CSI22_HEADER=y
 CONFIG_OV9724=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 1b465af..da4de08 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -278,6 +278,7 @@
 # CONFIG_I2C_MSM is not set
 CONFIG_I2C_QUP=y
 CONFIG_I2C_SSBI=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 40fde84..e30c7d8 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -278,6 +278,7 @@
 # CONFIG_I2C_MSM is not set
 CONFIG_I2C_QUP=y
 CONFIG_I2C_SSBI=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index aefc7c9..4610597 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -319,6 +319,7 @@
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MSM is not set
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index fbad97a..9b55c3b 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -83,6 +83,7 @@
 CONFIG_MSM_RPM_RBCPR_STATS_LOG=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 154a368..4d124f0 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -290,6 +290,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -373,6 +374,7 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 2605234..1ffa7d2 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -63,6 +63,7 @@
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
@@ -379,6 +380,7 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 3b84f8f..9e8e6ac 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -53,6 +53,7 @@
 CONFIG_MSM_RPM_STATS_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 3f15a68..d02f5da 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -55,7 +55,6 @@
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=m
-CONFIG_MSM_RTB=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_MSM_BOOT_STATS=y
@@ -210,6 +209,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -225,8 +225,8 @@
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
-CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index c771bc4..64c8535 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -50,6 +50,7 @@
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
@@ -228,8 +229,8 @@
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
-CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 7824502..85fa764 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2324,8 +2324,8 @@
 
 config MSM_BUSPM_DEV
 	tristate "MSM Bus Performance Monitor Kernel Module"
-	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
-	default m
+	depends on MSM_BUS_SCALING
+	default n
 	help
 	  This kernel module is used to mmap() hardware registers for the
 	  performance monitors, counters, etc. The module can also be used to
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 9a34d87..1c07dc1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -277,7 +277,7 @@
 obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
 obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
-obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o
+obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o bms-batterydata-qrd-4v2-1300mah.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 733c7a8..0028d6e 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -87,7 +87,6 @@
 
 static struct acpuclk_drv_data drv_data = {
 	.freq_tbl = acpu_freq_tbl_8226,
-	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
 	.vdd_max_cpu = CPR_CORNER_TURBO,
 	.src_clocks = {
diff --git a/arch/arm/mach-msm/acpuclock-9625.c b/arch/arm/mach-msm/acpuclock-9625.c
index 42659f9..a4a5b2a 100644
--- a/arch/arm/mach-msm/acpuclock-9625.c
+++ b/arch/arm/mach-msm/acpuclock-9625.c
@@ -65,7 +65,6 @@
 
 static struct acpuclk_drv_data drv_data = {
 	.freq_tbl = acpu_freq_tbl,
-	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
 	.vdd_max_cpu = LVL_HIGH,
 	.vdd_max_mem = 1050000,
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index afa6909..2c3f97b 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -138,6 +138,49 @@
 		pr_warn("acpu rcg didn't update its configuration\n");
 }
 
+static struct clkctl_acpu_speed *__init find_cur_cpu_level(void)
+{
+	struct clkctl_acpu_speed *f, *max = priv->freq_tbl;
+	void __iomem *apcs_rcg_config = priv->apcs_rcg_config;
+	struct acpuclk_reg_data *r = &priv->reg_data;
+	u32 regval, div, src;
+	unsigned long rate;
+	struct clk *parent;
+
+	regval = readl_relaxed(apcs_rcg_config);
+	src = regval & r->cfg_src_mask;
+	src >>= r->cfg_src_shift;
+
+	div = regval & r->cfg_div_mask;
+	div >>= r->cfg_div_shift;
+	/* No support for half-integer dividers */
+	div = div > 1 ? (div + 1) / 2 : 0;
+
+	for (f = priv->freq_tbl; f->khz; f++) {
+		if (f->use_for_scaling)
+			max = f;
+
+		if (f->src_sel != src || f->src_div != div)
+			continue;
+
+		parent = priv->src_clocks[f->src].clk;
+		rate = parent->rate / (div ? div : 1);
+		if (f->khz * 1000 == rate)
+			break;
+	}
+
+	if (f->khz)
+		return f;
+
+	pr_err("CPUs are running at an unknown rate. Defaulting to %u KHz.\n",
+		max->khz);
+
+	/* Change to a safe frequency */
+	select_clk_source_div(priv, priv->freq_tbl);
+	/* Default to largest frequency */
+	return max;
+}
+
 static int set_speed_atomic(struct clkctl_acpu_speed *tgt_s)
 {
 	struct clkctl_acpu_speed *strt_s = priv->current_speed;
@@ -231,7 +274,7 @@
 	strt_s = priv->current_speed;
 
 	/* Return early if rate didn't change */
-	if (rate == strt_s->khz)
+	if (rate == strt_s->khz && reason != SETRATE_INIT)
 		goto out;
 
 	/* Find target frequency */
@@ -244,7 +287,7 @@
 	}
 
 	/* Increase VDD levels if needed */
-	if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
+	if ((reason == SETRATE_CPUFREQ)
 			&& (tgt_s->khz > strt_s->khz)) {
 		rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
 		if (rc)
@@ -274,7 +317,7 @@
 	set_bus_bw(tgt_s->bw_level);
 
 	/* Drop VDD levels if we can. */
-	if (tgt_s->khz < strt_s->khz)
+	if (tgt_s->khz < strt_s->khz || reason == SETRATE_INIT)
 		decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
 
 out:
@@ -328,8 +371,8 @@
 int __init acpuclk_cortex_init(struct platform_device *pdev,
 	struct acpuclk_drv_data *data)
 {
-	unsigned long max_cpu_khz = 0;
-	int i, rc;
+	int rc;
+	int parent;
 
 	priv = data;
 	mutex_init(&priv->lock);
@@ -343,46 +386,41 @@
 		BUG();
 	}
 
-	/* Improve boot time by ramping up CPU immediately */
-	for (i = 0; priv->freq_tbl[i].khz != 0; i++)
-		if (priv->freq_tbl[i].use_for_scaling)
-			max_cpu_khz = priv->freq_tbl[i].khz;
-
 	/* Initialize regulators */
 	rc = increase_vdd(priv->vdd_max_cpu, priv->vdd_max_mem);
 	if (rc)
-		goto err_vdd;
+		return rc;
 
 	if (priv->vdd_mem) {
 		rc = regulator_enable(priv->vdd_mem);
 		if (rc) {
 			dev_err(&pdev->dev, "regulator_enable for mem failed\n");
-			goto err_vdd;
+			return rc;
 		}
 	}
 
 	rc = regulator_enable(priv->vdd_cpu);
 	if (rc) {
 		dev_err(&pdev->dev, "regulator_enable for cpu failed\n");
-		goto err_vdd_cpu;
+		return rc;
 	}
 
-	/*
-	 * Select a state which is always a valid transition to align SW with
-	 * the HW configuration set by the bootloaders.
-	 */
-	acpuclk_cortex_set_rate(0, acpuclk_cortex_data.power_collapse_khz,
-		SETRATE_INIT);
-	acpuclk_cortex_set_rate(0, max_cpu_khz, SETRATE_INIT);
+	priv->current_speed = find_cur_cpu_level();
+	parent = priv->current_speed->src;
+	rc = clk_prepare_enable(priv->src_clocks[parent].clk);
+	if (rc) {
+		dev_err(&pdev->dev, "handoff: prepare_enable failed\n");
+		return rc;
+	}
+
+	rc = acpuclk_cortex_set_rate(0, priv->current_speed->khz, SETRATE_INIT);
+	if (rc) {
+		dev_err(&pdev->dev, "handoff: set rate failed\n");
+		return rc;
+	}
 
 	acpuclk_register(&acpuclk_cortex_data);
 	cpufreq_table_init();
 
 	return 0;
-
-err_vdd_cpu:
-	if (priv->vdd_mem)
-		regulator_disable(priv->vdd_mem);
-err_vdd:
-	return rc;
 }
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
new file mode 100644
index 0000000..a2c6391
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+static struct single_row_lut fcc_temp = {
+	.x = {-20, 0, 25, 40, 60},
+	.y = {1343, 1353, 1408, 1345, 1342},
+	.cols = 5
+};
+
+static struct single_row_lut fcc_sf = {
+	.x = {0},
+	.y = {100},
+	.cols = 1
+};
+
+static struct sf_lut rbatt_sf = {
+	.rows = 29,
+	.cols = 5,
+	.row_entries = {-20, 0, 25, 40, 60},
+	.percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35,
+		30, 25, 20, 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+	.sf = {
+	       {604, 192, 100, 79, 71},
+	       {605, 192, 100, 79, 71},
+	       {641, 205, 103, 81, 72},
+	       {641, 221, 108, 84, 75},
+	       {622, 238, 115, 87, 77},
+	       {612, 254, 123, 92, 79},
+	       {605, 252, 137, 96, 83},
+	       {607, 219, 154, 104, 87},
+	       {613, 202, 135, 109, 89},
+	       {626, 200, 106, 90, 77},
+	       {656, 201, 101, 82, 75},
+	       {684, 204, 100, 84, 77},
+	       {710, 211, 100, 85, 79},
+	       {747, 224, 106, 89, 82},
+	       {806, 241, 116, 90, 80},
+	       {905, 260, 119, 87, 77},
+	       {1046, 291, 113, 87, 77},
+	       {1309, 329, 116, 90, 79},
+	       {1476, 300, 126, 97, 83},
+	       {1598, 311, 127, 98, 84},
+	       {1771, 323, 130, 99, 85},
+	       {1984, 342, 136, 101, 86},
+	       {2438, 368, 140, 101, 86},
+	       {3381, 388, 137, 100, 84},
+	       {4913, 414, 141, 99, 86},
+	       {6979, 468, 155, 104, 90},
+	       {9968, 565, 192, 113, 98},
+	       {16163, 833, 350, 140, 120},
+	       {36511, 6483, 4872, 472, 1095}
+	       }
+};
+
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+	.rows = 29,
+	.cols = 5,
+	.temp = {-20, 0, 25, 40, 60},
+	.percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35,
+		30, 25, 20, 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+	.ocv = {
+		{4177, 4174, 4199, 4167, 4162},
+		{4107, 4112, 4141, 4109, 4106},
+		{4058, 4064, 4091, 4061, 4059},
+		{3996, 4015, 4044, 4017, 4015},
+		{3947, 3975, 4001, 3978, 3976},
+		{3909, 3939, 3962, 3943, 3940},
+		{3874, 3901, 3926, 3911, 3907},
+		{3845, 3858, 3892, 3882, 3878},
+		{3821, 3826, 3851, 3849, 3846},
+		{3801, 3804, 3815, 3810, 3808},
+		{3788, 3789, 3793, 3789, 3787},
+		{3778, 3780, 3778, 3776, 3773},
+		{3769, 3776, 3770, 3767, 3764},
+		{3757, 3772, 3766, 3762, 3757},
+		{3740, 3765, 3762, 3754, 3744},
+		{3714, 3747, 3750, 3739, 3724},
+		{3668, 3706, 3717, 3710, 3697},
+		{3602, 3644, 3662, 3662, 3654},
+		{3533, 3571, 3601, 3607, 3605},
+		{3518, 3557, 3583, 3592, 3590},
+		{3500, 3543, 3565, 3576, 3574},
+		{3478, 3528, 3546, 3559, 3557},
+		{3451, 3506, 3521, 3538, 3534},
+		{3417, 3473, 3481, 3505, 3496},
+		{3377, 3423, 3424, 3454, 3444},
+		{3327, 3361, 3351, 3391, 3380},
+		{3261, 3279, 3258, 3310, 3297},
+		{3165, 3165, 3138, 3198, 3182},
+		{3000, 3000, 3000, 3000, 3000}
+		}
+};
+
+struct bms_battery_data qrd_4v2_1300mah_data = {
+	.fcc = 1300,
+	.fcc_temp_lut = &fcc_temp,
+	.fcc_sf_lut = &fcc_sf,
+	.pc_temp_ocv_lut = &pc_temp_ocv,
+	.rbatt_sf_lut = &rbatt_sf,
+	.default_rbatt_mohm = 172
+};
diff --git a/arch/arm/mach-msm/board-8084-gpiomux.c b/arch/arm/mach-msm/board-8084-gpiomux.c
index 8d5bb49..27f2e0d 100644
--- a/arch/arm/mach-msm/board-8084-gpiomux.c
+++ b/arch/arm/mach-msm/board-8084-gpiomux.c
@@ -17,6 +17,27 @@
 #include <mach/board.h>
 #include <mach/gpiomux.h>
 
+static struct gpiomux_setting gpio_i2c_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+	{
+		.gpio      = 10,		/* BLSP1 QUP3 I2C_SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 11,		/* BLSP1 QUP3 I2C_SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+};
+
 void __init apq8084_init_gpiomux(void)
 {
 	int rc;
@@ -26,4 +47,6 @@
 		pr_err("%s failed %d\n", __func__, rc);
 		return;
 	}
+
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
 }
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 7b81c11..56826c7 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -75,6 +75,8 @@
 static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
 			"msm_serial_hsl.0", NULL),
+	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF9922000, \
+			"msm_serial_hsl.1", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
@@ -96,6 +98,8 @@
 
 static const char *mpq8092_dt_match[] __initconst = {
 	"qcom,mpq8092-sim",
+	"qcom,mpq8092-rumi",
+	"qcom,mpq8092",
 	NULL
 };
 
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 6491452..378edc8 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -485,7 +485,7 @@
 	msm_gpiomux_install(msm_auxpcm_configs,
 			ARRAY_SIZE(msm_auxpcm_configs));
 
-	if (of_board_is_cdp() || of_board_is_mtp())
+	if (of_board_is_cdp() || of_board_is_mtp() || of_board_is_xpm())
 		msm_gpiomux_install(usb_otg_sw_configs,
 					ARRAY_SIZE(usb_otg_sw_configs));
 }
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 4645d34..39efcd8 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -49,6 +49,7 @@
 #include "clock.h"
 #include "platsmp.h"
 #include "spm.h"
+#include "pm.h"
 #include "lpm_resources.h"
 #include "modem_notifier.h"
 
@@ -111,6 +112,7 @@
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
+	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
 	qpnp_regulator_init();
 	if (of_board_is_rumi())
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 7096f3f..b261ce4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -84,6 +84,20 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting lcd_te_act_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting lcd_te_sus_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
 static struct gpiomux_setting gpio_keys_active = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -111,6 +125,13 @@
 			[GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
 		},
 	},
+	{
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_te_act_config,
+			[GPIOMUX_SUSPENDED] = &lcd_te_sus_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
@@ -231,6 +252,125 @@
 	},
 };
 
+static struct gpiomux_setting gpio_suspend_config[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO,  /* IN-NP */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	{
+		.func = GPIOMUX_FUNC_GPIO,  /* O-LOW */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+		.dir = GPIOMUX_OUT_LOW,
+	},
+};
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/ /* 0 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*suspend*/ /* 1 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*i2c suspend*/ /* 2 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 0*/ /* 3 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend 0*/ /* 4 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+};
+
+static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
+	{
+		.gpio = 13, /* CAM_MCLK0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 14, /* CAM_MCLK1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 16, /* CCI_I2C_SDA */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+		},
+	},
+	{
+		.gpio = 17, /* CCI_I2C_SCL */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+		},
+	},
+	{
+		.gpio = 18, /* FLASH_LED_EN */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+	{
+		.gpio = 19, /* FLASH_LED_NOW */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+	{
+		.gpio = 8, /* CAM1_STANDBY_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+	{
+		.gpio = 15, /* CAM1_RST_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+	{
+		.gpio = 20, /* WEBCAM1_STANDBY */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+	{
+		.gpio = 21, /* WEBCAM2_RESET_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm_keypad_configs[] __initdata = {
 	{
 		.gpio = 72,
@@ -298,4 +438,5 @@
 	msm_gpiomux_install(msm_keypad_configs,
 				ARRAY_SIZE(msm_keypad_configs));
 	msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
+	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
 }
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 962ed65..b4d77f1 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -50,6 +50,7 @@
 #include "clock.h"
 #include "platsmp.h"
 #include "spm.h"
+#include "pm.h"
 #include "lpm_resources.h"
 #include "modem_notifier.h"
 
@@ -106,6 +107,7 @@
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
+	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
 	qpnp_regulator_init();
 	tsens_tm_init_driver();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 35e46fc..771359c 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -95,6 +95,7 @@
 	msm_smd_init();
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
+	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
 	krait_power_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 6bb5655..56246dd 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -22,6 +22,7 @@
 #include <linux/of_irq.h>
 #include <linux/memory.h>
 #include <linux/msm_tsens.h>
+#include <linux/msm_thermal.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -239,6 +240,7 @@
 	msm_clock_init(&msm9625_clock_init_data);
 	msm9625_init_buses();
 	tsens_tm_init_driver();
+	msm_thermal_device_init();
 }
 
 void __init msm9625_init(void)
diff --git a/arch/arm/mach-msm/board-krypton-gpiomux.c b/arch/arm/mach-msm/board-krypton-gpiomux.c
index 3d86ba7..ee38e5f 100644
--- a/arch/arm/mach-msm/board-krypton-gpiomux.c
+++ b/arch/arm/mach-msm/board-krypton-gpiomux.c
@@ -17,12 +17,37 @@
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 
+#define KS8851_IRQ_GPIO 75
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct msm_gpiomux_config msm_eth_config[] = {
+	{
+		.gpio = KS8851_IRQ_GPIO,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
 static struct gpiomux_setting gpio_uart_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
 		.gpio      = 8,	       /* BLSP1 UART TX */
@@ -36,6 +61,30 @@
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
 	},
+	{
+		.gpio      = 20,		/* BLSP1 QUP6 SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 21,		/* BLSP1 QUP6 SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 23,		/* BLSP1 QUP6 SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 22,		/* BLSP1 QUP6 SPI_CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
 };
 
 void __init msmkrypton_init_gpiomux(void)
@@ -49,4 +98,7 @@
 	}
 
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(msm_eth_config, ARRAY_SIZE(msm_eth_config));
+#endif
 }
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index ff7c8e0..b40fcfa 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -34,6 +34,9 @@
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("core_clk",	SPI_CLK,	"f9928000.spi",  OFF),
+	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"f9928000.spi",  OFF),
+
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index 1af026b..bec9f1b4 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -75,12 +75,13 @@
 	CLK_DUMMY("",	usb_hsic_system_clk_src.c,	"", OFF),
 	CLK_DUMMY("",	gcc_bam_dma_ahb_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_bam_dma_inactivity_timers_clk.c,	"", OFF),
-	CLK_DUMMY("",	gcc_blsp1_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("iface_clk",	gcc_blsp1_ahb_clk.c,	"f9925000.i2c", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup1_i2c_apps_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup1_spi_apps_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup2_i2c_apps_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup2_spi_apps_clk.c,	"", OFF),
-	CLK_DUMMY("",	gcc_blsp1_qup3_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("core_clk",	gcc_blsp1_qup3_i2c_apps_clk.c,	"f9925000.i2c",
+									OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup3_spi_apps_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup4_i2c_apps_clk.c,	"", OFF),
 	CLK_DUMMY("",	gcc_blsp1_qup4_spi_apps_clk.c,	"", OFF),
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
index a8520e6..9de97ea 100644
--- a/arch/arm/mach-msm/clock-8092.c
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -38,6 +38,8 @@
 static struct clk_lookup msm_clocks_8092[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.1", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.1", OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
 	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
 	CLK_DUMMY("core_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
@@ -246,7 +248,9 @@
 	CLK_DUMMY("",	mmss_mmssnoc_ahb_clk.c,	"", OFF),
 	CLK_DUMMY("",	mmss_mmssnoc_axi_clk.c,	"", OFF),
 	CLK_DUMMY("",	mmss_s0_axi_clk.c,	"", OFF),
-	CLK_DUMMY("",	ocmemcx_ocmemnoc_clk.c,	"", OFF),
+	CLK_DUMMY("core_clk",  ocmemgx_core_clk.c, "fdd00000.qcom,ocmem", OFF),
+	CLK_DUMMY("iface_clk",	ocmemcx_ocmemnoc_clk.c,	"fdd00000.qcom.ocmem",
+							 OFF),
 	CLK_DUMMY("",	oxili_ocmemgx_clk.c,	"", OFF),
 	CLK_DUMMY("",	oxili_gfx3d_clk.c,	"", OFF),
 	CLK_DUMMY("",	oxilicx_ahb_clk.c,	"", OFF),
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1477541..fd3ba14 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -1891,7 +1891,7 @@
 	.c = {
 		.dbg_name = "vcodec0_clk_src",
 		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP3(LOW, 66670000, NOMINAL, 133330000, HIGH,
+		VDD_DIG_FMAX_MAP3(LOW, 66700000, NOMINAL, 133330000, HIGH,
 			160000000),
 		CLK_INIT(vcodec0_clk_src.c),
 	},
@@ -2846,11 +2846,6 @@
 		},
 		.num_fmax = VDD_SR2_PLL_NUM,
 		CLK_INIT(a7sspll.c),
-		/*
-		 * Need to skip handoff of the acpu pll to avoid
-		 * turning off the pll when the cpu is using it
-		 */
-		.flags = CLKFLAG_SKIP_HANDOFF,
 	},
 };
 
@@ -2873,6 +2868,7 @@
 
 static DEFINE_CLK_VOTER(qseecom_ce1_clk_src, &ce1_clk_src.c, 100000000);
 static DEFINE_CLK_VOTER(scm_ce1_clk_src, &ce1_clk_src.c, 100000000);
+static DEFINE_CLK_VOTER(gud_ce1_clk_src, &ce1_clk_src.c, 100000000);
 
 static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
@@ -3241,6 +3237,11 @@
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,     "qseecom"),
 	CLK_LOOKUP("core_clk_src", qseecom_ce1_clk_src.c, "qseecom"),
 
+	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,         "mcd"),
+	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,     "mcd"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,     "mcd"),
+	CLK_LOOKUP("core_clk_src", gud_ce1_clk_src.c,     "mcd"),
+
 	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,         "scm"),
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,     "scm"),
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,     "scm"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index e34b539..58c5745 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -577,11 +577,6 @@
 		},
 		.num_fmax = VDD_SR2_PLL_NUM,
 		CLK_INIT(a7sspll.c),
-		/*
-		 * Need to skip handoff of the acpu pll to avoid
-		 * turning off the pll when the cpu is using it
-		 */
-		.flags = CLKFLAG_SKIP_HANDOFF,
 	},
 };
 
@@ -1833,6 +1828,7 @@
 };
 
 static struct clk_freq_tbl ftbl_mclk0_1_clk[] = {
+	F_MM(24000000, gpll0, 5, 1, 5),
 	F_MM(66670000, gpll0, 9, 0, 0),
 	F_END,
 };
@@ -3002,6 +2998,77 @@
 							 "fd010000.qcom,iommu"),
 	CLK_LOOKUP("core_clk",         pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
 
+	/* MM sensor clocks */
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006f"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
+
+
+	/* CSIPHY clocks */
+	CLK_LOOKUP("csiphy_timer_src_clk", csi0phytimer_clk_src.c,
+		"fda00c00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", csi0phytimer_clk.c,
+		"fda00c00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
+		"fda01000.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", csi1phytimer_clk.c,
+		"fda01000.qcom,csiphy"),
+
+	/* CSID clocks */
+
+	CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00000.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda00000.qcom,csid"),
+	CLK_LOOKUP("csi_clk", csi0_clk.c,         "fda00000.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", csi0phy_clk.c,  "fda00000.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", csi0pix_clk.c,  "fda00000.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", csi0rdi_clk.c,  "fda00000.qcom,csid"),
+
+	/*CLK_LOOKUP("csi0_phy_mux_sel", csi0phy_mux_clk.c,
+		"fda00000.qcom,csid"),
+	CLK_LOOKUP("csi0_pix_mux_sel", csi0pix_mux_clk.c,
+		"fda00000.qcom,csid"),
+	CLK_LOOKUP("csi0_rdi_mux_sel", rdi0_mux_clk.c,
+		"fda00000.qcom,csid"),*/
+
+	CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00400.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda00400.qcom,csid"),
+	CLK_LOOKUP("csi_clk", csi1_clk.c,         "fda00400.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", csi1phy_clk.c,  "fda00400.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", csi1pix_clk.c,  "fda00400.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", csi1rdi_clk.c,  "fda00400.qcom,csid"),
+
+	/*CLK_LOOKUP("csi1_phy_mux_sel", csi1phy_mux_clk.c,
+		"fda00400.qcom,csid"),
+	CLK_LOOKUP("csi1_pix_mux_sel", csi0pix_mux_clk.c,
+		"fda00400.qcom,csid"),
+	CLK_LOOKUP("csi1_rdi_mux_sel", rdi1_mux_clk.c,
+		"fda00400.qcom,csid"),*/
+
+	/* ISPIF clocks */
+	CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda00800.qcom,ispif"),
+	CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda00800.qcom,ispif"),
+
+	CLK_LOOKUP("csi_pix_clk", csi0pix_clk.c,
+		"fda00800.qcom,ispif"),
+	CLK_LOOKUP("csi_rdi_clk", csi0rdi_clk.c,
+		"fda00800.qcom,ispif"),
+	CLK_LOOKUP("csi_pix1_clk", csi1pix_clk.c,
+		"fda00800.qcom,ispif"),
+	CLK_LOOKUP("csi_rdi1_clk", csi1rdi_clk.c,
+		"fda00800.qcom,ispif"),
+	CLK_LOOKUP("csi_rdi2_clk", csi1rdi_clk.c,
+		"fda00800.qcom,ispif"),
+
+	CLK_LOOKUP("vfe_clk_src", vfe_clk_src.c, "fde00000.qcom,vfe"),
+	CLK_LOOKUP("vfe_clk", vfe_clk.c, "fde00000.qcom,vfe"),
+
+	CLK_LOOKUP("csi_vfe_clk", csi_vfe_clk.c, "fde00000.qcom,vfe"),
+	CLK_LOOKUP("vfe_ahb_clk", vfe_ahb_clk.c, "fde00000.qcom,vfe"),
+
+	CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "fde00000.qcom,vfe"),
+
+
 	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 3277d75..facd6ba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -390,10 +390,6 @@
 	PLL_F_END
 };
 
-/*
- * Need to skip handoff of the acpu pll to avoid handoff code
- * to turn off the pll when the acpu is running off this pll.
- */
 static struct pll_clk apcspll_clk_src = {
 	.mode_reg = (void __iomem *)APCS_CPU_PLL_MODE_REG,
 	.l_reg = (void __iomem *)APCS_CPU_PLL_L_REG,
@@ -415,7 +411,6 @@
 		.dbg_name = "apcspll_clk_src",
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(apcspll_clk_src.c),
-		.flags = CLKFLAG_SKIP_HANDOFF,
 	},
 };
 
@@ -1579,6 +1574,10 @@
 };
 
 struct measure_mux_entry measure_mux_common[] __initdata = {
+	{&snoc_clk.c,				GCC_BASE, 0x0000},
+	{&cnoc_clk.c,				GCC_BASE, 0x0008},
+	{&pnoc_clk.c,				GCC_BASE, 0x0010},
+	{&bimc_clk.c,				GCC_BASE, 0x0155},
 	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d0},
 	{&gcc_usb_hsic_io_cal_sleep_clk.c,	GCC_BASE, 0x005c},
 	{&gcc_usb_hsic_xcvr_fs_clk.c,		GCC_BASE, 0x005d},
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index fcdcb29..908107e 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -294,13 +294,7 @@
 {
 	struct pll_freq_tbl *nf;
 	struct pll_clk *pll = to_pll_clk(c);
-	u32 mode;
-
-	mode = readl_relaxed(PLL_MODE_REG(pll));
-
-	/* Don't change PLL's rate if it is enabled */
-	if ((mode & PLL_MODE_MASK) == PLL_MODE_MASK)
-		return -EBUSY;
+	unsigned long flags;
 
 	for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END
 			&& nf->freq_hz != rate; nf++)
@@ -309,12 +303,24 @@
 	if (nf->freq_hz == PLL_FREQ_END)
 		return -EINVAL;
 
+	/*
+	 * Ensure PLL is off before changing rate. For optimization reasons,
+	 * assume no downstream clock is using actively using it.
+	 */
+	spin_lock_irqsave(&c->lock, flags);
+	if (c->count)
+		c->ops->disable(c);
+
 	writel_relaxed(nf->l_val, PLL_L_REG(pll));
 	writel_relaxed(nf->m_val, PLL_M_REG(pll));
 	writel_relaxed(nf->n_val, PLL_N_REG(pll));
 
 	__pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks);
 
+	if (c->count)
+		c->ops->enable(c);
+
+	spin_unlock_irqrestore(&c->lock, flags);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index e647d1d..5550282 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -682,10 +682,20 @@
 	}
 
 	rc = regulator_enable(cpr_vreg->vdd_apc);
-	if (!rc)
-		cpr_vreg->vreg_enabled = true;
-	else
+	if (rc) {
 		pr_err("regulator_enable: vdd_apc: rc=%d\n", rc);
+		return rc;
+	}
+
+	cpr_vreg->vreg_enabled = true;
+
+	mutex_lock(&cpr_vreg->cpr_mutex);
+	if (cpr_is_allowed(cpr_vreg) && cpr_vreg->corner) {
+		cpr_irq_clr(cpr_vreg);
+		cpr_corner_switch(cpr_vreg, cpr_vreg->corner);
+		cpr_ctl_enable(cpr_vreg);
+	}
+	mutex_unlock(&cpr_vreg->cpr_mutex);
 
 	return rc;
 }
@@ -700,10 +710,17 @@
 		if (cpr_vreg->vdd_mx)
 			rc = regulator_disable(cpr_vreg->vdd_mx);
 
-		if (rc)
+		if (rc) {
 			pr_err("regulator_disable: vdd_mx: rc=%d\n", rc);
-		else
-			cpr_vreg->vreg_enabled = false;
+			return rc;
+		}
+
+		cpr_vreg->vreg_enabled = false;
+
+		mutex_lock(&cpr_vreg->cpr_mutex);
+		if (cpr_is_allowed(cpr_vreg))
+			cpr_ctl_disable(cpr_vreg);
+		mutex_unlock(&cpr_vreg->cpr_mutex);
 	} else {
 		pr_err("regulator_disable: vdd_apc: rc=%d\n", rc);
 	}
@@ -739,7 +756,7 @@
 	if (rc)
 		goto _exit;
 
-	if (cpr_is_allowed(cpr_vreg)) {
+	if (cpr_is_allowed(cpr_vreg) && cpr_vreg->vreg_enabled) {
 		cpr_irq_clr(cpr_vreg);
 		cpr_corner_switch(cpr_vreg, corner);
 		cpr_ctl_enable(cpr_vreg);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 0963e27..774548c 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -47,7 +47,8 @@
 	void __iomem		*gdscr;
 	struct clk		**clocks;
 	int			clock_count;
-	bool			toggle_mems;
+	bool			toggle_mem;
+	bool			toggle_periph;
 	bool			toggle_logic;
 	bool			resets_asserted;
 };
@@ -86,11 +87,11 @@
 		sc->resets_asserted = false;
 	}
 
-	if (sc->toggle_mems) {
-		for (i = 0; i < sc->clock_count; i++) {
+	for (i = 0; i < sc->clock_count; i++) {
+		if (sc->toggle_mem)
 			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+		if (sc->toggle_periph)
 			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
-		}
 	}
 
 	/*
@@ -127,11 +128,11 @@
 		sc->resets_asserted = true;
 	}
 
-	if (sc->toggle_mems) {
-		for (i = 0; i < sc->clock_count; i++) {
+	for (i = 0; i < sc->clock_count; i++) {
+		if (sc->toggle_mem)
 			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+		if (sc->toggle_periph)
 			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-		}
 	}
 
 	return ret;
@@ -150,7 +151,7 @@
 	struct resource *res;
 	struct gdsc *sc;
 	uint32_t regval;
-	bool retain_mems;
+	bool retain_mem, retain_periph;
 	int i, ret;
 
 	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
@@ -222,18 +223,23 @@
 	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
 	writel_relaxed(regval, sc->gdscr);
 
-	retain_mems = of_property_read_bool(pdev->dev.of_node,
-					    "qcom,retain-mems");
+	retain_mem = of_property_read_bool(pdev->dev.of_node,
+					    "qcom,retain-mem");
+	retain_periph = of_property_read_bool(pdev->dev.of_node,
+					    "qcom,retain-periph");
 	for (i = 0; i < sc->clock_count; i++) {
-		if (retain_mems || (regval & PWR_ON_MASK)) {
+		if (retain_mem || (regval & PWR_ON_MASK))
 			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
-			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
-		} else {
+		else
 			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+		if (retain_periph || (regval & PWR_ON_MASK))
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+		else
 			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-		}
 	}
-	sc->toggle_mems = !retain_mems;
+	sc->toggle_mem = !retain_mem;
+	sc->toggle_periph = !retain_periph;
 	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
 						"qcom,skip-logic-collapse");
 	if (!sc->toggle_logic) {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index e9a4af0..20e3c3b 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -24,16 +24,9 @@
 
 extern volatile int pen_release;
 
-struct msm_hotplug_device {
-	struct completion cpu_killed;
-	unsigned int warm_boot;
-};
-
-
 static cpumask_t cpu_dying_mask;
 
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
-			msm_hotplug_devices);
+static DEFINE_PER_CPU(unsigned int, warm_boot_flag);
 
 static inline void cpu_enter_lowpower(void)
 {
@@ -95,7 +88,6 @@
 			__func__, smp_processor_id(), cpu);
 		BUG();
 	}
-	complete(&__get_cpu_var(msm_hotplug_devices).cpu_killed);
 	/*
 	 * we're ready for shutdown now, so do it
 	 */
@@ -161,11 +153,10 @@
 int msm_platform_secondary_init(unsigned int cpu)
 {
 	int ret;
-	struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+	unsigned int *warm_boot = &__get_cpu_var(warm_boot_flag);
 
-	if (!dev->warm_boot) {
-		dev->warm_boot = 1;
-		init_completion(&dev->cpu_killed);
+	if (!(*warm_boot)) {
+		*warm_boot = 1;
 		return 0;
 	}
 	msm_jtag_restore_state();
@@ -179,9 +170,6 @@
 
 static int __init init_hotplug(void)
 {
-
-	struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
-	init_completion(&dev->cpu_killed);
 	return register_hotcpu_notifier(&hotplug_rtb_notifier);
 }
 early_initcall(init_hotplug);
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
index ab5271f..608927c 100644
--- a/arch/arm/mach-msm/include/mach/msm_spi.h
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -14,8 +14,19 @@
  * SPI driver for Qualcomm MSM platforms.
  */
 
+/**
+ * msm_spi_platform_data: msm spi-controller's configuration data
+ *
+ * @active_only when set, votes when system active and removes the vote when
+ *       system goes idle (optimises for performance). When unset, voting using
+ *       runtime pm (optimizes for power).
+ * @master_id master id number of the controller's wrapper (BLSP or GSBI).
+ *       When zero, clock path voting is disabled.
+ */
 struct msm_spi_platform_data {
 	u32 max_clock_speed;
+	bool active_only;
+	u32  master_id;
 	int (*gpio_config)(void);
 	void (*gpio_release)(void);
 	int (*dma_config)(void);
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index bc76f56..a3e993d 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -298,7 +298,7 @@
  * Resets the USB BAM that has A2 pipes
  *
  */
-int usb_bam_a2_reset(void);
+int usb_bam_a2_reset(bool to_reconnect);
 
 /**
  * Indicates if the client of the USB BAM is ready to start
@@ -308,6 +308,14 @@
  *
  */
 int usb_bam_client_ready(bool ready);
+
+/**
+* Returns upon reset completion if reset is in progress
+* immediately otherwise.
+*
+*/
+void usb_bam_reset_complete(void);
+
 /**
 * Returns qdss index from the connections array.
 *
@@ -403,7 +411,7 @@
 	return -ENODEV;
 }
 
-static inline int usb_bam_a2_reset(void)
+static inline int usb_bam_a2_reset(bool to_reconnect)
 {
 	return -ENODEV;
 }
@@ -413,6 +421,11 @@
 	return -ENODEV;
 }
 
+static inline void usb_bam_reset_complete(void)
+{
+	return;
+}
+
 static inline int usb_bam_get_qdss_idx(u8 num)
 {
 	return -ENODEV;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 841ccf3..56eaa2b 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2258,6 +2258,29 @@
 	return ret;
 }
 
+/**
+ * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
+ * @port_ptr: Pointer to the local port
+ * @data : Pointer to the socket buffer head
+ * @src: Pointer to local port address
+ * @timeout: < 0 timeout indicates infinite wait till a message arrives.
+ *	     > 0 timeout indicates the wait time.
+ *	     0 indicates that we do not wait.
+ * @return: = Number of bytes read(On successful read operation).
+ *	    = 0 (If there are no pending messages and timeout is 0).
+ *	    = -EINVAL (If either of the arguments, port_ptr or data is invalid)
+ *	    = -EFAULT (If there are no pending messages when timeout is > 0
+ *	      and the wait_event_interruptible_timeout has returned value > 0)
+ *	    = -ERESTARTSYS (If there are no pending messages when timeout
+ *	      is < 0 and wait_event_interruptible was interrupted by a signal)
+ *
+ * This function reads the messages that are destined for a local port. It
+ * is used by modules that exist with-in the kernel and use IPC Router for
+ * transport. The function checks if there are any messages that are already
+ * received. If yes, it reads them, else it waits as per the timeout value.
+ * On a successful read, the return value of the function indicates the number
+ * of bytes that are read.
+ */
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
 			     struct sk_buff_head **data,
 			     struct msm_ipc_addr *src,
@@ -2291,7 +2314,7 @@
 				return -EFAULT;
 		}
 		if (timeout == 0)
-			return -ETIMEDOUT;
+			return 0;
 		mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	}
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2326,7 +2349,11 @@
 	struct sk_buff_head *in_skb_head;
 	int ret;
 
-	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
+	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
+
+	if (ret == 0)
+		return -ENOMSG;
+
 	if (ret < 0) {
 		pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
 			__func__, ret);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 9b16944..3ff7530 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -491,7 +491,7 @@
 	deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT);
 	if (!deffab) {
 		MSM_BUS_ERR("Error finding default fabric\n");
-		return -ENXIO;
+		return 0;
 	}
 
 	nfab = msm_bus_get_num_fab();
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 4c4635a..9b3e500 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.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
@@ -450,6 +450,11 @@
 	/* Read the messages */
 	rc = msm_ipc_router_read_msg((struct msm_ipc_port *)(handle->src_port),
 				     &src_addr, &recv_msg, &recv_msg_len);
+	if (rc == -ENOMSG) {
+		mutex_unlock(&handle->handle_lock);
+		return rc;
+	}
+
 	if (rc < 0) {
 		pr_err("%s: Read failed %d\n", __func__, rc);
 		mutex_unlock(&handle->handle_lock);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 545723c..a054077 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1616,14 +1616,6 @@
 {
 	int rc;
 
-	rc = platform_driver_register(&msm_cpu_status_driver);
-
-	if (rc) {
-		pr_err("%s(): failed to register driver %s\n", __func__,
-				msm_cpu_status_driver.driver.name);
-		return rc;
-	}
-
 	rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
 
 	if (rc) {
@@ -1647,3 +1639,8 @@
 	return platform_driver_register(&msm_pm_8x60_driver);
 }
 device_initcall(msm_pm_8x60_init);
+
+void __init msm_pm_sleep_status_init(void)
+{
+	platform_driver_register(&msm_cpu_status_driver);
+}
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 8a043d8..f2fc80b 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -136,10 +136,12 @@
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
 void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
 int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+void __init msm_pm_sleep_status_init(void);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
 static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
 static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline void msm_pm_sleep_status_init(void) {};
 #endif
 #ifdef CONFIG_HOTPLUG_CPU
 int msm_platform_secondary_init(unsigned int cpu);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1c8a25d..4ff4b3e 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -747,16 +747,17 @@
 		if (PageHighMem(page)) {
 			if (len + offset > PAGE_SIZE)
 				len = PAGE_SIZE - offset;
-			vaddr = kmap_high_get(page);
-			if (vaddr) {
-				vaddr += offset;
-				op(vaddr, len, dir);
-				kunmap_high(page);
-			} else if (cache_is_vipt()) {
-				/* unmapped pages might still be cached */
+
+			if (cache_is_vipt_nonaliasing()) {
 				vaddr = kmap_atomic(page);
 				op(vaddr + offset, len, dir);
 				kunmap_atomic(vaddr);
+			} else {
+				vaddr = kmap_high_get(page);
+				if (vaddr) {
+					op(vaddr + offset, len, dir);
+					kunmap_high(page);
+				}
 			}
 		} else {
 			vaddr = page_address(page) + offset;
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 7745854..839a18e 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -170,15 +170,18 @@
 	if (!PageHighMem(page)) {
 		__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 	} else {
-		void *addr = kmap_high_get(page);
-		if (addr) {
-			__cpuc_flush_dcache_area(addr, PAGE_SIZE);
-			kunmap_high(page);
-		} else if (cache_is_vipt()) {
-			/* unmapped pages might still be cached */
+		void *addr;
+
+		if (cache_is_vipt_nonaliasing()) {
 			addr = kmap_atomic(page);
 			__cpuc_flush_dcache_area(addr, PAGE_SIZE);
 			kunmap_atomic(addr);
+		} else {
+			addr = kmap_high_get(page);
+			if (addr) {
+				__cpuc_flush_dcache_area(addr, PAGE_SIZE);
+				kunmap_high(page);
+			}
 		}
 	}
 
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 26a06b8..770e1d6 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -715,12 +715,12 @@
 	if (error)
 		goto out_unregister;
 
+	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
 	if (drv->bus->p->drivers_autoprobe) {
 		error = driver_attach(drv);
 		if (error)
 			goto out_unregister;
 	}
-	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
 	error = driver_create_file(drv, &driver_attr_uevent);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 4a9a97a..f39334a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -441,7 +441,7 @@
 		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
 		    !drvdata->reset_flush_race) {
 			coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
-			coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+			coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
 		} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
 			drvdata->usbch = usb_qdss_open("qdss", drvdata,
 						       usb_notifier);
@@ -676,7 +676,7 @@
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
 		    !drvdata->reset_flush_race) {
-			coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+			coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
 			coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
 		} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
 			tmc_etr_bam_disable(drvdata);
@@ -996,7 +996,7 @@
 
 		if (!drvdata->reset_flush_race) {
 			coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
-			coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+			coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
 		}
 
 		tmc_etr_bam_disable(drvdata);
@@ -1020,7 +1020,7 @@
 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 		if (!drvdata->reset_flush_race) {
-			coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+			coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
 			coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
 		}
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 459a79c..b917248 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -123,7 +123,7 @@
 #define LONG_IB_DETECT_REG_INDEX_START 1
 #define LONG_IB_DETECT_REG_INDEX_END 5
 
-unsigned int ft_detect_regs[] = {
+unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT] = {
 	A3XX_RBBM_STATUS,
 	REG_CP_RB_RPTR,   /* LONG_IB_DETECT_REG_INDEX_START */
 	REG_CP_IB1_BASE,
@@ -138,8 +138,6 @@
 	0
 };
 
-const unsigned int ft_detect_regs_count = ARRAY_SIZE(ft_detect_regs);
-
 /*
  * This is the master list of all GPU cores that are supported by this
  * driver.
@@ -166,6 +164,15 @@
 	/* version of pfp microcode that supports sync_lock
 	   between CPU and GPU for IOMMU-v0 programming */
 	unsigned int sync_lock_pfp_ver;
+	/* PM4 jump table index */
+	unsigned int pm4_jt_idx;
+	/* PM4 jump table load addr */
+	unsigned int pm4_jt_addr;
+	/* PFP jump table index */
+	unsigned int pfp_jt_idx;
+	/* PFP jump table load addr */
+	unsigned int pfp_jt_addr;
+
 } adreno_gpulist[] = {
 	{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
@@ -202,10 +209,11 @@
 		512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
 	{ ADRENO_REV_A330, 3, 3, 0, ANY_ID,
 		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2, SZ_1M, NO_VER, NO_VER },
+		512, 0, 2, SZ_1M, NO_VER, NO_VER, 0x8AD, 0x2E4, 0x201, 0x200 },
 	{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
 		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2, SZ_128K, NO_VER, NO_VER },
+		512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
+		0x201, 0x200 },
 	{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
@@ -534,6 +542,8 @@
 	/* Reset the time-out in our idle timer */
 	mod_timer_pending(&device->idle_timer,
 		jiffies + device->pwrctrl.interval_timeout);
+	mod_timer_pending(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 	return result;
 }
 
@@ -1118,6 +1128,10 @@
 	adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
 	adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
 	adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
+	adreno_dev->pm4_jt_idx = adreno_gpulist[i].pm4_jt_idx;
+	adreno_dev->pm4_jt_addr = adreno_gpulist[i].pm4_jt_addr;
+	adreno_dev->pfp_jt_idx = adreno_gpulist[i].pfp_jt_idx;
+	adreno_dev->pfp_jt_addr = adreno_gpulist[i].pfp_jt_addr;
 	adreno_dev->gpulist_index = i;
 }
 
@@ -1785,6 +1799,9 @@
 	if (KGSL_STATE_DUMP_AND_FT != device->state)
 		mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
 
+	mod_timer(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+
 	adreno_perfcounter_start(adreno_dev);
 
 	device->reset_counter++;
@@ -1820,6 +1837,7 @@
 	device->ftbl->irqctrl(device, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 
 	adreno_ocmem_gmem_free(adreno_dev);
 
@@ -2175,10 +2193,70 @@
 	}
 }
 
+/**
+ * adreno_soft_reset() -  Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int ret;
+
+	/* If the jump table index is 0 soft reset is not supported */
+	if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+		return -EINVAL;
+	}
+
+	adreno_dev->drawctxt_active = NULL;
+
+	/* Stop the ringbuffer */
+	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+	/* Delete the idle timer */
+	del_timer_sync(&device->idle_timer);
+
+	/* Make sure we are totally awake */
+	kgsl_pwrctrl_enable(device);
+
+	/* Reset the GPU */
+	adreno_dev->gpudev->soft_reset(adreno_dev);
+
+	/* Reinitialize the GPU */
+	adreno_dev->gpudev->start(adreno_dev);
+
+	/* Enable IRQ */
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+	device->ftbl->irqctrl(device, 1);
+
+	/*
+	 * Restart the ringbuffer - we can go down the warm start path because
+	 * power was never yanked
+	 */
+	ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+	if (ret)
+		return ret;
+
+	device->reset_counter++;
+
+	return 0;
+}
+
 static int
 _adreno_ft_restart_device(struct kgsl_device *device,
 			   struct kgsl_context *context)
 {
+	/* If device soft reset fails try hard reset */
+	if (adreno_soft_reset(device))
+		KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+	else
+		/* Soft reset is successful */
+		goto reset_done;
+
 	/* restart device */
 	if (adreno_stop(device)) {
 		KGSL_FT_ERR(device, "Device stop failed\n");
@@ -2195,6 +2273,7 @@
 		return 1;
 	}
 
+reset_done:
 	if (context) {
 		struct adreno_context *adreno_context = context->devctxt;
 		kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
@@ -2301,6 +2380,7 @@
 	struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
 	unsigned int long_ib = 0;
 	static int no_context_ft;
+	struct kgsl_mmu *mmu = &device->mmu;
 
 	context = idr_find(&device->context_idr, ft_data->context_id);
 	if (context == NULL) {
@@ -2374,12 +2454,13 @@
 
 	/* Do not try the reply if hang is due to a pagefault */
 	if (adreno_context && adreno_context->pagefault) {
+		/* Resume MMU */
+		mmu->mmu_ops->mmu_pagefault_resume(mmu);
 		if ((ft_data->context_id == adreno_context->id) &&
 			(ft_data->global_eop == adreno_context->pagefault_ts)) {
 			ft_data->ft_policy &= ~KGSL_FT_REPLAY;
 			KGSL_FT_ERR(device, "MMU fault skipping replay\n");
 		}
-
 		adreno_context->pagefault = 0;
 	}
 
@@ -2637,6 +2718,9 @@
 		} else {
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 			mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+			mod_timer(&device->hang_timer,
+				(jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 		}
 		complete_all(&device->ft_gate);
 	}
@@ -2828,7 +2912,7 @@
 	unsigned int rbbm_status;
 	unsigned long wait_time;
 	unsigned long wait_time_part;
-	unsigned int prev_reg_val[ft_detect_regs_count];
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
@@ -3223,7 +3307,8 @@
 						unsigned int *prev_reg_val)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int curr_reg_val[ft_detect_regs_count];
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
 	unsigned int fast_hang_detected = 1;
 	unsigned int long_ib_detected = 1;
 	unsigned int i;
@@ -3243,7 +3328,9 @@
 	if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
 		return 0;
 
-	if (is_adreno_rbbm_status_idle(device)) {
+	if (is_adreno_rbbm_status_idle(device) &&
+		(kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
+		== rb->timestamp[KGSL_MEMSTORE_GLOBAL])) {
 
 		/*
 		 * On A2XX if the RPTR != WPTR and the device is idle, then
@@ -3275,7 +3362,7 @@
 			msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
 
 	/* Read the current Hang detect reg values here */
-	for (i = 0; i < ft_detect_regs_count; i++) {
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
 		if (ft_detect_regs[i] == 0)
 			continue;
 		adreno_regread(device, ft_detect_regs[i],
@@ -3310,7 +3397,7 @@
 					"Fault tolerance no context found\n");
 			}
 		}
-		for (i = 0; i < ft_detect_regs_count; i++) {
+		for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
 			if (curr_reg_val[i] != prev_reg_val[i]) {
 				fast_hang_detected = 0;
 
@@ -3386,55 +3473,11 @@
 
 	/* If hangs are not detected copy the current reg values
 	 * to previous values and return no hang */
-	for (i = 0; i < ft_detect_regs_count; i++)
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
 			prev_reg_val[i] = curr_reg_val[i];
 	return 0;
 }
 
-/**
- * adreno_handle_hang - Process a hang detected in adreno_waittimestamp
- * @device - pointer to a KGSL device structure
- * @context - pointer to the active KGSL context
- * @timestamp - the timestamp that the process was waiting for
- *
- * Process a possible GPU hang and try fault tolerance from it
- * cleanly
- */
-static int adreno_handle_hang(struct kgsl_device *device,
-	struct kgsl_context *context, unsigned int timestamp)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int context_id = _get_context_id(context);
-	unsigned int ts_issued;
-	unsigned int rptr;
-
-	/* Do one last check to see if we somehow made it through */
-	if (kgsl_check_timestamp(device, context, timestamp))
-		return 0;
-
-	ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
-
-	adreno_regread(device, REG_CP_RB_RPTR, &rptr);
-
-	/* Make sure timestamp check finished before triggering a hang */
-	mb();
-
-	KGSL_DRV_WARN(device,
-		     "Device hang detected while waiting for timestamp: "
-		     "<%d:0x%x>, last submitted timestamp: <%d:0x%x>, "
-		     "retired timestamp: <%d:0x%x>, wptr: 0x%x, rptr: 0x%x\n",
-		      context_id, timestamp, context_id, ts_issued, context_id,
-			kgsl_readtimestamp(device, context,
-			KGSL_TIMESTAMP_RETIRED),
-		      adreno_dev->ringbuffer.wptr, rptr);
-
-	/* Return 0 after a successful fault tolerance */
-	if (!adreno_dump_and_exec_ft(device))
-		return 0;
-
-	return -ETIMEDOUT;
-}
-
 static int _check_pending_timestamp(struct kgsl_device *device,
 		struct kgsl_context *context, unsigned int timestamp)
 {
@@ -3483,7 +3526,6 @@
 	struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	unsigned int context_id = _get_context_id(context);
-	unsigned int prev_reg_val[ft_detect_regs_count];
 	unsigned int time_elapsed = 0;
 	unsigned int wait;
 	int ts_compare = 1;
@@ -3511,10 +3553,6 @@
 		context->wait_on_invalid_ts = false;
 	}
 
-
-	/* Clear the registers used for hang detection */
-	memset(prev_reg_val, 0, sizeof(prev_reg_val));
-
 	/*
 	 * On the first time through the loop only wait 100ms.
 	 * this gives enough time for the engine to start moving and oddly
@@ -3541,12 +3579,6 @@
 			break;
 		}
 
-		/* Check to see if the GPU is hung */
-		if (adreno_ft_detect(device, prev_reg_val)) {
-			ret = adreno_handle_hang(device, context, timestamp);
-			break;
-		}
-
 		/*
 		 * For proper power accounting sometimes we need to call
 		 * io_wait_interruptible_timeout and sometimes we need to call
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 816940f..531a77c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -110,6 +110,10 @@
 	unsigned int mharb;
 	struct adreno_gpudev *gpudev;
 	unsigned int wait_timeout;
+	unsigned int pm4_jt_idx;
+	unsigned int pm4_jt_addr;
+	unsigned int pfp_jt_idx;
+	unsigned int pfp_jt_addr;
 	unsigned int istore_size;
 	unsigned int pix_shader_start;
 	unsigned int instruction_size;
@@ -200,6 +204,7 @@
 	void (*coresight_disable) (struct kgsl_device *device);
 	void (*coresight_config_debug_reg) (struct kgsl_device *device,
 			int debug_reg, unsigned int val);
+	void (*soft_reset)(struct adreno_device *device);
 };
 
 /*
@@ -242,6 +247,8 @@
 	unsigned int replay_for_snapshot;
 };
 
+#define FT_DETECT_REGS_COUNT 12
+
 /* Fault Tolerance policy flags */
 #define  KGSL_FT_DISABLE                  BIT(0)
 #define  KGSL_FT_REPLAY                   BIT(1)
@@ -280,7 +287,6 @@
 extern const unsigned int a330_registers_count;
 
 extern unsigned int ft_detect_regs[];
-extern const unsigned int ft_detect_regs_count;
 
 int adreno_coresight_enable(struct coresight_device *csdev);
 void adreno_coresight_disable(struct coresight_device *csdev);
@@ -330,6 +336,9 @@
 int adreno_perfcounter_put(struct adreno_device *adreno_dev,
 	unsigned int groupid, unsigned int countable);
 
+int adreno_soft_reset(struct kgsl_device *device);
+
+
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 884b72b..29855f7 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3461,6 +3461,30 @@
 	ARRAY_SIZE(a3xx_perfcounter_groups),
 };
 
+/*
+ * a3xx_soft_reset() - Soft reset GPU
+ * @adreno_dev: Pointer to adreno device
+ *
+ * Soft reset the GPU by doing a AHB write of value 1 to RBBM_SW_RESET
+ * register. This is used when we want to reset the GPU without
+ * turning off GFX power rail. The reset when asserted resets
+ * all the HW logic, restores GPU registers to default state and
+ * flushes out pending VBIF transactions.
+ */
+static void a3xx_soft_reset(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	unsigned int reg;
+
+	adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 1);
+	/*
+	 * Do a dummy read to get a brief read cycle delay for the reset to take
+	 * effect
+	 */
+	adreno_regread(device, A3XX_RBBM_SW_RESET_CMD, &reg);
+	adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 0);
+}
+
 /* Defined in adreno_a3xx_snapshot.c */
 void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
 	int *remain, int hang);
@@ -3488,4 +3512,5 @@
 	.coresight_enable = a3xx_coresight_enable,
 	.coresight_disable = a3xx_coresight_disable,
 	.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
+	.soft_reset = a3xx_soft_reset,
 };
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 4e95e93..70223db 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/log2.h>
+#include <linux/time.h>
+#include <linux/delay.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -64,7 +66,7 @@
 	unsigned long wait_time;
 	unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 	unsigned long wait_time_part;
-	unsigned int prev_reg_val[ft_detect_regs_count];
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
@@ -242,8 +244,16 @@
 	return ret;
 }
 
-
-int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pm4_ucode() - Load pm4 ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pm4 ucode to load
+ * @addr: Address to load the pm4 ucode
+ *
+ * Load the pm4 ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device,
+					unsigned int start, unsigned int addr)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
@@ -258,8 +268,8 @@
 		adreno_dev->pm4_fw_version);
 
 	adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
-	adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
-	for (i = 1; i < adreno_dev->pm4_fw_size; i++)
+	adreno_regwrite(device, REG_CP_ME_RAM_WADDR, addr);
+	for (i = start; i < adreno_dev->pm4_fw_size; i++)
 		adreno_regwrite(device, REG_CP_ME_RAM_DATA,
 			adreno_dev->pm4_fw[i]);
 
@@ -297,7 +307,16 @@
 	return ret;
 }
 
-int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pfp_ucode() - Load pfp ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pfp ucode to load
+ * @addr: Address to load the pfp ucode
+ *
+ * Load the pfp ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
+					unsigned int start, unsigned int addr)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
@@ -311,8 +330,9 @@
 	KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
 			adreno_dev->pfp_fw_version);
 
-	adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
-	for (i = 1; i < adreno_dev->pfp_fw_size; i++)
+	adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr,
+						addr);
+	for (i = start; i < adreno_dev->pfp_fw_size; i++)
 		adreno_regwrite(device,
 		adreno_dev->gpudev->reg_cp_pfp_ucode_data,
 		adreno_dev->pfp_fw[i]);
@@ -320,7 +340,13 @@
 	return 0;
 }
 
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+/**
+ * _ringbuffer_start_common() - Ringbuffer start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Setup ringbuffer for GPU.
+ */
+int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
 {
 	int status;
 	/*cp_rb_cntl_u cp_rb_cntl; */
@@ -420,16 +446,6 @@
 	adreno_regwrite(device, REG_SCRATCH_UMSK,
 			     GSL_RB_MEMPTRS_SCRATCH_MASK);
 
-	/* load the CP ucode */
-	status = adreno_ringbuffer_load_pm4_ucode(device);
-	if (status != 0)
-		return status;
-
-	/* load the prefetch parser ucode */
-	status = adreno_ringbuffer_load_pfp_ucode(device);
-	if (status != 0)
-		return status;
-
 	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
 	if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
 		adreno_is_a320(adreno_dev))
@@ -457,6 +473,54 @@
 	return status;
 }
 
+/**
+ * adreno_ringbuffer_warm_start() - Ringbuffer warm start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Start the ringbuffer but load only jump tables part of the
+ * microcode.
+ */
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb)
+{
+	int status;
+	struct kgsl_device *device = rb->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* load the CP ucode */
+	status = adreno_ringbuffer_load_pm4_ucode(device,
+			adreno_dev->pm4_jt_idx, adreno_dev->pm4_jt_addr);
+	if (status != 0)
+		return status;
+
+	/* load the prefetch parser ucode */
+	status = adreno_ringbuffer_load_pfp_ucode(device,
+			adreno_dev->pfp_jt_idx, adreno_dev->pfp_jt_addr);
+	if (status != 0)
+		return status;
+
+	return _ringbuffer_start_common(rb);
+}
+
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+{
+	int status;
+
+	if (rb->flags & KGSL_FLAGS_STARTED)
+		return 0;
+
+	/* load the CP ucode */
+	status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1, 0);
+	if (status != 0)
+		return status;
+
+	/* load the prefetch parser ucode */
+	status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1, 0);
+	if (status != 0)
+		return status;
+
+	return _ringbuffer_start_common(rb);
+}
+
 void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
 {
 	struct kgsl_device *device = rb->device;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 115533e..f59b834 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -97,6 +97,8 @@
 
 int adreno_ringbuffer_init(struct kgsl_device *device);
 
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb);
+
 int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
 
 void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1d2c341..becb4ef 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -39,6 +39,7 @@
 #include "kgsl_device.h"
 #include "kgsl_trace.h"
 #include "kgsl_sync.h"
+#include "adreno.h"
 
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "kgsl."
@@ -59,6 +60,54 @@
 };
 
 /**
+ * kgsl_hang_check() - Check for GPU hang
+ * data: KGSL device structure
+ *
+ * This function is called every KGSL_TIMEOUT_PART time when
+ * GPU is active to check for hang. If a hang is detected we
+ * trigger fault tolerance.
+ */
+void kgsl_hang_check(struct work_struct *work)
+{
+	struct kgsl_device *device = container_of(work, struct kgsl_device,
+							hang_check_ws);
+	static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+
+	mutex_lock(&device->mutex);
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+
+		/* Check to see if the GPU is hung */
+		if (adreno_ft_detect(device, prev_reg_val))
+			adreno_dump_and_exec_ft(device);
+
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+	}
+
+	mutex_unlock(&device->mutex);
+}
+
+/**
+ * hang_timer() - Hang timer function
+ * data: KGSL device structure
+ *
+ * This function is called when hang timer expires, in this
+ * function we check if GPU is in active state and queue the
+ * work on device workqueue to check for the hang. We restart
+ * the timer after KGSL_TIMEOUT_PART time.
+ */
+void hang_timer(unsigned long data)
+{
+	struct kgsl_device *device = (struct kgsl_device *) data;
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+		/* Have work run in a non-interrupt context. */
+		queue_work(device->work_queue, &device->hang_check_ws);
+	}
+}
+
+/**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
  * device: KGSL device
  * id: ID of the context submitting the command
@@ -550,6 +599,7 @@
 
 	/* Don't let the timer wake us during suspended sleep. */
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 	switch (device->state) {
 		case KGSL_STATE_INIT:
 			break;
@@ -3292,6 +3342,7 @@
 
 
 	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+	setup_timer(&device->hang_timer, hang_timer, (unsigned long) device);
 	status = kgsl_create_device_workqueue(device);
 	if (status)
 		goto error_pwrctrl_close;
@@ -3371,9 +3422,7 @@
 
 	/* Disable the idle timer so we don't get interrupted */
 	del_timer_sync(&device->idle_timer);
-	mutex_unlock(&device->mutex);
-	flush_workqueue(device->work_queue);
-	mutex_lock(&device->mutex);
+	del_timer_sync(&device->hang_timer);
 
 	/* Force on the clocks */
 	kgsl_pwrctrl_wake(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 4a1f291..0983111 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -203,6 +203,7 @@
 #define MMU_CONFIG 1
 #endif
 
+void kgsl_hang_check(struct work_struct *work);
 void kgsl_mem_entry_destroy(struct kref *kref);
 int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6477cbd..94792a0 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -172,7 +172,9 @@
 	struct completion hwaccess_gate;
 	const struct kgsl_functable *ftbl;
 	struct work_struct idle_check_ws;
+	struct work_struct hang_check_ws;
 	struct timer_list idle_timer;
+	struct timer_list hang_timer;
 	struct kgsl_pwrctrl pwrctrl;
 	int open_count;
 
@@ -237,6 +239,8 @@
 	.ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
 	.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
 			kgsl_idle_check),\
+	.hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
+			kgsl_hang_check),\
 	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
 			kgsl_process_events),\
 	.context_idr = IDR_INIT((_dev).context_idr),\
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index eb85900..0bacc5e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1735,10 +1735,36 @@
 	return ret;
 }
 
-static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu)
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	int i, j;
+
+	if (mmu->fault) {
+		for (i = 0; i < iommu->unit_count; i++) {
+			struct kgsl_iommu_unit *iommu_unit =
+						&iommu->iommu_units[i];
+			for (j = 0; j < iommu_unit->dev_count; j++) {
+				if (iommu_unit->dev[j].fault) {
+					kgsl_iommu_enable_clk(mmu, j);
+					_iommu_lock();
+					KGSL_IOMMU_SET_CTX_REG(iommu,
+						iommu_unit,
+						iommu_unit->dev[j].ctx_id,
+						RESUME, 1);
+					_iommu_unlock();
+					iommu_unit->dev[j].fault = 0;
+				}
+			}
+		}
+		mmu->fault = 0;
+	}
+}
+
+
+static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
 	/*
 	 *  stop device mmu
 	 *
@@ -1751,25 +1777,7 @@
 
 		mmu->flags &= ~KGSL_FLAGS_STARTED;
 
-		if (mmu->fault) {
-			for (i = 0; i < iommu->unit_count; i++) {
-				struct kgsl_iommu_unit *iommu_unit =
-					&iommu->iommu_units[i];
-				for (j = 0; j < iommu_unit->dev_count; j++) {
-					if (iommu_unit->dev[j].fault) {
-						kgsl_iommu_enable_clk(mmu, j);
-						_iommu_lock();
-						KGSL_IOMMU_SET_CTX_REG(iommu,
-						iommu_unit,
-						iommu_unit->dev[j].ctx_id,
-						RESUME, 1);
-						_iommu_unlock();
-						iommu_unit->dev[j].fault = 0;
-					}
-				}
-			}
-			mmu->fault = 0;
-		}
+		kgsl_iommu_pagefault_resume(mmu);
 	}
 	/* switch off MMU clocks and cancel any events it has queued */
 	iommu->clk_event_queued = false;
@@ -1987,6 +1995,7 @@
 	.mmu_setstate = kgsl_iommu_setstate,
 	.mmu_device_setstate = kgsl_iommu_default_setstate,
 	.mmu_pagefault = NULL,
+	.mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
 	.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
 	.mmu_enable_clk = kgsl_iommu_enable_clk,
 	.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index a4fffec..27cfc40 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -141,6 +141,8 @@
 	void (*mmu_pagefault) (struct kgsl_mmu *mmu);
 	phys_addr_t (*mmu_get_current_ptbase)
 			(struct kgsl_mmu *mmu);
+	void (*mmu_pagefault_resume)
+			(struct kgsl_mmu *mmu);
 	void (*mmu_disable_clk_on_ts)
 		(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
 	int (*mmu_enable_clk)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 847c59e..3a2345e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1242,6 +1242,7 @@
 			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 			return -EBUSY;
 		}
+		del_timer_sync(&device->hang_timer);
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1311,6 +1312,7 @@
 	case KGSL_STATE_NAP:
 	case KGSL_STATE_SLEEP:
 		del_timer_sync(&device->idle_timer);
+		del_timer_sync(&device->hang_timer);
 		/* make sure power is on to stop the device*/
 		kgsl_pwrctrl_enable(device);
 		device->ftbl->suspend_context(device);
@@ -1403,6 +1405,8 @@
 		/* Re-enable HW access */
 		mod_timer(&device->idle_timer,
 				jiffies + device->pwrctrl.interval_timeout);
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 		pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
 				device->pwrctrl.pm_qos_latency);
 	case KGSL_STATE_ACTIVE:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 29b269a..479b788 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2923,13 +2923,32 @@
 		goto err_free_mem;
 	}
 
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		/* configure touchscreen reset out gpio */
+		error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
+		if (error) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						pdata->reset_gpio);
+			goto err_regulator_on;
+		}
+
+		error = gpio_direction_output(pdata->reset_gpio, 0);
+		if (error) {
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				pdata->reset_gpio);
+			goto err_reset_gpio_req;
+		}
+		mxt_reset_delay(data);
+	}
+
 	if (pdata->power_on)
 		error = pdata->power_on(true);
 	else
 		error = mxt_power_on(data, true);
 	if (error) {
 		dev_err(&client->dev, "Failed to power on hardware\n");
-		goto err_regulator_on;
+		goto err_reset_gpio_req;
 	}
 
 	if (gpio_is_valid(pdata->irq_gpio)) {
@@ -2954,20 +2973,12 @@
 	}
 
 	if (gpio_is_valid(pdata->reset_gpio)) {
-		/* configure touchscreen reset out gpio */
-		error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
-		if (error) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						pdata->reset_gpio);
-			goto err_irq_gpio_req;
-		}
-
 		error = gpio_direction_output(pdata->reset_gpio, 1);
 		if (error) {
 			dev_err(&client->dev,
 				"unable to set direction for gpio [%d]\n",
 				pdata->reset_gpio);
-			goto err_reset_gpio_req;
+				goto err_irq_gpio_req;
 		}
 	}
 
@@ -2982,7 +2993,7 @@
 
 	error = mxt_initialize(data);
 	if (error)
-		goto err_reset_gpio_req;
+		goto err_irq_gpio_req;
 
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 			pdata->irqflags, client->dev.driver->name, data);
@@ -3036,9 +3047,6 @@
 	free_irq(client->irq, data);
 err_free_object:
 	kfree(data->object_table);
-err_reset_gpio_req:
-	if (gpio_is_valid(pdata->reset_gpio))
-		gpio_free(pdata->reset_gpio);
 err_irq_gpio_req:
 	if (gpio_is_valid(pdata->irq_gpio))
 		gpio_free(pdata->irq_gpio);
@@ -3047,6 +3055,9 @@
 		pdata->power_on(false);
 	else
 		mxt_power_on(data, false);
+err_reset_gpio_req:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
 err_regulator_on:
 	if (pdata->init_hw)
 		pdata->init_hw(false);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index d43bfbe..efcace6 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -26,12 +26,18 @@
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
 #include <linux/input/ft5x06_ts.h>
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
 /* Early-suspend level */
-#define FT5X06_SUSPEND_LEVEL 1
+#define FT_SUSPEND_LEVEL 1
 #endif
 
 #define CFG_MAX_TOUCH_POINTS	5
@@ -52,26 +58,118 @@
 #define POINT_READ_BUF	(3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
 
 /*register address*/
-#define FT5X06_REG_ID		0xA3
-#define FT5X06_REG_PMODE	0xA5
-#define FT5X06_REG_FW_VER	0xA6
-#define FT5X06_REG_POINT_RATE	0x88
-#define FT5X06_REG_THGROUP	0x80
+#define FT_REG_DEV_MODE		0x00
+#define FT_DEV_MODE_REG_CAL	0x02
+#define FT_REG_ID		0xA3
+#define FT_REG_PMODE		0xA5
+#define FT_REG_FW_VER		0xA6
+#define FT_REG_POINT_RATE	0x88
+#define FT_REG_THGROUP		0x80
+#define FT_REG_ECC		0xCC
+#define FT_REG_RESET_FW		0x07
 
 /* power register bits*/
-#define FT5X06_PMODE_ACTIVE		0x00
-#define FT5X06_PMODE_MONITOR		0x01
-#define FT5X06_PMODE_STANDBY		0x02
-#define FT5X06_PMODE_HIBERNATE		0x03
+#define FT_PMODE_ACTIVE		0x00
+#define FT_PMODE_MONITOR	0x01
+#define FT_PMODE_STANDBY	0x02
+#define FT_PMODE_HIBERNATE	0x03
+#define FT_FACTORYMODE_VALUE	0x40
+#define FT_WORKMODE_VALUE	0x00
+#define FT_RST_CMD_REG		0xFC
+#define FT_READ_ID_REG		0x90
+#define FT_ERASE_APP_REG	0x61
+#define FT_ERASE_PANEL_REG	0x63
+#define FT_FW_START_REG		0xBF
 
-#define FT5X06_VTG_MIN_UV	2600000
-#define FT5X06_VTG_MAX_UV	3300000
-#define FT5X06_I2C_VTG_MIN_UV	1800000
-#define FT5X06_I2C_VTG_MAX_UV	1800000
 
-#define FT5X06_COORDS_ARR_SIZE	4
+#define FT_VTG_MIN_UV		2600000
+#define FT_VTG_MAX_UV		3300000
+#define FT_I2C_VTG_MIN_UV	1800000
+#define FT_I2C_VTG_MAX_UV	1800000
+
+#define FT_COORDS_ARR_SIZE	4
 #define MAX_BUTTONS		4
 
+#define FT_8BIT_SHIFT		8
+#define FT_4BIT_SHIFT		4
+#define FT_FW_NAME_MAX_LEN	50
+
+#define FT5316_ID		0x0A
+#define FT5306I_ID		0x55
+
+#define FT_UPGRADE_AA		0xAA
+#define FT_UPGRADE_55		0x55
+
+/*upgrade config of FT5606*/
+#define FT5606_UPGRADE_AA_DELAY		50
+#define FT5606_UPGRADE_55_DELAY		10
+#define FT5606_UPGRADE_ID_1		0x79
+#define FT5606_UPGRADE_ID_2		0x06
+#define FT5606_UPGRADE_READID_DELAY	100
+#define FT5606_UPGRADE_EARSE_DELAY	2000
+
+/*upgrade config of FT5316*/
+#define FT5316_UPGRADE_AA_DELAY		50
+#define FT5316_UPGRADE_55_DELAY		30
+#define FT5316_UPGRADE_ID_1		0x79
+#define FT5316_UPGRADE_ID_2		0x07
+#define FT5316_UPGRADE_READID_DELAY	1
+#define FT5316_UPGRADE_EARSE_DELAY	1500
+
+/*upgrade config of FT5x06(x=2,3,4)*/
+#define FT5X06_UPGRADE_AA_DELAY		50
+#define FT5X06_UPGRADE_55_DELAY		30
+#define FT5X06_UPGRADE_ID_1		0x79
+#define FT5X06_UPGRADE_ID_2		0x03
+#define FT5X06_UPGRADE_READID_DELAY	1
+#define FT5X06_UPGRADE_EARSE_DELAY	2000
+
+/*upgrade config of FT6208*/
+#define FT6208_UPGRADE_AA_DELAY		60
+#define FT6208_UPGRADE_55_DELAY		10
+#define FT6208_UPGRADE_ID_1		0x79
+#define FT6208_UPGRADE_ID_2		0x05
+#define FT6208_UPGRADE_READID_DELAY	10
+#define FT6208_UPGRADE_EARSE_DELAY	2000
+
+#define FT_UPGRADE_INFO(x, y)	do { \
+		x->delay_55 = y##_UPGRADE_55_DELAY; \
+		x->delay_aa = y##_UPGRADE_AA_DELAY; \
+		x->upgrade_id_1 = y##_UPGRADE_ID_1; \
+		x->upgrade_id_2 = y##_UPGRADE_ID_2; \
+		x->delay_readid = y##_UPGRADE_READID_DELAY; \
+		x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
+		} while (0)
+
+#define FT_FW_MIN_SIZE		8
+#define FT_FW_MAX_SIZE		32768
+#define FT_FW_FILE_VER(x)	((x)->data[(x)->size - 2])
+#define FT_FW_CHECK(x)		\
+	(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
+	&& (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
+	&& (((x)->data[(x)->size - 3] ^ (x)->data[(x)->size - 4]) == 0xFF)))
+
+#define FT_MAX_TRIES		5
+#define FT_RETRY_DLY		20
+
+#define FT_MAX_WR_BUF		10
+#define FT_MAX_RD_BUF		2
+#define FT_FW_PKT_LEN		128
+#define FT_FW_PKT_META_LEN	6
+#define FT_FW_PKT_DLY_MS	20
+#define FT_FW_LAST_PKT		0x6ffa
+#define FT_EARSE_DLY_MS		100
+
+#define FT_UPGRADE_LOOP		3
+#define FT_CAL_START		0x04
+#define FT_CAL_FIN		0x00
+#define FT_CAL_STORE		0x05
+#define FT_CAL_RETRY		100
+#define FT_REG_CAL		0x00
+#define FT_CAL_MASK		0x70
+
+#define FT_DEBUG_DIR_NAME	"ft_debug"
+
 struct ts_event {
 	u16 x[CFG_MAX_TOUCH_POINTS];	/*x coordinate */
 	u16 y[CFG_MAX_TOUCH_POINTS];	/*y coordinate */
@@ -82,6 +180,15 @@
 	u8 touch_point;
 };
 
+struct upgrade_info {
+	u16 delay_aa;		/*delay of write FT_UPGRADE_AA */
+	u16 delay_55;		/*delay of write FT_UPGRADE_55 */
+	u8 upgrade_id_1;	/*upgrade id 1 */
+	u8 upgrade_id_2;	/*upgrade id 2 */
+	u16 delay_readid;	/*delay of read id */
+	u16 delay_earse_flash; /*delay of earse flash*/
+};
+
 struct ft5x06_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
@@ -89,7 +196,15 @@
 	const struct ft5x06_ts_platform_data *pdata;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
-#ifdef CONFIG_HAS_EARLYSUSPEND
+	char fw_name[FT_FW_NAME_MAX_LEN];
+	bool loading_fw;
+	u8 family_id;
+	struct dentry *dir;
+	u16 addr;
+	bool suspended;
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 	struct early_suspend early_suspend;
 #endif
 };
@@ -154,6 +269,21 @@
 	return ret;
 }
 
+static int ft5x0x_write_reg(struct i2c_client *client, u8 addr, const u8 val)
+{
+	u8 buf[2] = {0};
+
+	buf[0] = addr;
+	buf[1] = val;
+
+	return ft5x06_i2c_write(client, buf, sizeof(buf));
+}
+
+static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
+{
+	return ft5x06_i2c_read(client, &addr, 1, val, 1);
+}
+
 static void ft5x06_report_value(struct ft5x06_ts_data *data)
 {
 	struct ts_event *event = &data->event;
@@ -293,8 +423,8 @@
 	}
 
 	if (regulator_count_voltages(data->vdd) > 0) {
-		rc = regulator_set_voltage(data->vdd, FT5X06_VTG_MIN_UV,
-					   FT5X06_VTG_MAX_UV);
+		rc = regulator_set_voltage(data->vdd, FT_VTG_MIN_UV,
+					   FT_VTG_MAX_UV);
 		if (rc) {
 			dev_err(&data->client->dev,
 				"Regulator set_vtg failed vdd rc=%d\n", rc);
@@ -311,8 +441,8 @@
 	}
 
 	if (regulator_count_voltages(data->vcc_i2c) > 0) {
-		rc = regulator_set_voltage(data->vcc_i2c, FT5X06_I2C_VTG_MIN_UV,
-					   FT5X06_I2C_VTG_MAX_UV);
+		rc = regulator_set_voltage(data->vcc_i2c, FT_I2C_VTG_MIN_UV,
+					   FT_I2C_VTG_MAX_UV);
 		if (rc) {
 			dev_err(&data->client->dev,
 			"Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
@@ -326,19 +456,19 @@
 	regulator_put(data->vcc_i2c);
 reg_vdd_set_vtg:
 	if (regulator_count_voltages(data->vdd) > 0)
-		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+		regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
 reg_vdd_put:
 	regulator_put(data->vdd);
 	return rc;
 
 pwr_deinit:
 	if (regulator_count_voltages(data->vdd) > 0)
-		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+		regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
 
 	regulator_put(data->vdd);
 
 	if (regulator_count_voltages(data->vcc_i2c) > 0)
-		regulator_set_voltage(data->vcc_i2c, 0, FT5X06_I2C_VTG_MAX_UV);
+		regulator_set_voltage(data->vcc_i2c, 0, FT_I2C_VTG_MAX_UV);
 
 	regulator_put(data->vcc_i2c);
 	return 0;
@@ -350,14 +480,26 @@
 	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
 	char txbuf[2];
 
+	if (data->loading_fw) {
+		dev_info(dev, "Firmware loading in process...\n");
+		return 0;
+	}
+
+	if (data->suspended) {
+		dev_info(dev, "Already in suspend state\n");
+		return 0;
+	}
+
 	disable_irq(data->client->irq);
 
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
-		txbuf[0] = FT5X06_REG_PMODE;
-		txbuf[1] = FT5X06_PMODE_HIBERNATE;
+		txbuf[0] = FT_REG_PMODE;
+		txbuf[1] = FT_PMODE_HIBERNATE;
 		ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
 	}
 
+	data->suspended = true;
+
 	return 0;
 }
 
@@ -365,6 +507,11 @@
 {
 	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
 
+	if (!data->suspended) {
+		dev_info(dev, "Already in awake state\n");
+		return 0;
+	}
+
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
 		msleep(FT_RESET_DLY);
@@ -372,10 +519,32 @@
 	}
 	enable_irq(data->client->irq);
 
+	data->suspended = false;
+
 	return 0;
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct ft5x06_ts_data *ft5x06_data =
+		container_of(self, struct ft5x06_ts_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+			ft5x06_data && ft5x06_data->client) {
+		blank = evdata->data;
+		if (*blank == FB_BLANK_UNBLANK)
+			ft5x06_ts_resume(&ft5x06_data->client->dev);
+		else if (*blank == FB_BLANK_POWERDOWN)
+			ft5x06_ts_suspend(&ft5x06_data->client->dev);
+	}
+
+	return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 static void ft5x06_ts_early_suspend(struct early_suspend *handler)
 {
 	struct ft5x06_ts_data *data = container_of(handler,
@@ -396,18 +565,461 @@
 #endif
 
 static const struct dev_pm_ops ft5x06_ts_pm_ops = {
-#ifndef CONFIG_HAS_EARLYSUSPEND
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
 	.suspend = ft5x06_ts_suspend,
 	.resume = ft5x06_ts_resume,
 #endif
 };
 #endif
 
+static int ft5x06_auto_cal(struct i2c_client *client)
+{
+	u8 temp = 0, i;
+
+	/* set to factory mode */
+	msleep(2 * FT_STARTUP_DLY);
+	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
+	msleep(FT_STARTUP_DLY);
+
+	/* start calibration */
+	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
+	msleep(2 * FT_STARTUP_DLY);
+	for (i = 0; i < FT_CAL_RETRY; i++) {
+		ft5x0x_read_reg(client, FT_REG_CAL, &temp);
+		/*return to normal mode, calibration finish */
+		if (((temp & FT_CAL_MASK) >> FT_4BIT_SHIFT) == FT_CAL_FIN)
+			break;
+	}
+
+	/*calibration OK */
+	msleep(2 * FT_STARTUP_DLY);
+	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
+	msleep(FT_STARTUP_DLY);
+
+	/* store calibration data */
+	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
+	msleep(2 * FT_STARTUP_DLY);
+
+	/* set to normal mode */
+	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
+	msleep(2 * FT_STARTUP_DLY);
+
+	return 0;
+}
+
+static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
+{
+	switch (family_id) {
+	case FT5306I_ID:
+		FT_UPGRADE_INFO(info, FT5X06);
+		break;
+	case FT5316_ID:
+		FT_UPGRADE_INFO(info, FT5316);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ft5x06_fw_upgrade_start(struct i2c_client *client,
+			const u8 *data, u32 data_len)
+{
+	struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
+	struct upgrade_info info;
+	u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
+	u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
+	int rc, i, j, temp;
+	u32 pkt_num, pkt_len;
+	u8 fw_ecc;
+
+	rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
+	if (rc < 0) {
+		dev_err(&client->dev, "Cannot get upgrade information!\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < FT_UPGRADE_LOOP; i++) {
+		/* reset - write 0xaa and 0x55 to register 0xfc */
+		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
+		msleep(info.delay_aa);
+
+		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
+		msleep(info.delay_55);
+
+		/* Enter upgrade mode */
+		w_buf[0] = FT_UPGRADE_55;
+		w_buf[1] = FT_UPGRADE_AA;
+		do {
+			i++;
+			rc = ft5x06_i2c_write(client, w_buf, 2);
+			msleep(FT_RETRY_DLY);
+		} while (rc <= 0 && i < FT_MAX_TRIES);
+
+		/* check READ_ID */
+		msleep(info.delay_readid);
+		w_buf[0] = FT_READ_ID_REG;
+		w_buf[1] = 0x00;
+		w_buf[2] = 0x00;
+		w_buf[3] = 0x00;
+
+		ft5x06_i2c_read(client, w_buf, 4, r_buf, 2);
+
+		if (r_buf[0] != info.upgrade_id_1
+			|| r_buf[1] != info.upgrade_id_2) {
+			dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+		} else
+			break;
+	}
+
+	if (i >= FT_UPGRADE_LOOP) {
+		dev_err(&client->dev, "Abort upgrade\n");
+		return -EIO;
+	}
+
+	/* erase app and panel paramenter area */
+	w_buf[0] = FT_ERASE_APP_REG;
+	ft5x06_i2c_write(client, w_buf, 1);
+	msleep(info.delay_earse_flash);
+
+	w_buf[0] = FT_ERASE_PANEL_REG;
+	ft5x06_i2c_write(client, w_buf, 1);
+	msleep(FT_EARSE_DLY_MS);
+
+	/* program firmware */
+	data_len = data_len - 8;
+	pkt_num = (data_len) / FT_FW_PKT_LEN;
+	pkt_len = FT_FW_PKT_LEN;
+	pkt_buf[0] = FT_FW_START_REG;
+	pkt_buf[1] = 0x00;
+	fw_ecc = 0;
+
+	for (i = 0; i < pkt_num; i++) {
+		temp = i * FT_FW_PKT_LEN;
+		pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
+		pkt_buf[3] = (u8) temp;
+		pkt_buf[4] = (u8) (pkt_len >> FT_8BIT_SHIFT);
+		pkt_buf[5] = (u8) pkt_len;
+
+		for (j = 0; j < FT_FW_PKT_LEN; j++) {
+			pkt_buf[6 + j] = data[i * FT_FW_PKT_LEN + j];
+			fw_ecc ^= pkt_buf[6 + j];
+		}
+
+		ft5x06_i2c_write(client, pkt_buf,
+				FT_FW_PKT_LEN + FT_FW_PKT_META_LEN);
+		msleep(FT_FW_PKT_DLY_MS);
+	}
+
+	/* send remaining bytes */
+	if ((data_len) % FT_FW_PKT_LEN > 0) {
+		temp = pkt_num * FT_FW_PKT_LEN;
+		pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
+		pkt_buf[3] = (u8) temp;
+		temp = (data_len) % FT_FW_PKT_LEN;
+		pkt_buf[4] = (u8) (temp >> FT_8BIT_SHIFT);
+		pkt_buf[5] = (u8) temp;
+
+		for (i = 0; i < temp; i++) {
+			pkt_buf[6 + i] = data[pkt_num * FT_FW_PKT_LEN + i];
+			fw_ecc ^= pkt_buf[6 + i];
+		}
+
+		ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
+		msleep(FT_FW_PKT_DLY_MS);
+	}
+
+	/* send the finishing packet */
+	for (i = 0; i < 6; i++) {
+		temp = FT_FW_LAST_PKT + i;
+		pkt_buf[2] = (u8) (temp >> 8);
+		pkt_buf[3] = (u8) temp;
+		temp = 1;
+		pkt_buf[4] = (u8) (temp >> 8);
+		pkt_buf[5] = (u8) temp;
+		pkt_buf[6] = data[data_len + i];
+		fw_ecc ^= pkt_buf[6];
+		ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
+		msleep(FT_FW_PKT_DLY_MS);
+	}
+
+	/* verify checksum */
+	w_buf[0] = FT_REG_ECC;
+	ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
+	if (r_buf[0] != fw_ecc) {
+		dev_err(&client->dev, "ECC error! dev_ecc=%02x fw_ecc=%02x\n",
+					r_buf[0], fw_ecc);
+		return -EIO;
+	}
+
+	/* reset */
+	w_buf[0] = FT_REG_RESET_FW;
+	ft5x06_i2c_write(client, w_buf, 1);
+	msleep(FT_STARTUP_DLY);
+
+	return 0;
+}
+
+static int ft5x06_fw_upgrade(struct device *dev, bool force)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	const struct firmware *fw = NULL;
+	int rc;
+	u8 val = 0;
+
+	rc = request_firmware(&fw, data->fw_name, dev);
+	if (rc < 0) {
+		dev_err(dev, "Request firmware failed - %s (%d)\n",
+						data->fw_name, rc);
+		return rc;
+	}
+
+	if (fw->size < FT_FW_MIN_SIZE || fw->size > FT_FW_MAX_SIZE) {
+		dev_err(dev, "Invalid firmware size (%d)\n", fw->size);
+		rc = -EIO;
+		goto rel_fw;
+	}
+
+	/* check firmware version */
+	rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
+	if (rc < 0) {
+		dev_err(dev, "Get firmware version failed\n");
+		goto rel_fw;
+	}
+
+	if (val == FT_FW_FILE_VER(fw) && !force) {
+		dev_err(dev, "No need to update (0x%x)\n", val);
+		rc = -EFAULT;
+		goto rel_fw;
+	}
+
+	dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
+					FT_FW_FILE_VER(fw), val);
+
+	/* start firmware upgrade */
+	if (FT_FW_CHECK(fw)) {
+		rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
+		if (rc < 0)
+			dev_err(dev, "update failed (%d)\n", rc);
+		else
+			ft5x06_auto_cal(data->client);
+	} else {
+		dev_err(dev, "FW format error\n");
+		rc = -EIO;
+	}
+
+rel_fw:
+	release_firmware(fw);
+	return rc;
+}
+
+static ssize_t ft5x06_update_fw_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	return snprintf(buf, 2, "%d\n", data->loading_fw);
+}
+
+static ssize_t ft5x06_update_fw_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int rc;
+
+	if (size > 2)
+		return -EINVAL;
+
+	rc = kstrtoul(buf, 10, &val);
+	if (rc != 0)
+		return rc;
+
+	mutex_lock(&data->input_dev->mutex);
+	if (!data->loading_fw  && val) {
+		data->loading_fw = true;
+		ft5x06_fw_upgrade(dev, false);
+		data->loading_fw = false;
+	}
+	mutex_unlock(&data->input_dev->mutex);
+
+	return size;
+}
+
+static DEVICE_ATTR(update_fw, 0664, ft5x06_update_fw_show,
+				ft5x06_update_fw_store);
+
+static ssize_t ft5x06_force_update_fw_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	unsigned long val;
+	int rc;
+
+	if (size > 2)
+		return -EINVAL;
+
+	rc = kstrtoul(buf, 10, &val);
+	if (rc != 0)
+		return rc;
+
+	mutex_lock(&data->input_dev->mutex);
+	if (!data->loading_fw  && val) {
+		data->loading_fw = true;
+		ft5x06_fw_upgrade(dev, true);
+		data->loading_fw = false;
+	}
+	mutex_unlock(&data->input_dev->mutex);
+
+	return size;
+}
+
+static DEVICE_ATTR(force_update_fw, 0664, ft5x06_update_fw_show,
+				ft5x06_force_update_fw_store);
+
+static ssize_t ft5x06_fw_name_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	return snprintf(buf, FT_FW_NAME_MAX_LEN - 1, "%s\n", data->fw_name);
+}
+
+static ssize_t ft5x06_fw_name_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+
+	if (size > FT_FW_NAME_MAX_LEN - 1)
+		return -EINVAL;
+
+	strlcpy(data->fw_name, buf, size);
+	if (data->fw_name[size-1] == '\n')
+		data->fw_name[size-1] = 0;
+
+	return size;
+}
+
+static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store);
+
+static bool ft5x06_debug_addr_is_valid(int addr)
+{
+	if (addr < 0 || addr > 0xFF) {
+		pr_err("FT reg address is invalid: 0x%x\n", addr);
+		return false;
+	}
+
+	return true;
+}
+
+static int ft5x06_debug_data_set(void *_data, u64 val)
+{
+	struct ft5x06_ts_data *data = _data;
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (ft5x06_debug_addr_is_valid(data->addr))
+		dev_info(&data->client->dev,
+			"Writing into FT registers not supported\n");
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+static int ft5x06_debug_data_get(void *_data, u64 *val)
+{
+	struct ft5x06_ts_data *data = _data;
+	int rc;
+	u8 reg;
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (ft5x06_debug_addr_is_valid(data->addr)) {
+		rc = ft5x0x_read_reg(data->client, data->addr, &reg);
+		if (rc < 0)
+			dev_err(&data->client->dev,
+				"FT read register 0x%x failed (%d)\n",
+				data->addr, rc);
+		else
+			*val = reg;
+	}
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, ft5x06_debug_data_get,
+			ft5x06_debug_data_set, "0x%02llX\n");
+
+static int ft5x06_debug_addr_set(void *_data, u64 val)
+{
+	struct ft5x06_ts_data *data = _data;
+
+	if (ft5x06_debug_addr_is_valid(val)) {
+		mutex_lock(&data->input_dev->mutex);
+		data->addr = val;
+		mutex_unlock(&data->input_dev->mutex);
+	}
+
+	return 0;
+}
+
+static int ft5x06_debug_addr_get(void *_data, u64 *val)
+{
+	struct ft5x06_ts_data *data = _data;
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (ft5x06_debug_addr_is_valid(data->addr))
+		*val = data->addr;
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, ft5x06_debug_addr_get,
+			ft5x06_debug_addr_set, "0x%02llX\n");
+
+static int ft5x06_debug_suspend_set(void *_data, u64 val)
+{
+	struct ft5x06_ts_data *data = _data;
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (val)
+		ft5x06_ts_suspend(&data->client->dev);
+	else
+		ft5x06_ts_resume(&data->client->dev);
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+static int ft5x06_debug_suspend_get(void *_data, u64 *val)
+{
+	struct ft5x06_ts_data *data = _data;
+
+	mutex_lock(&data->input_dev->mutex);
+	*val = data->suspended;
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, ft5x06_debug_suspend_get,
+			ft5x06_debug_suspend_set, "%lld\n");
+
 #ifdef CONFIG_OF
 static int ft5x06_get_dt_coords(struct device *dev, char *name,
 				struct ft5x06_ts_platform_data *pdata)
 {
-	u32 coords[FT5X06_COORDS_ARR_SIZE];
+	u32 coords[FT_COORDS_ARR_SIZE];
 	struct property *prop;
 	struct device_node *np = dev->of_node;
 	int coords_size, rc;
@@ -419,7 +1031,7 @@
 		return -ENODATA;
 
 	coords_size = prop->length / sizeof(u32);
-	if (coords_size != FT5X06_COORDS_ARR_SIZE) {
+	if (coords_size != FT_COORDS_ARR_SIZE) {
 		dev_err(dev, "invalid %s\n", name);
 		return -EINVAL;
 	}
@@ -518,6 +1130,7 @@
 	struct ft5x06_ts_platform_data *pdata;
 	struct ft5x06_ts_data *data;
 	struct input_dev *input_dev;
+	struct dentry *dir, *temp;
 	u8 reg_value;
 	u8 reg_addr;
 	int err;
@@ -653,37 +1266,43 @@
 	msleep(FT_STARTUP_DLY);
 
 	/* check the controller id */
-	reg_addr = FT5X06_REG_ID;
+	reg_addr = FT_REG_ID;
 	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
 	if (err < 0) {
 		dev_err(&client->dev, "version read failed");
 		return err;
 	}
 
+	dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
+
 	if (pdata->family_id != reg_value) {
 		dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
 		goto free_reset_gpio;
 	}
 
+	data->family_id = reg_value;
+
 	/*get some register information */
-	reg_addr = FT5X06_REG_FW_VER;
+	reg_addr = FT_REG_FW_VER;
 	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err)
+	if (err < 0)
 		dev_err(&client->dev, "version read failed");
 
-	dev_info(&client->dev, "[FTS] Firmware version = 0x%x\n", reg_value);
+	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
 
-	reg_addr = FT5X06_REG_POINT_RATE;
+	reg_addr = FT_REG_POINT_RATE;
 	ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err)
+	if (err < 0)
 		dev_err(&client->dev, "report rate read failed");
-	dev_info(&client->dev, "[FTS] report rate is %dHz.\n", reg_value * 10);
 
-	reg_addr = FT5X06_REG_THGROUP;
+	dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
+
+	reg_addr = FT_REG_THGROUP;
 	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err)
+	if (err < 0)
 		dev_err(&client->dev, "threshold read failed");
-	dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", reg_value * 4);
+
+	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
 
 	err = request_threaded_irq(client->irq, NULL,
 				   ft5x06_ts_interrupt, pdata->irqflags,
@@ -693,9 +1312,66 @@
 		goto free_reset_gpio;
 	}
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+	err = device_create_file(&client->dev, &dev_attr_fw_name);
+	if (err) {
+		dev_err(&client->dev, "sys file creation failed\n");
+		goto irq_free;
+	}
+
+	err = device_create_file(&client->dev, &dev_attr_update_fw);
+	if (err) {
+		dev_err(&client->dev, "sys file creation failed\n");
+		goto free_fw_name_sys;
+	}
+
+	err = device_create_file(&client->dev, &dev_attr_force_update_fw);
+	if (err) {
+		dev_err(&client->dev, "sys file creation failed\n");
+		goto free_update_fw_sys;
+	}
+
+	dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
+	if (dir == NULL || IS_ERR(dir)) {
+		pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
+		err = PTR_ERR(dir);
+		goto free_force_update_fw_sys;
+	}
+
+	temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dir, data,
+				   &debug_addr_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		err = PTR_ERR(temp);
+		goto free_debug_dir;
+	}
+
+	temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, dir, data,
+				   &debug_data_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		err = PTR_ERR(temp);
+		goto free_debug_dir;
+	}
+
+	temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, dir, data,
+				   &debug_suspend_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		err = PTR_ERR(temp);
+		goto free_debug_dir;
+	}
+
+#if defined(CONFIG_FB)
+	data->fb_notif.notifier_call = fb_notifier_callback;
+
+	err = fb_register_client(&data->fb_notif);
+
+	if (err)
+		dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
+			err);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 	data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
-	    FT5X06_SUSPEND_LEVEL;
+						    FT_SUSPEND_LEVEL;
 	data->early_suspend.suspend = ft5x06_ts_early_suspend;
 	data->early_suspend.resume = ft5x06_ts_late_resume;
 	register_early_suspend(&data->early_suspend);
@@ -703,12 +1379,22 @@
 
 	return 0;
 
+free_debug_dir:
+	debugfs_remove_recursive(data->dir);
+free_force_update_fw_sys:
+	device_remove_file(&client->dev, &dev_attr_force_update_fw);
+free_update_fw_sys:
+	device_remove_file(&client->dev, &dev_attr_update_fw);
+free_fw_name_sys:
+	device_remove_file(&client->dev, &dev_attr_fw_name);
+irq_free:
+	free_irq(client->irq, data);
 free_reset_gpio:
 	if (gpio_is_valid(pdata->reset_gpio))
 		gpio_free(pdata->reset_gpio);
 free_irq_gpio:
 	if (gpio_is_valid(pdata->irq_gpio))
-		gpio_free(pdata->reset_gpio);
+		gpio_free(pdata->irq_gpio);
 pwr_off:
 	if (pdata->power_on)
 		pdata->power_on(false);
@@ -733,7 +1419,15 @@
 {
 	struct ft5x06_ts_data *data = i2c_get_clientdata(client);
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+	debugfs_remove_recursive(data->dir);
+	device_remove_file(&client->dev, &dev_attr_force_update_fw);
+	device_remove_file(&client->dev, &dev_attr_update_fw);
+	device_remove_file(&client->dev, &dev_attr_fw_name);
+
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&data->fb_notif))
+		dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 	unregister_early_suspend(&data->early_suspend);
 #endif
 	free_irq(client->irq, data);
@@ -742,7 +1436,7 @@
 		gpio_free(data->pdata->reset_gpio);
 
 	if (gpio_is_valid(data->pdata->irq_gpio))
-		gpio_free(data->pdata->reset_gpio);
+		gpio_free(data->pdata->irq_gpio);
 
 	if (data->pdata->power_on)
 		data->pdata->power_on(false);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index d51481f..349b020 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -304,10 +304,10 @@
 };
 
 static struct device_attribute attrs[] = {
-	__ATTR(forceflash, S_IWUGO,
+	__ATTR(force_update_fw, S_IWUGO,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_force_reflash_store),
-	__ATTR(doreflash, S_IWUGO,
+	__ATTR(update_fw, S_IWUGO,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_do_reflash_store),
 	__ATTR(writeconfig, S_IWUGO,
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index c3a5564..aef6295 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -133,6 +133,11 @@
 			_rgb_led_blue << PM8XXX_ID_RGB_LED_BLUE, \
 	}
 
+#define PM8XXX_PWM_CURRENT_4MA		4
+#define PM8XXX_PWM_CURRENT_8MA		8
+#define PM8XXX_PWM_CURRENT_12MA		12
+
+
 /**
  * supported_leds - leds supported for each PMIC version
  * @version - version of PMIC
@@ -795,7 +800,7 @@
 
 static int pm8xxx_led_pwm_configure(struct pm8xxx_led_data *led)
 {
-	int start_idx, idx_len, duty_us, rc;
+	int start_idx, idx_len, duty_us, rc, flags;
 
 	led->pwm_dev = pwm_request(led->pwm_channel,
 					led->cdev.name);
@@ -808,6 +813,22 @@
 		return -ENODEV;
 	}
 
+	flags = PM8XXX_LED_PWM_FLAGS;
+	switch (led->max_current) {
+	case PM8XXX_PWM_CURRENT_4MA:
+		flags |= PM_PWM_BANK_LO;
+		break;
+	case PM8XXX_PWM_CURRENT_8MA:
+		flags |= PM_PWM_BANK_HI;
+		break;
+	case PM8XXX_PWM_CURRENT_12MA:
+		flags |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+		break;
+	default:
+		flags |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+		break;
+	}
+
 	if (led->pwm_duty_cycles != NULL) {
 		start_idx = led->pwm_duty_cycles->start_idx;
 		idx_len = led->pwm_duty_cycles->num_duty_pcts;
@@ -825,7 +846,7 @@
 				led->pwm_duty_cycles->duty_pcts,
 				led->pwm_duty_cycles->duty_ms,
 				start_idx, idx_len, 0, 0,
-				PM8XXX_LED_PWM_FLAGS);
+				flags);
 	} else {
 		duty_us = led->pwm_period_us;
 		rc = pwm_config(led->pwm_dev, duty_us, led->pwm_period_us);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index ff9c9b8..2c5e136 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -38,6 +38,10 @@
 		.compatible = "qcom,vfe40",
 		.data = &vfe40_hw_info,
 	},
+	{
+		.compatible = "qcom,vfe32",
+		.data = &vfe32_hw_info,
+	},
 	{}
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index cf03c7f..f1f4c17 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -419,6 +419,7 @@
 	struct msm_vfe_error_info error_info;
 	struct msm_isp_buf_mgr *buf_mgr;
 	int dump_reg;
+	int vfe_clk_idx;
 	uint32_t vfe_open_cnt;
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 73b4f4d..4c5f258 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -22,7 +22,7 @@
 #include "msm.h"
 #include "msm_camera_io_util.h"
 
-#define VFE32_BURST_LEN 3
+#define VFE32_BURST_LEN 1
 #define VFE32_UB_SIZE 1024
 #define VFE32_EQUAL_SLICE_UB 204
 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
@@ -40,7 +40,17 @@
 	(~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
 
 #define VFE32_CLK_IDX 0
-static struct msm_cam_clk_info msm_vfe32_clk_info[] = {
+static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = {
+	/*vfe32 clock info for B-family: 8610 */
+	{"vfe_clk_src", 266670000},
+	{"vfe_clk", -1},
+	{"vfe_ahb_clk", -1},
+	{"csi_vfe_clk", -1},
+	{"bus_clk", -1},
+};
+
+static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = {
+	/*vfe32 clock info for A-family: 8960 */
 	{"vfe_clk", 266667000},
 	{"vfe_pclk", -1},
 	{"csi_vfe_clk", -1},
@@ -49,6 +59,7 @@
 static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
 {
 	int rc = -1;
+	vfe_dev->vfe_clk_idx = 0;
 	rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
 	if (rc < 0) {
 		pr_err("%s: Bandwidth registration Failed!\n", __func__);
@@ -63,10 +74,18 @@
 		}
 	}
 
-	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
-		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 1);
-	if (rc < 0)
-		goto clk_enable_failed;
+	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
+		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
+	if (rc < 0) {
+		rc = msm_cam_clk_enable(&vfe_dev->pdev->dev,
+			 msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+			ARRAY_SIZE(msm_vfe32_2_clk_info), 1);
+		if (rc < 0)
+			goto clk_enable_failed;
+		else
+			vfe_dev->vfe_clk_idx = 2;
+	} else
+		vfe_dev->vfe_clk_idx = 1;
 
 	vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start,
 		resource_size(vfe_dev->vfe_mem));
@@ -87,8 +106,14 @@
 irq_req_failed:
 	iounmap(vfe_dev->vfe_base);
 vfe_remap_failed:
-	msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
-		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 1)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 2)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
 clk_enable_failed:
 	regulator_disable(vfe_dev->fs_vfe);
 fs_failed:
@@ -102,8 +127,14 @@
 	free_irq(vfe_dev->vfe_irq->start, vfe_dev);
 	tasklet_kill(&vfe_dev->vfe_tasklet);
 	iounmap(vfe_dev->vfe_base);
-	msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
-		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 1)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 2)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
 	regulator_disable(vfe_dev->fs_vfe);
 	msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
 }
@@ -330,7 +361,18 @@
 static void msm_vfe32_axi_reload_wm(
 	struct vfe_device *vfe_dev, uint32_t reload_mask)
 {
-	msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+	if (!vfe_dev->pdev->dev.of_node) {
+		/*vfe32 A-family: 8960*/
+		msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+	} else {
+		/*vfe32 B-family: 8610*/
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x24);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x20);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
+		msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600);
+		msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38);
+	}
 }
 
 static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
@@ -914,14 +956,22 @@
 		goto vfe_no_resource;
 	}
 
-	vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+	if (!vfe_dev->pdev->dev.of_node)
+		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+	else
+		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0");
+
 	if (!vfe_dev->iommu_ctx[0]) {
 		pr_err("%s: no iommux ctx resource?\n", __func__);
 		rc = -ENODEV;
 		goto vfe_no_resource;
 	}
 
-	vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+	if (!vfe_dev->pdev->dev.of_node)
+		vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+	else
+		vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0");
+
 	if (!vfe_dev->iommu_ctx[1]) {
 		pr_err("%s: no iommux ctx resource?\n", __func__);
 		rc = -ENODEV;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 1c146d0..84ba4d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <mach/iommu.h>
+#include <linux/ratelimit.h>
 
 #include "msm_isp40.h"
 #include "msm_isp_util.h"
@@ -496,10 +497,15 @@
 	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
 	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
 	/*Ignore composite 3 irq which is used for dual VFE only*/
-	*irq_status0 &= ~BIT(28);
+	if (*irq_status0 & 0x6000000)
+		*irq_status0 &= ~(0x10000000);
 	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
 	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+	if (*irq_status0 & 0x10000000) {
+		pr_err_ratelimited("%s: Protection triggered\n", __func__);
+		*irq_status0 &= ~(0x10000000);
+	}
 
 	if (*irq_status1 & (1 << 0))
 		vfe_dev->error_info.camif_status =
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f470d36..d3138ed 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -97,6 +97,8 @@
 	case V4L2_PIX_FMT_QGBRG12:
 	case V4L2_PIX_FMT_QGRBG12:
 	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
 		stream_info->num_planes = 1;
 		stream_info->format_factor = ISP_Q2;
 		break;
@@ -165,6 +167,8 @@
 	case V4L2_PIX_FMT_QGBRG8:
 	case V4L2_PIX_FMT_QGRBG8:
 	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
 		size = plane_cfg[plane_idx].output_height *
 		plane_cfg[plane_idx].output_width;
 		break;
@@ -549,9 +553,9 @@
 	}
 
 	if (stream_info->num_planes > 1) {
-		msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
 		vfe_dev->hw_info->vfe_ops.axi_ops.
-		clear_comp_mask(vfe_dev, stream_info);
+			clear_comp_mask(vfe_dev, stream_info);
+		msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
 	} else {
 		vfe_dev->hw_info->vfe_ops.axi_ops.
 		clear_wm_irq_mask(vfe_dev, stream_info);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ac44c61..908d3c6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -619,6 +619,8 @@
 	case V4L2_PIX_FMT_QGBRG8:
 	case V4L2_PIX_FMT_QGRBG8:
 	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
 		val = CAL_WORD(pixel_per_line, 1, 8);
 		break;
 	case V4L2_PIX_FMT_SBGGR10:
@@ -672,6 +674,8 @@
 	case V4L2_PIX_FMT_QGBRG8:
 	case V4L2_PIX_FMT_QGRBG8:
 	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
 		return 8;
 	case V4L2_PIX_FMT_SBGGR10:
 	case V4L2_PIX_FMT_SGBRG10:
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index dc1bcc3..3082e99 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -55,7 +55,7 @@
 static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
 	uint8_t intf_type)
 {
-	return (csid_version <= CSID_VERSION_V2 && intf_type != VFE0) ?
+	return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ?
 		false : true;
 }
 
@@ -67,7 +67,7 @@
 {
 	int rc = 0;
 
-	if (ispif->csid_version < CSID_VERSION_V3) {
+	if (ispif->csid_version < CSID_VERSION_V30) {
 		/* Older ISPIF versiond don't need ahb clokc */
 		return 0;
 	}
@@ -407,14 +407,14 @@
 
 		if ((intftype >= INTF_MAX) ||
 			(vfe_intf >=  ispif->vfe_info.num_vfe) ||
-			(ispif->csid_version <= CSID_VERSION_V2 &&
+			(ispif->csid_version <= CSID_VERSION_V22 &&
 			(vfe_intf > VFE0))) {
 			pr_err("%s: VFEID %d and CSID version %d mismatch\n",
 				__func__, vfe_intf, ispif->csid_version);
 			return -EINVAL;
 		}
 
-		if (ispif->csid_version >= CSID_VERSION_V3)
+		if (ispif->csid_version >= CSID_VERSION_V30)
 				msm_ispif_select_clk_mux(ispif, intftype,
 				params->entries[i].csid, vfe_intf);
 
@@ -488,7 +488,7 @@
 		vfe_intf = params->entries[i].vfe_intf;
 		for (k = 0; k < params->entries[i].num_cids; k++) {
 			cid = params->entries[i].cids[k];
-			vc = cid % 4;
+			vc = cid / 4;
 			if (intf_type == RDI2) {
 				/* zero out two bits */
 				ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &=
@@ -776,7 +776,7 @@
 
 	ispif->csid_version = csid_version;
 
-	if (ispif->csid_version >= CSID_VERSION_V3) {
+	if (ispif->csid_version >= CSID_VERSION_V30) {
 		if (!ispif->clk_mux_mem || !ispif->clk_mux_io) {
 			pr_err("%s csi clk mux mem %p io %p\n", __func__,
 				ispif->clk_mux_mem, ispif->clk_mux_io);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index 6396486..c8a4366 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -103,4 +103,5 @@
 
 #define ISPIF_IRQ_GLOBAL_CLEAR_CMD        0x000001
 
+#define ISPIF_STOP_INTF_IMMEDIATELY              0xAAAAAAAA
 #endif /* __MSM_ISPIF_HWREG_V1_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
index 8b96227..7a06c00 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
@@ -228,6 +228,7 @@
 
 fail_1:
 	__msm_jpeg_exit(msm_jpeg_device_p);
+	return rc;
 
 fail:
 	kfree(msm_jpeg_device_p);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 4f02197..e74f1082 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1013,6 +1013,7 @@
 	struct msm_cpp_frame_info_t *u_frame_info =
 		(struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
 	int32_t status = 0;
+	uint8_t fw_version_1_2_x = 0;
 
 	int i = 0;
 	if (!new_frame) {
@@ -1117,12 +1118,21 @@
 		((cpp_frame_msg[12] >> 10) & 0x3FF) +
 		(cpp_frame_msg[12] & 0x3FF);
 
+	fw_version_1_2_x = 0;
+	if (cpp_dev->hw_info.cpp_hw_version == 0x10010000)
+		fw_version_1_2_x = 2;
+
 	for (i = 0; i < num_stripes; i++) {
-		cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
-		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
-		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
-		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
-		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
+		cpp_frame_msg[(133 + fw_version_1_2_x) + i * 27] +=
+			(uint32_t) in_phyaddr;
+		cpp_frame_msg[(139 + fw_version_1_2_x) + i * 27] +=
+			(uint32_t) out_phyaddr0;
+		cpp_frame_msg[(140 + fw_version_1_2_x) + i * 27] +=
+			(uint32_t) out_phyaddr1;
+		cpp_frame_msg[(141 + fw_version_1_2_x) + i * 27] +=
+			(uint32_t) out_phyaddr0;
+		cpp_frame_msg[(142 + fw_version_1_2_x) + i * 27] +=
+			(uint32_t) out_phyaddr1;
 	}
 
 	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
@@ -1549,9 +1559,9 @@
 	}
 
 	cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp");
-	if (!cpp_dev->iommu_ctx) {
+	if (IS_ERR(cpp_dev->iommu_ctx)) {
 		pr_err("%s: cannot get iommu_ctx\n", __func__);
-		rc = -ENODEV;
+		rc = -EPROBE_DEFER;
 		goto ERROR3;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
index 572e722..771167d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
@@ -2,6 +2,8 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
 ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
   ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.0
+else ifeq ($(CONFIG_MSM_CSI22_HEADER),y)
+  ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2
 else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
   ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi3.0
 endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h
new file mode 100644
index 0000000..5b30472
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_HWREG_H
+#define MSM_CSID_HWREG_H
+
+/* MIPI	CSID registers */
+#define CSID_HW_VERSION_ADDR                        0x0
+#define CSID_CORE_CTRL_0_ADDR                       0x4
+#define CSID_CORE_CTRL_1_ADDR                       0x4
+#define CSID_RST_CMD_ADDR                           0x8
+#define CSID_CID_LUT_VC_0_ADDR                      0xc
+#define CSID_CID_LUT_VC_1_ADDR                      0x10
+#define CSID_CID_LUT_VC_2_ADDR                      0x14
+#define CSID_CID_LUT_VC_3_ADDR                      0x18
+#define CSID_CID_n_CFG_ADDR                         0x1C
+#define CSID_IRQ_CLEAR_CMD_ADDR                     0x5c
+#define CSID_IRQ_MASK_ADDR                          0x60
+#define CSID_IRQ_STATUS_ADDR                        0x64
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR    0x68
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR     0x6c
+#define CSID_CAPTURED_SHORT_PKT_ADDR                0x70
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR             0x74
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR             0x78
+#define CSID_PIF_MISR_DL0_ADDR                      0x7C
+#define CSID_PIF_MISR_DL1_ADDR                      0x80
+#define CSID_PIF_MISR_DL2_ADDR                      0x84
+#define CSID_PIF_MISR_DL3_ADDR                      0x88
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR             0x8C
+#define CSID_STATS_ECC_ADDR                         0x90
+#define CSID_STATS_CRC_ADDR                         0x94
+#define CSID_TG_CTRL_ADDR                           0x9C
+#define CSID_TG_VC_CFG_ADDR                         0xA0
+#define CSID_TG_DT_n_CFG_0_ADDR                     0xA8
+#define CSID_TG_DT_n_CFG_1_ADDR                     0xAC
+#define CSID_TG_DT_n_CFG_2_ADDR                     0xB0
+#define CSID_RST_DONE_IRQ_BITSHIFT                  11
+#define CSID_RST_STB_ALL                            0x7FFF
+#define CSID_DL_INPUT_SEL_SHIFT                     0x2
+#define CSID_PHY_SEL_SHIFT                          17
+#define CSID_VERSION                                0x02001000
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 4db6855..7af0c14 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -20,8 +20,9 @@
 #include "msm_camera_io_util.h"
 
 #define V4L2_IDENT_CSID                            50002
-#define CSID_VERSION_V2                      0x02000011
-#define CSID_VERSION_V3                      0x30000000
+#define CSID_VERSION_V20                      0x02000011
+#define CSID_VERSION_V22                      0x02001000
+#define CSID_VERSION_V30                      0x30000000
 #define MSM_CSID_DRV_NAME                    "msm_csid"
 
 #define DBG_CSID 0
@@ -196,6 +197,15 @@
 	{"csi_rdi_clk", -1},
 };
 
+static struct msm_cam_clk_info csid_8610_clk_info[] = {
+	{"csi_ahb_clk", -1},
+	{"csi_src_clk", 200000000},
+	{"csi_clk", -1},
+	{"csi_phy_clk", -1},
+	{"csi_pix_clk", -1},
+	{"csi_rdi_clk", -1},
+};
+
 static struct camera_vreg_t csid_8960_vreg_info[] = {
 	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 };
@@ -207,6 +217,7 @@
 static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
 {
 	int rc = 0;
+	struct camera_vreg_t *cam_vreg;
 
 	if (!csid_version) {
 		pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
@@ -229,31 +240,47 @@
 		return rc;
 	}
 
-	if (CSID_VERSION <= CSID_VERSION_V2) {
+	if (CSID_VERSION == CSID_VERSION_V20)
+		cam_vreg = csid_8960_vreg_info;
+	else
+		cam_vreg = csid_vreg_info;
+
+	if (CSID_VERSION < CSID_VERSION_V30) {
 		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
-			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 1);
 		if (rc < 0) {
 			pr_err("%s: regulator on failed\n", __func__);
 			goto vreg_config_failed;
 		}
-
 		rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
-			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 1);
 		if (rc < 0) {
 			pr_err("%s: regulator enable failed\n", __func__);
 			goto vreg_enable_failed;
 		}
 
-		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
-			csid_8960_clk_info, csid_dev->csid_clk,
-			ARRAY_SIZE(csid_8960_clk_info), 1);
-		if (rc < 0) {
-			pr_err("%s: clock enable failed\n", __func__);
-			goto clk_enable_failed;
+		if (CSID_VERSION == CSID_VERSION_V20) {
+			rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+				csid_8960_clk_info, csid_dev->csid_clk,
+				ARRAY_SIZE(csid_8960_clk_info), 1);
+			if (rc < 0) {
+				pr_err("%s: 8960: clock enable failed\n",
+					 __func__);
+				goto clk_enable_failed;
+			}
+		} else {
+			rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+				csid_8610_clk_info, csid_dev->csid_clk,
+				ARRAY_SIZE(csid_8610_clk_info), 1);
+			if (rc < 0) {
+				pr_err("%s: 8610: clock enable failed\n",
+					 __func__);
+				goto clk_enable_failed;
+			}
 		}
-	} else if (CSID_VERSION >= CSID_VERSION_V3) {
+	} else if (CSID_VERSION >= CSID_VERSION_V30) {
 		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 1);
@@ -294,21 +321,21 @@
 	return rc;
 
 clk_enable_failed:
-	if (CSID_VERSION <= CSID_VERSION_V2) {
+	if (CSID_VERSION < CSID_VERSION_V30) {
 		msm_camera_enable_vreg(&csid_dev->pdev->dev,
-			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
-	} else if (CSID_VERSION >= CSID_VERSION_V3) {
+	} else if (CSID_VERSION >= CSID_VERSION_V30) {
 		msm_camera_enable_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
 	}
 vreg_enable_failed:
-	if (CSID_VERSION <= CSID_VERSION_V2) {
+	if (CSID_VERSION < CSID_VERSION_V30) {
 		msm_camera_config_vreg(&csid_dev->pdev->dev,
-			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
-	} else if (CSID_VERSION >= CSID_VERSION_V3) {
+	} else if (CSID_VERSION >= CSID_VERSION_V30) {
 		msm_camera_config_vreg(&csid_dev->pdev->dev,
 			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
@@ -335,7 +362,7 @@
 
 	disable_irq(csid_dev->irq->start);
 
-	if (csid_dev->hw_version <= CSID_VERSION_V2) {
+	if (csid_dev->hw_version == CSID_VERSION_V20) {
 		msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8960_clk_info,
 			csid_dev->csid_clk, ARRAY_SIZE(csid_8960_clk_info), 0);
 
@@ -346,7 +373,20 @@
 		msm_camera_config_vreg(&csid_dev->pdev->dev,
 			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
 			NULL, 0, &csid_dev->csi_vdd, 0);
-	} else if (csid_dev->hw_version >= CSID_VERSION_V3) {
+	} else if (csid_dev->hw_version == CSID_VERSION_V22) {
+		msm_cam_clk_enable(&csid_dev->pdev->dev,
+			csid_8610_clk_info,
+			csid_dev->csid_clk,
+			ARRAY_SIZE(csid_8610_clk_info), 0);
+
+		msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+
+		msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	} else if (csid_dev->hw_version >= CSID_VERSION_V30) {
 		msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8974_clk_info,
 			csid_dev->csid_clk, ARRAY_SIZE(csid_8974_clk_info), 0);
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
index eab1f6f..61671ea 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
@@ -2,6 +2,8 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
 ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
   ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.0
+else ifeq ($(CONFIG_MSM_CSI22_HEADER),y)
+  ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2
 else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
   ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi3.0
 endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h
new file mode 100644
index 0000000..c4ff05d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_HWREG_H
+#define MSM_CSIPHY_HWREG_H
+
+/*MIPI CSI PHY registers*/
+#define MIPI_CSIPHY_HW_VERSION_ADDR              0x17C
+#define MIPI_CSIPHY_LNn_CFG1_ADDR                0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR                0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR                0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR                0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR                0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR               0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR               0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR               0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR               0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR               0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
+#define MIPI_CSIPHY_GLBL_RESET_ADDR              0x140
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR            0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR            0x164
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR       0x180
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR         0x1A0
+#define MIPI_CSIPHY_INTERRUPT_MASK_VAL           0x6F
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR          0x1A4
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR        0x1C0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR         0x1C4
+#define MIPI_CSIPHY_MODE_CONFIG_SHIFT            0x4
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
+#define CSIPHY_VERSION                           0x1
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 429d151..0fbe238 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -24,7 +24,9 @@
 #define DBG_CSIPHY 0
 
 #define V4L2_IDENT_CSIPHY                        50003
-#define CSIPHY_VERSION_V3                        0x10
+#define CSIPHY_VERSION_V22                        0x01
+#define CSIPHY_VERSION_V20                        0x00
+#define CSIPHY_VERSION_V30                        0x10
 #define MSM_CSIPHY_DRV_NAME                      "msm_csiphy"
 
 #undef CDBG
@@ -66,7 +68,7 @@
 		csiphy_params->settle_cnt,
 		csiphy_params->csid_core);
 
-	if (csiphy_dev->hw_version >= CSIPHY_VERSION_V3) {
+	if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) {
 		val = msm_camera_io_r(csiphy_dev->clk_mux_base);
 		if (csiphy_params->combo_mode &&
 			(csiphy_params->lane_mask & 0x18)) {
@@ -84,7 +86,7 @@
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
 
-	if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+	if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
 		val = 0x3;
 		msm_camera_io_w((lane_mask << 2) | val,
 				csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
@@ -173,6 +175,11 @@
 	{"csiphy_timer_clk", -1},
 };
 
+static struct msm_cam_clk_info csiphy_8610_clk_info[] = {
+	{"csiphy_timer_src_clk", 200000000},
+	{"csiphy_timer_clk", -1},
+};
+
 static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
 	{"camss_top_ahb_clk", -1},
 	{"ispif_ahb_clk", -1},
@@ -216,12 +223,17 @@
 	}
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
 		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 1);
-	} else {
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+		CDBG("%s:%d called\n", __func__, __LINE__);
+		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8610_clk_info), 1);
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
 		if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
 			pr_err("%s clk mux mem %p io %p\n", __func__,
 				csiphy_dev->clk_mux_mem,
@@ -242,6 +254,11 @@
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 1);
+	} else {
+		pr_err("%s: ERROR Invalid CSIPHY Version %d",
+			 __func__, __LINE__);
+		rc = -EINVAL;
+		return rc;
 	}
 
 	CDBG("%s:%d called\n", __func__, __LINE__);
@@ -259,8 +276,13 @@
 	msm_csiphy_reset(csiphy_dev);
 
 	CDBG("%s:%d called\n", __func__, __LINE__);
-	csiphy_dev->hw_version =
-		msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V30)
+		csiphy_dev->hw_version =
+			msm_camera_io_r(csiphy_dev->base +
+				 MIPI_CSIPHY_HW_VERSION_ADDR);
+	else
+		csiphy_dev->hw_version = CSIPHY_VERSION;
 
 	CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__,
 		csiphy_dev->hw_version);
@@ -304,13 +326,17 @@
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
 		CDBG("%s:%d called\n", __func__, __LINE__);
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 1);
-	} else {
-
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+		CDBG("%s:%d called\n", __func__, __LINE__);
+		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8610_clk_info), 1);
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
 		if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
 			pr_err("%s clk mux mem %p io %p\n", __func__,
 				csiphy_dev->clk_mux_mem,
@@ -332,6 +358,11 @@
 		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 1);
+	} else {
+		pr_err("%s: ERROR Invalid CSIPHY Version %d",
+			 __func__, __LINE__);
+		rc = -EINVAL;
+		return rc;
 	}
 
 	CDBG("%s:%d called\n", __func__, __LINE__);
@@ -347,8 +378,13 @@
 	msm_csiphy_reset(csiphy_dev);
 
 	CDBG("%s:%d called\n", __func__, __LINE__);
-	csiphy_dev->hw_version =
-		msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V30)
+		csiphy_dev->hw_version =
+			msm_camera_io_r(csiphy_dev->base +
+				 MIPI_CSIPHY_HW_VERSION_ADDR);
+	else
+		csiphy_dev->hw_version = CSIPHY_VERSION;
 
 	CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__,
 		csiphy_dev->hw_version);
@@ -382,7 +418,7 @@
 		csi_lane_params->csi_lane_assign,
 		csi_lane_params->csi_lane_mask);
 
-	if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+	if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
 		for (i = 0; i < 4; i++)
 			msm_camera_io_w(0x0, csiphy_dev->base +
@@ -412,11 +448,15 @@
 
 	disable_irq(csiphy_dev->irq->start);
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 0);
-	} else {
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8610_clk_info), 0);
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 0);
@@ -453,7 +493,7 @@
 		csi_lane_params->csi_lane_assign,
 		csi_lane_params->csi_lane_mask);
 
-	if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+	if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
 		for (i = 0; i < 4; i++)
 			msm_camera_io_w(0x0, csiphy_dev->base +
@@ -481,11 +521,17 @@
 	msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
 	msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
 
-	if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+	if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8960_clk_info), 0);
-	} else {
+
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8610_clk_info), 0);
+
+	} else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
 		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
 			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
 			ARRAY_SIZE(csiphy_8974_clk_info), 0);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index 9b02b17..8368a4d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -93,9 +93,15 @@
 	{ }
 };
 
+static int32_t msm_imx135_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &imx135_s_ctrl);
+}
+
 static struct i2c_driver imx135_i2c_driver = {
 	.id_table = imx135_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_imx135_i2c_probe,
 	.driver = {
 		.name = IMX135_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 68c7d23..c834925 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -613,11 +613,10 @@
 	return rc;
 }
 
-static int32_t msm_sensor_get_dt_data(struct platform_device *pdev,
+static int32_t msm_sensor_get_dt_data(struct device_node *of_node,
 	struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int32_t rc = 0, i = 0, ret = 0;
-	struct device_node *of_node = pdev->dev.of_node;
 	struct msm_camera_gpio_conf *gconf = NULL;
 	struct msm_camera_sensor_board_info *sensordata = NULL;
 	uint16_t *gpio_array = NULL;
@@ -867,6 +866,11 @@
 	[SENSOR_CAM_MCLK] = {"cam_clk", 24000000},
 };
 
+static struct msm_cam_clk_info cam_8610_clk_info[] = {
+	[SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000},
+	[SENSOR_CAM_CLK] = {"cam_clk", 0},
+};
+
 static struct msm_cam_clk_info cam_8974_clk_info[] = {
 	[SENSOR_CAM_MCLK] = {"cam_src_clk", 19200000},
 	[SENSOR_CAM_CLK] = {"cam_clk", 0},
@@ -1670,7 +1674,7 @@
 	CDBG("%s called data %p\n", __func__, data);
 	CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name);
 	if (pdev->dev.of_node) {
-		rc = msm_sensor_get_dt_data(pdev, s_ctrl);
+		rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl);
 		if (rc < 0) {
 			pr_err("%s failed line %d\n", __func__, __LINE__);
 			return rc;
@@ -1744,10 +1748,9 @@
 }
 
 int32_t msm_sensor_i2c_probe(struct i2c_client *client,
-	const struct i2c_device_id *id)
+	const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int rc = 0;
-	struct msm_sensor_ctrl_t *s_ctrl;
 	uint32_t session_id;
 	CDBG("%s %s_i2c_probe called\n", __func__, client->name);
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
@@ -1757,15 +1760,25 @@
 		return rc;
 	}
 
-	s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
-	if (!s_ctrl) {
-		pr_err("%s:%d sensor ctrl structure NULL\n", __func__,
-			__LINE__);
-		return -EINVAL;
+	if (!client->dev.of_node) {
+		CDBG("msm_sensor_i2c_probe: of_node is NULL");
+		s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+		if (!s_ctrl) {
+			pr_err("%s:%d sensor ctrl structure NULL\n", __func__,
+				__LINE__);
+			return -EINVAL;
+		}
+		s_ctrl->sensordata = client->dev.platform_data;
+	} else {
+		CDBG("msm_sensor_i2c_probe: of_node exisists");
+		rc = msm_sensor_get_dt_data(client->dev.of_node, s_ctrl);
+		if (rc < 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return rc;
+		}
 	}
 
 	s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE;
-	s_ctrl->sensordata = client->dev.platform_data;
 	if (s_ctrl->sensordata == NULL) {
 		pr_err("%s %s NULL sensor data\n", __func__, client->name);
 		return -EFAULT;
@@ -1793,14 +1806,27 @@
 	if (!s_ctrl->sensor_v4l2_subdev_ops)
 		s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
 
-	s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
-		GFP_KERNEL);
-	if (!s_ctrl->clk_info) {
-		pr_err("%s:%d failed nomem\n", __func__, __LINE__);
-		return -ENOMEM;
+	if (!client->dev.of_node) {
+		s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
+			GFP_KERNEL);
+		if (!s_ctrl->clk_info) {
+			pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+			return -ENOMEM;
+		}
+		memcpy(s_ctrl->clk_info, cam_8960_clk_info,
+			sizeof(cam_8960_clk_info));
+		s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
+	} else {
+		s_ctrl->clk_info = kzalloc(sizeof(cam_8610_clk_info),
+			GFP_KERNEL);
+		if (!s_ctrl->clk_info) {
+			pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+			return -ENOMEM;
+		}
+		memcpy(s_ctrl->clk_info, cam_8610_clk_info,
+			sizeof(cam_8610_clk_info));
+		s_ctrl->clk_info_size = ARRAY_SIZE(cam_8610_clk_info);
 	}
-	memcpy(s_ctrl->clk_info, cam_8960_clk_info, sizeof(cam_8960_clk_info));
-	s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
 
 	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
 	if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index fe11a56..80a2bd4 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -88,7 +88,7 @@
 	void *data);
 
 int32_t msm_sensor_i2c_probe(struct i2c_client *client,
-	const struct i2c_device_id *id);
+	const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl);
 
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
index 9911a59..c1cf862 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
@@ -1107,9 +1107,15 @@
 	{ }
 };
 
+static int32_t msm_mt9m114_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &mt9m114_s_ctrl);
+}
+
 static struct i2c_driver mt9m114_i2c_driver = {
 	.id_table = mt9m114_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_mt9m114_i2c_probe,
 	.driver = {
 		.name = MT9M114_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov2720.c b/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
index d790c65..397564b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
@@ -75,9 +75,15 @@
 	{ }
 };
 
+static int32_t msm_ov2720_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov2720_s_ctrl);
+}
+
 static struct i2c_driver ov2720_i2c_driver = {
 	.id_table = ov2720_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_ov2720_i2c_probe,
 	.driver = {
 		.name = OV2720_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index b56eb10..3256c5c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -93,9 +93,15 @@
 	{ }
 };
 
+static int32_t msm_ov8825_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov8825_s_ctrl);
+}
+
 static struct i2c_driver ov8825_i2c_driver = {
 	.id_table = ov8825_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_ov8825_i2c_probe,
 	.driver = {
 		.name = OV8825_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 981cc10..56af02b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -83,6 +83,12 @@
 	},
 };
 
+static int32_t msm_ov9724_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov9724_s_ctrl);
+}
+
 static const struct i2c_device_id ov9724_i2c_id[] = {
 	{OV9724_SENSOR_NAME, (kernel_ulong_t)&ov9724_s_ctrl},
 	{ }
@@ -90,7 +96,7 @@
 
 static struct i2c_driver ov9724_i2c_driver = {
 	.id_table = ov9724_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_ov9724_i2c_probe,
 	.driver = {
 		.name = OV9724_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
index 21a7369..225e81d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
@@ -93,9 +93,15 @@
 	{ }
 };
 
+static int32_t msm_s5k3l1yx_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &s5k3l1yx_s_ctrl);
+}
+
 static struct i2c_driver s5k3l1yx_i2c_driver = {
 	.id_table = s5k3l1yx_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = msm_s5k3l1yx_i2c_probe,
 	.driver = {
 		.name = S5K3L1YX_SENSOR_NAME,
 	},
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index a63fccf..85fdff6 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -14,11 +14,12 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/file.h>
+#include <linux/scatterlist.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
 #include "mpq_sdmx.h"
 
-#define SDMX_MAJOR_VERSION_MATCH	(3)
+#define SDMX_MAJOR_VERSION_MATCH	(4)
 
 #define TS_PACKET_HEADER_LENGTH (4)
 
@@ -3357,7 +3358,6 @@
 		if (status != SDMX_SUCCESS) {
 			MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n",
 				__func__, status);
-			return -EINVAL;
 		}
 		mpq_demux->sdmx_eos = 0;
 		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
@@ -3369,14 +3369,64 @@
 }
 EXPORT_SYMBOL(mpq_sdmx_close_session);
 
+static int mpq_sdmx_get_buffer_chunks(struct mpq_demux *mpq_demux,
+	struct ion_handle *buff_handle,
+	u32 actual_buff_size,
+	struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS])
+{
+	int i;
+	struct sg_table *sg_ptr;
+	struct scatterlist *sg;
+	u32 chunk_size;
+
+	memset(buff_chunks, 0,
+		sizeof(struct sdmx_buff_descr) * SDMX_MAX_PHYSICAL_CHUNKS);
+
+	sg_ptr = ion_sg_table(mpq_demux->ion_client, buff_handle);
+	if (sg_ptr == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: ion_sg_table failed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (sg_ptr->nents == 0) {
+		MPQ_DVB_ERR_PRINT("%s: num of scattered entries is 0\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (sg_ptr->nents > SDMX_MAX_PHYSICAL_CHUNKS) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: num of scattered entries %d greater than max supported %d\n",
+			__func__, sg_ptr->nents, SDMX_MAX_PHYSICAL_CHUNKS);
+		return -EINVAL;
+	}
+
+	sg = sg_ptr->sgl;
+	for (i = 0; i < sg_ptr->nents; i++) {
+		buff_chunks[i].base_addr =
+			(void *)sg_dma_address(sg);
+		if (sg->length > actual_buff_size)
+			chunk_size = actual_buff_size;
+		else
+			chunk_size = sg->length;
+
+		buff_chunks[i].size = chunk_size;
+		sg = sg_next(sg);
+		actual_buff_size -= chunk_size;
+	}
+
+	return 0;
+}
+
 static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux,
 	struct mpq_feed *feed, u32 *num_buffers,
-	struct sdmx_buff_descr *buf_desc, enum sdmx_buf_mode *buf_mode)
+	struct sdmx_data_buff_descr buf_desc[DMX_MAX_DECODER_BUFFER_NUM],
+	enum sdmx_buf_mode *buf_mode)
 {
 	struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed;
 	struct dvb_ringbuffer *buffer;
 	struct mpq_video_feed_info *feed_data = &feed->video_info;
-	ion_phys_addr_t addr;
 	struct ion_handle *sdmx_buff;
 	int ret;
 	int i;
@@ -3389,57 +3439,56 @@
 		*num_buffers = feed_data->buffer_desc.decoder_buffers_num;
 
 		for (i = 0; i < *num_buffers; i++) {
-			ret = ion_phys(mpq_demux->ion_client,
-				feed_data->buffer_desc.ion_handle[i],
-				&addr, &buf_desc[i].size);
+			buf_desc[i].length =
+				feed_data->buffer_desc.desc[i].size;
+
+			ret = mpq_sdmx_get_buffer_chunks(mpq_demux,
+					feed_data->buffer_desc.ion_handle[i],
+					buf_desc[i].length,
+					buf_desc[i].buff_chunks);
 			if (ret) {
 				MPQ_DVB_ERR_PRINT(
-					"%s: FAILED to get physical buffer address, ret=%d\n",
-					__func__, ret);
-					goto end;
+					"%s: mpq_sdmx_get_buffer_chunks failed\n",
+					__func__);
+				return ret;
 			}
-			buf_desc[i].base_addr = (void *)addr;
-			buf_desc[i].size = feed_data->buffer_desc.desc[i].size;
-		}
-	} else {
-		*num_buffers = 1;
-		if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
-			dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
-			buffer = &feed->sdmx_buf;
-			sdmx_buff = feed->sdmx_buf_handle;
-		} else {
-			buffer = (struct dvb_ringbuffer *)
-				dvbdmx_feed->feed.ts.buffer.ringbuff;
-			sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
 		}
 
-		if (sdmx_buff == NULL) {
-			MPQ_DVB_ERR_PRINT(
-				"%s: Invalid buffer allocation\n",
-				__func__);
-			return -ENOMEM;
-		}
-
-		ret = ion_phys(mpq_demux->ion_client, sdmx_buff, &addr,
-			&buf_desc[0].size);
-		if (ret) {
-			MPQ_DVB_ERR_PRINT(
-				"%s: FAILED to get physical buffer address, ret=%d\n",
-				__func__, ret);
-				goto end;
-		} else {
-			buf_desc[0].size = buffer->size;
-			buf_desc[0].base_addr = (void *)addr;
-		}
-
+		return 0;
 	}
+
+	*num_buffers = 1;
+	if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
+		dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
+		buffer = &feed->sdmx_buf;
+		sdmx_buff = feed->sdmx_buf_handle;
+	} else {
+		buffer = (struct dvb_ringbuffer *)
+			dvbdmx_feed->feed.ts.buffer.ringbuff;
+		sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
+	}
+
+	if (sdmx_buff == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid buffer allocation\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	buf_desc[0].length = buffer->size;
+	ret = mpq_sdmx_get_buffer_chunks(mpq_demux, sdmx_buff,
+		buf_desc[0].length,
+		buf_desc[0].buff_chunks);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_get_buffer_chunks failed\n",
+			__func__);
+		return ret;
+	}
+
 	return 0;
-
-end:
-	return ret;
 }
 
-
 static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux,
 	struct dvb_demux_feed *dvbdmx_feed)
 {
@@ -3447,7 +3496,7 @@
 	struct mpq_feed *feed;
 	struct mpq_feed *main_rec_feed;
 	struct sdmx_buff_descr metadata_buff_desc;
-	struct sdmx_buff_descr data_buff_desc[DMX_MAX_DECODER_BUFFER_NUM];
+	struct sdmx_data_buff_descr *data_buff_desc = NULL;
 	u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM;
 	enum sdmx_buf_mode buf_mode;
 	enum sdmx_raw_out_format ts_out_format = SDMX_188_OUTPUT;
@@ -3490,6 +3539,15 @@
 		MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__);
 	}
 
+	data_buff_desc = vmalloc(
+			sizeof(*data_buff_desc)*DMX_MAX_DECODER_BUFFER_NUM);
+	if (!data_buff_desc) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: failed to allocate memory for data buffer\n",
+			__func__);
+		return -ENOMEM;
+	}
+
 	/*
 	 * Recording feed sdmx filter handle lookup:
 	 * In case this is a recording filter with multiple feeds,
@@ -3530,7 +3588,7 @@
 				MPQ_DVB_ERR_PRINT(
 					"%s: Failed to initialize metadata buffer. ret=%d\n",
 					__func__, ret);
-				goto end;
+				goto sdmx_filter_setup_failed;
 			}
 		}
 
@@ -3541,7 +3599,7 @@
 				"%s: Failed to initialize data buffer. ret=%d\n",
 				__func__, ret);
 			mpq_sdmx_terminate_metadata_buffer(feed);
-			goto end;
+			goto sdmx_filter_setup_failed;
 		}
 		ret = sdmx_add_filter(mpq_demux->sdmx_session_handle,
 			dvbdmx_feed->pid,
@@ -3559,14 +3617,14 @@
 				__func__, ret);
 			ret = -ENODEV;
 			mpq_sdmx_terminate_metadata_buffer(feed);
-			goto end;
+			goto sdmx_filter_setup_failed;
 		}
 
 		MPQ_DVB_DBG_PRINT(
 			"%s: feed=0x%p, filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n",
 			__func__, feed, dvbdmx_feed->pid,
 			feed->sdmx_filter_handle,
-			data_buf_num, data_buff_desc[0].size);
+			data_buf_num, data_buff_desc[0].length);
 
 		mpq_demux->sdmx_filter_count++;
 	} else {
@@ -3583,7 +3641,7 @@
 				"%s: FAILED to add raw pid, ret=%d\n",
 				__func__, ret);
 			ret = -ENODEV;
-			goto end;
+			goto sdmx_filter_setup_failed;
 		}
 	}
 
@@ -3605,12 +3663,14 @@
 			MPQ_DVB_ERR_PRINT(
 				"%s: FAILED to set key ladder, ret=%d\n",
 				__func__, ret);
-			ret = -ENODEV;
-			goto end;
 		}
 	}
 
-end:
+	vfree(data_buff_desc);
+	return 0;
+
+sdmx_filter_setup_failed:
+	vfree(data_buff_desc);
 	return ret;
 }
 
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
index 14d3a39..888bbbf 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
@@ -115,7 +115,7 @@
 	enum sdmx_raw_out_format ts_out_format;
 	u32 flags;
 	u32 num_data_bufs;
-	struct sdmx_buff_descr data_bufs[];
+	struct sdmx_data_buff_descr data_bufs[];
 };
 
 struct sdmx_add_filt_rsp {
@@ -478,7 +478,7 @@
 	struct sdmx_buff_descr *meta_data_buf,
 	enum sdmx_buf_mode d_buf_mode,
 	u32 num_data_bufs,
-	struct sdmx_buff_descr *data_bufs,
+	struct sdmx_data_buff_descr *data_bufs,
 	int *filter_handle,
 	enum sdmx_raw_out_format ts_out_format,
 	u32 flags)
@@ -493,7 +493,7 @@
 		return SDMX_STATUS_INVALID_INPUT_PARAMS;
 
 	cmd_len = sizeof(struct sdmx_add_filt_req)
-		+ num_data_bufs * sizeof(struct sdmx_buff_descr);
+		+ num_data_bufs * sizeof(struct sdmx_data_buff_descr);
 	rsp_len = sizeof(struct sdmx_add_filt_rsp);
 
 	/* Will be later overridden by SDMX response */
@@ -523,7 +523,7 @@
 	cmd->buffer_mode = d_buf_mode;
 	cmd->num_data_bufs = num_data_bufs;
 	memcpy(cmd->data_bufs, data_bufs,
-		num_data_bufs * sizeof(struct sdmx_buff_descr));
+		num_data_bufs * sizeof(struct sdmx_data_buff_descr));
 
 	/* Issue QSEECom command */
 	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 6b669e4..fadb6b2 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -19,6 +19,8 @@
 #define SDMX_MAX_SESSIONS  (4)
 #define SDMX_LOOPBACK_PID  (0x2000)
 
+#define SDMX_MAX_PHYSICAL_CHUNKS (10)
+
 /* Filter-level error indicators */
 #define SDMX_FILTER_SUCCESS                       (0)
 #define SDMX_FILTER_ERR_MD_BUF_FULL               BIT(0)
@@ -164,10 +166,18 @@
 	/* Physical address where buffer starts */
 	void *base_addr;
 
-	/* Total size of buffer */
+	/* Size of buffer */
 	u32 size;
 };
 
+struct sdmx_data_buff_descr {
+	/* Physical chunks of the buffer */
+	struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS];
+
+	/* Length of buffer */
+	u32 length;
+};
+
 /*
  * Data payload residing in the data buffers is described using this meta-data
  * header. The meta data header specifies where the payload is located in the
@@ -231,7 +241,7 @@
 
 int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type,
 	struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
-	u32 num_data_bufs, struct sdmx_buff_descr *data_bufs,
+	u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs,
 	int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags);
 
 int sdmx_remove_filter(int session_handle, int filter_handle);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 29ae7b4..7547464 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1251,11 +1251,9 @@
 static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
 {
 	int rc = 0;
-	struct v4l2_control control;
 	struct hal_nal_stream_format_supported stream_format;
 	struct hal_enable_picture enable_picture;
 	struct hal_enable hal_property;/*, prop;*/
-	u32 control_idx = 0;
 	enum hal_property property_id = 0;
 	u32 property_val = 0;
 	void *pdata = NULL;
@@ -1357,10 +1355,8 @@
 
 	if (!rc && property_id) {
 		dprintk(VIDC_DBG,
-			"Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
-			property_id,
-			msm_vdec_ctrls[control_idx].id,
-			control.value);
+			"Control: HAL property = %d, ctrl_id = 0x%x, ctrl_value = %d\n",
+			property_id, ctrl->id, ctrl->val);
 			rc = call_hfi_op(hdev, session_set_property, (void *)
 				inst->session, property_id, pdata);
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index e5619ea..7fc2595 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -21,7 +21,7 @@
 #define MSM_VENC_DVC_NAME "msm_venc_8974"
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MIN_NUM_CAPTURE_BUFFERS 4
-#define MIN_BIT_RATE 64000
+#define MIN_BIT_RATE 32000
 #define MAX_BIT_RATE 160000000
 #define DEFAULT_BIT_RATE 64000
 #define BIT_RATE_STEP 100
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index ae1e9b7..bea9070 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -15,7 +15,8 @@
 #include "vidc_hfi_api.h"
 
 #define MAX_DBG_BUF_SIZE 4096
-int msm_vidc_debug = 0x3;
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
 int msm_fw_debug = 0x18;
 int msm_fw_debug_mode = 0x1;
 int msm_fw_low_power_mode = 0x1;
@@ -171,6 +172,11 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	if (!debugfs_create_u32("debug_output", S_IRUGO | S_IWUSR,
+			parent, &msm_vidc_debug_out)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
 failed_create_dir:
 	return dir;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index ea6dd70..5b572c9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -31,9 +31,15 @@
 	VIDC_INFO = 0x0004,
 	VIDC_DBG  = 0x0008,
 	VIDC_PROF = 0x0010,
+	VIDC_PKT  = 0x0020,
 	VIDC_FW   = 0x1000,
 };
 
+enum vidc_msg_out {
+	VIDC_OUT_PRINTK = 0,
+	VIDC_OUT_FTRACE,
+};
+
 enum msm_vidc_debugfs_event {
 	MSM_VIDC_DEBUGFS_EVENT_ETB,
 	MSM_VIDC_DEBUGFS_EVENT_EBD,
@@ -42,6 +48,7 @@
 };
 
 extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
 extern int msm_fw_debug;
 extern int msm_fw_debug_mode;
 extern int msm_fw_low_power_mode;
@@ -49,11 +56,18 @@
 
 #define dprintk(__level, __fmt, arg...)	\
 	do { \
-		if (msm_vidc_debug & __level) \
-			printk(KERN_DEBUG VIDC_DBG_TAG \
-				__fmt, __level, ## arg); \
+		if (msm_vidc_debug & __level) { \
+			if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+				printk(KERN_DEBUG VIDC_DBG_TAG \
+						__fmt, __level, ## arg); \
+			} else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+				trace_printk(KERN_DEBUG VIDC_DBG_TAG \
+						__fmt, __level, ## arg); \
+			} \
+		} \
 	} while (0)
 
+
 struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
 		struct dentry *parent);
 struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index ca4ac53..8453b81 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -62,6 +62,23 @@
 	int ret;
 };
 
+static void venus_hfi_dump_packet(u8 *packet)
+{
+	u32 c = 0, packet_size = *(u32 *)packet;
+	const int row_size = 32;
+	/* row must contain enough for 0xdeadbaad * 8 to be converted into
+	 * "de ad ba ab " * 8 + '\0' */
+	char row[3 * row_size];
+
+	for (c = 0; c * row_size < packet_size; ++c) {
+		int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+			packet_size % row_size : row_size;
+		hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+				row_size, 4, row, sizeof(row), false);
+		dprintk(VIDC_PKT, "%s\n", row);
+	}
+}
+
 static void venus_hfi_sim_modify_cmd_packet(u8 *packet)
 {
 	struct hfi_cmd_sys_session_init_packet *sys_init;
@@ -171,8 +188,6 @@
 		return -EINVAL;
 	}
 
-	venus_hfi_sim_modify_cmd_packet(packet);
-
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
@@ -180,6 +195,13 @@
 		return -ENOENT;
 	}
 
+	venus_hfi_sim_modify_cmd_packet(packet);
+
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+		venus_hfi_dump_packet(packet);
+	}
+
 	packet_size_in_words = (*(u32 *)packet) >> 2;
 	dprintk(VIDC_DBG, "Packet_size in words: %d", packet_size_in_words);
 
@@ -359,6 +381,10 @@
 
 	*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
 	venus_hfi_hal_sim_modify_msg_packet(packet);
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+		venus_hfi_dump_packet(packet);
+	}
 	dprintk(VIDC_DBG, "Out : ");
 	return rc;
 }
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index caaba81..0388484 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -58,10 +58,11 @@
 #define PM8XXX_PWM_DISABLE		0x3F
 
 /* PM8XXX LPG PWM */
+#define SSBI_REG_ADDR_LPG_BANK_LOW_EN	0x130
 #define SSBI_REG_ADDR_LPG_CTL_BASE	0x13C
 #define SSBI_REG_ADDR_LPG_CTL(n)	(SSBI_REG_ADDR_LPG_CTL_BASE + (n))
 #define SSBI_REG_ADDR_LPG_BANK_SEL	0x143
-#define SSBI_REG_ADDR_LPG_BANK_EN	0x144
+#define SSBI_REG_ADDR_LPG_BANK_HIGH_EN	0x144
 #define SSBI_REG_ADDR_LPG_LUT_CFG0	0x145
 #define SSBI_REG_ADDR_LPG_LUT_CFG1	0x146
 #define SSBI_REG_ADDR_LPG_TEST		0x147
@@ -206,13 +207,15 @@
 	struct pm8xxx_pwm_chip	*chip;
 	int			bypass_lut;
 	int			dtest_mode_supported;
+	int			banks;
 };
 
 struct pm8xxx_pwm_chip {
 	struct pwm_device		*pwm_dev;
 	u8				pwm_channels;
 	u8				pwm_total_pre_divs;
-	u8				bank_mask;
+	u8				lo_bank_mask;
+	u8				hi_bank_mask;
 	struct mutex			pwm_mutex;
 	struct device			*dev;
 	bool				is_lpg_supported;
@@ -259,18 +262,37 @@
 
 	chip = pwm->chip;
 
-	if (enable)
-		reg = chip->bank_mask | (1 << pwm->pwm_id);
-	else
-		reg = chip->bank_mask & ~(1 << pwm->pwm_id);
+	if (pwm->banks & PM_PWM_BANK_LO) {
+		if (enable)
+			reg = chip->lo_bank_mask | (1 << pwm->pwm_id);
+		else
+			reg = chip->lo_bank_mask & ~(1 << pwm->pwm_id);
 
-	rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
-	if (rc) {
-		pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
-		return rc;
+		rc = pm8xxx_writeb(chip->dev->parent,
+				SSBI_REG_ADDR_LPG_BANK_LOW_EN, reg);
+		if (rc) {
+			pr_err("pm8xxx_writeb(): Enable Bank Low =%d\n", rc);
+			return rc;
+		}
+
+		chip->lo_bank_mask = reg;
 	}
-	chip->bank_mask = reg;
 
+	if (pwm->banks & PM_PWM_BANK_HI) {
+		if (enable)
+			reg = chip->hi_bank_mask | (1 << pwm->pwm_id);
+		else
+			reg = chip->hi_bank_mask & ~(1 << pwm->pwm_id);
+
+		rc = pm8xxx_writeb(chip->dev->parent,
+				SSBI_REG_ADDR_LPG_BANK_HIGH_EN, reg);
+		if (rc) {
+			pr_err("pm8xxx_writeb(): Enable Bank High =%d\n", rc);
+			return rc;
+		}
+
+		chip->hi_bank_mask = reg;
+	}
 	return 0;
 }
 
@@ -1010,6 +1032,16 @@
 	period = &pwm->period;
 	mutex_lock(&pwm->chip->pwm_mutex);
 
+	if (flags & PM_PWM_BANK_HI)
+		pwm->banks = PM_PWM_BANK_HI;
+
+	if (flags & PM_PWM_BANK_LO)
+		pwm->banks |= PM_PWM_BANK_LO;
+
+	/*Enable both banks if banks information is not shared.*/
+	if (!pwm->banks)
+		pwm->banks |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+
 	if (!pwm->in_use) {
 		pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
 		rc = -EINVAL;
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index be9058b..f000df7 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -47,27 +47,50 @@
 #define ECM_IPA_LOG_EXIT() pr_debug("end\n")
 
 /**
- * enum ecm_ipa_state - specify the current driver internal state.
+ * enum ecm_ipa_state - specify the current driver internal state
+ *  which is guarded by a state machine.
  *
- * The driver internal state changes due to its API usage.
+ * The driver internal state changes due to its external API usage.
  * The driver saves its internal state to guard from caller illegal
  * call sequence.
- * LOADED is the first state which is the default one.
+ * states:
+ * UNLOADED is the first state which is the default one and is also the state
+ *  after the driver gets unloaded(cleanup).
  * INITIALIZED is the driver state once it finished registering
- *  the network device
+ *  the network device and all internal data struct were initialized
  * CONNECTED is the driver state once the USB pipes were connected to IPA
- * UP is the driver state when it allows Linux network stack start
- *  data transfer
+ * UP is the driver state after the interface mode was set to UP but the
+ *  pipes are not connected yet - this state is meta-stable state.
+ * CONNECTED_AND_UP is the driver state when the pipe were connected and
+ *  the interface got UP request from the network stack. this is the driver
+ *   idle operation state which allows it to transmit/receive data.
+ * INVALID is a state which is not allowed.
  */
-enum ecm_ipa_mode {
-	ECM_IPA_LOADED,
+enum ecm_ipa_state {
+	ECM_IPA_UNLOADED = 0,
 	ECM_IPA_INITIALIZED,
 	ECM_IPA_CONNECTED,
 	ECM_IPA_UP,
+	ECM_IPA_CONNECTED_AND_UP,
+	ECM_IPA_INVALID,
 };
 
-#define ECM_IPA_MODE(ecm_ipa_ctx) \
-	pr_debug("Driver mode changed - %d", ecm_ipa_ctx->mode);
+/**
+ * enum ecm_ipa_operation - enumerations used to descibe the API operation
+ *
+ * Those enums are used as input for the driver state machine.
+ */
+enum ecm_ipa_operation {
+	ECM_IPA_INITIALIZE,
+	ECM_IPA_CONNECT,
+	ECM_IPA_OPEN,
+	ECM_IPA_STOP,
+	ECM_IPA_DISCONNECT,
+	ECM_IPA_CLEANUP,
+};
+
+#define ECM_IPA_STATE_DEBUG(ecm_ipa_ctx) \
+	pr_debug("Driver state - %s", ecm_ipa_state_string(ecm_ipa_ctx->state));
 
 /**
  * struct ecm_ipa_dev - main driver context parameters
@@ -85,7 +108,7 @@
  * @outstanding_high: number of outstanding packets allowed
  * @outstanding_low: number of outstanding packets which shall cause
  *  to netdev queue start (after stopped due to outstanding_high reached)
- * @mode: current mode of ecm_ipa driver
+ * @state: current state of ecm_ipa driver
  */
 struct ecm_ipa_dev {
 	struct net_device *net;
@@ -101,7 +124,7 @@
 	atomic_t outstanding_pkts;
 	u8 outstanding_high;
 	u8 outstanding_low;
-	enum ecm_ipa_mode mode;
+	enum ecm_ipa_state state;
 };
 
 static int ecm_ipa_open(struct net_device *net);
@@ -142,8 +165,9 @@
 static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
 static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
 		u8 device_ethaddr[]);
-static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
-		enum ecm_ipa_mode new_mode);
+static enum ecm_ipa_state ecm_ipa_next_state(enum ecm_ipa_state current_state,
+		enum ecm_ipa_operation operation);
+static const char *ecm_ipa_state_string(enum ecm_ipa_state state);
 static int ecm_ipa_init_module(void);
 static void ecm_ipa_cleanup_module(void);
 
@@ -270,8 +294,8 @@
 	params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
 	params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
 	params->private = (void *)ecm_ipa_ctx;
-	ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
-	ECM_IPA_MODE(ecm_ipa_ctx);
+	ecm_ipa_ctx->state = ECM_IPA_INITIALIZED;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 
@@ -314,16 +338,20 @@
 		void *priv)
 {
 	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+	int next_state;
 
 	ECM_IPA_LOG_ENTRY();
 	NULL_CHECK(priv);
 	pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
 					usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
 
-	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
-		ECM_IPA_ERROR("can't call connect before driver init\n");
+	next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_CONNECT);
+	if (next_state == ECM_IPA_INVALID) {
+		ECM_IPA_ERROR("can't call connect before calling initialize\n");
 		return -EPERM;
 	}
+	ecm_ipa_ctx->state = next_state;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
 	if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
 		ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
@@ -347,8 +375,10 @@
 	}
 	pr_debug("carrier_on notified, ecm_ipa is operational\n");
 
-	ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
-	ECM_IPA_MODE(ecm_ipa_ctx);
+	if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
+		netif_start_queue(ecm_ipa_ctx->net);
+		pr_debug("queue started\n");
+	}
 
 	ECM_IPA_LOG_EXIT();
 
@@ -368,24 +398,26 @@
 static int ecm_ipa_open(struct net_device *net)
 {
 	struct ecm_ipa_dev *ecm_ipa_ctx;
+	int next_state;
 
 	ECM_IPA_LOG_ENTRY();
 
 	ecm_ipa_ctx = netdev_priv(net);
 
-	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_UP)) {
-		ECM_IPA_ERROR("can't bring driver up before cable connect\n");
+	next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_OPEN);
+	if (next_state == ECM_IPA_INVALID) {
+		ECM_IPA_ERROR("can't bring driver up before initialize\n");
 		return -EPERM;
 	}
+	ecm_ipa_ctx->state = next_state;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
-	if (!netif_carrier_ok(net))
-		pr_debug("carrier is not ON yet - continuing\n");
-
-	netif_start_queue(net);
-	pr_debug("queue started\n");
-
-	ecm_ipa_ctx->mode = ECM_IPA_UP;
-	ECM_IPA_MODE(ecm_ipa_ctx);
+	if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
+		netif_start_queue(net);
+		pr_debug("queue started\n");
+	} else {
+		pr_debug("queue was not started due to meta-stabilie state\n");
+	}
 
 	ECM_IPA_LOG_EXIT();
 
@@ -424,8 +456,8 @@
 		goto out;
 	}
 
-	if (unlikely(ecm_ipa_ctx->mode != ECM_IPA_UP)) {
-		ECM_IPA_ERROR("can't send without network interface up\n");
+	if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
+		ECM_IPA_ERROR("Missing pipe connected and/or iface up\n");
 		return -NETDEV_TX_BUSY;
 	}
 
@@ -488,6 +520,11 @@
 	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 	int result;
 
+	if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
+		ECM_IPA_ERROR("Missing pipe connected and/or iface up\n");
+		return;
+	}
+
 	if (evt != IPA_RECEIVE)	{
 		ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
 		return;
@@ -522,20 +559,21 @@
 static int ecm_ipa_stop(struct net_device *net)
 {
 	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
+	int next_state;
 
 	ECM_IPA_LOG_ENTRY();
 
-	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
+	next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_STOP);
+	if (next_state == ECM_IPA_INVALID) {
 		ECM_IPA_ERROR("can't do network interface down without up\n");
 		return -EPERM;
 	}
+	ecm_ipa_ctx->state = next_state;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
 	netif_stop_queue(net);
 	pr_debug("network device stopped\n");
 
-	ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
-	ECM_IPA_MODE(ecm_ipa_ctx);
-
 	ECM_IPA_LOG_EXIT();
 	return 0;
 }
@@ -553,15 +591,19 @@
 int ecm_ipa_disconnect(void *priv)
 {
 	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+	int next_state;
 
 	ECM_IPA_LOG_ENTRY();
 	NULL_CHECK(ecm_ipa_ctx);
 	pr_debug("priv=0x%p\n", priv);
 
-	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_INITIALIZED)) {
-		ECM_IPA_ERROR("can't disconnect without connect first\n");
+	next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_DISCONNECT);
+	if (next_state == ECM_IPA_INVALID) {
+		ECM_IPA_ERROR("can't disconnect before connect\n");
 		return -EPERM;
 	}
+	ecm_ipa_ctx->state = next_state;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
 	netif_carrier_off(ecm_ipa_ctx->net);
 	pr_debug("carrier_off notifcation was sent\n");
@@ -569,9 +611,6 @@
 	netif_stop_queue(ecm_ipa_ctx->net);
 	pr_debug("queue stopped\n");
 
-	ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
-	ECM_IPA_MODE(ecm_ipa_ctx);
-
 	ECM_IPA_LOG_EXIT();
 
 	return 0;
@@ -598,6 +637,7 @@
 void ecm_ipa_cleanup(void *priv)
 {
 	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+	int next_state;
 
 	ECM_IPA_LOG_ENTRY();
 
@@ -608,9 +648,13 @@
 		return;
 	}
 
-	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_LOADED))
+	next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_CLEANUP);
+	if (next_state == ECM_IPA_INVALID) {
 		ECM_IPA_ERROR("can't clean driver without cable disconnect\n");
-
+		return;
+	}
+	ecm_ipa_ctx->state = next_state;
+	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
 	ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
 	ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
@@ -619,7 +663,6 @@
 	free_netdev(ecm_ipa_ctx->net);
 
 	pr_debug("cleanup done\n");
-	ecm_ipa_ctx = NULL;
 	ECM_IPA_LOG_EXIT();
 
 	return ;
@@ -1224,46 +1267,87 @@
 	return 0;
 }
 
-/** ecm_ipa_state_validate - check if a state transition is allowed
+/** ecm_ipa_next_state - return the next state of the driver
+ * @current_state: the current state of the driver
+ * @operation: an enum which represent the operation being made on the driver
+ *  by its API.
  *
- * Allowed transition:
- *  LOADED->INITIALIZED: ecm_ipa_init()
- *  INITIALIZED->CONNECTED: ecm_ipa_connect()
- *  CONNECTED->INITIALIZED: ecm_ipa_disconnect()
- *  CONNECTED->UP: ecm_ipa_open()
- *  UP->CONNECTED: ecm_ipa_stop()
- *  UP->INITIALIZED: ecm_ipa_disconnect()
- *  INITIALIZED-> LOADED
+ * This function implements the driver internal state machine.
+ * Its decisions are based on the driver current state and the operation
+ * being made.
+ * In case the operation is invalid this state machine will return
+ * the value ECM_IPA_INVALID to inform the caller for a forbidden sequence.
  */
-static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
-		enum ecm_ipa_mode new_mode)
+static enum ecm_ipa_state ecm_ipa_next_state(enum ecm_ipa_state current_state,
+		enum ecm_ipa_operation operation)
 {
-	bool result;
+	int next_state = ECM_IPA_INVALID;
 
-	switch (current_mode) {
-	case ECM_IPA_LOADED:
-		result = (new_mode == ECM_IPA_INITIALIZED);
+	switch (current_state) {
+	case ECM_IPA_UNLOADED:
+		if (operation == ECM_IPA_INITIALIZE)
+			next_state = ECM_IPA_INITIALIZED;
 		break;
 	case ECM_IPA_INITIALIZED:
-		result = (new_mode == ECM_IPA_CONNECTED ||
-				new_mode == ECM_IPA_LOADED);
+		if (operation == ECM_IPA_CONNECT)
+			next_state = ECM_IPA_CONNECTED;
+		else if (operation == ECM_IPA_OPEN)
+			next_state = ECM_IPA_UP;
+		else if (operation == ECM_IPA_CLEANUP)
+			next_state = ECM_IPA_UNLOADED;
 		break;
 	case ECM_IPA_CONNECTED:
-		result = (new_mode == ECM_IPA_INITIALIZED ||
-				new_mode == ECM_IPA_UP);
+		if (operation == ECM_IPA_DISCONNECT)
+			next_state = ECM_IPA_INITIALIZED;
+		else if (operation == ECM_IPA_OPEN)
+			next_state = ECM_IPA_CONNECTED_AND_UP;
 		break;
 	case ECM_IPA_UP:
-		result = (new_mode == ECM_IPA_CONNECTED ||
-				new_mode == ECM_IPA_INITIALIZED);
+		if (operation == ECM_IPA_STOP)
+			next_state = ECM_IPA_INITIALIZED;
+		else if (operation == ECM_IPA_CONNECT)
+			next_state = ECM_IPA_CONNECTED_AND_UP;
+		break;
+	case ECM_IPA_CONNECTED_AND_UP:
+		if (operation == ECM_IPA_STOP)
+			next_state = ECM_IPA_CONNECTED;
+		else if (operation == ECM_IPA_DISCONNECT)
+			next_state = ECM_IPA_UP;
 		break;
 	default:
-		result = false;
+		ECM_IPA_ERROR("State is not supported\n");
 		break;
 	}
 
-	pr_debug("state transition (%d->%d)- %s\n", current_mode,
-			new_mode , result ? "Allowed" : "Forbidden");
-	return result;
+	pr_debug("state transition ( %s -> %s )- %s\n",
+			ecm_ipa_state_string(current_state),
+			ecm_ipa_state_string(next_state) ,
+			next_state == ECM_IPA_INVALID ?
+					"Forbidden" : "Allowed");
+
+	return next_state;
+}
+
+/**
+ * ecm_ipa_state_string - return the state string representation
+ * @state: enum which describe the state
+ */
+static const char *ecm_ipa_state_string(enum ecm_ipa_state state)
+{
+	switch (state) {
+	case ECM_IPA_UNLOADED:
+		return "ECM_IPA_UNLOADED";
+	case ECM_IPA_INITIALIZED:
+		return "ECM_IPA_INITIALIZED";
+	case ECM_IPA_CONNECTED:
+		return "ECM_IPA_CONNECTED";
+	case ECM_IPA_UP:
+		return "ECM_IPA_UP";
+	case ECM_IPA_CONNECTED_AND_UP:
+		return "ECM_IPA_CONNECTED_AND_UP";
+	default:
+		return "Not supported";
+	}
 }
 
 /**
diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.c b/drivers/net/wireless/wcnss/wcnss_prealloc.c
index 7d10657..c450bcb 100644
--- a/drivers/net/wireless/wcnss/wcnss_prealloc.c
+++ b/drivers/net/wireless/wcnss/wcnss_prealloc.c
@@ -13,8 +13,9 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/wcnss_wlan.h>
+#include <linux/spinlock.h>
 
-static DEFINE_MUTEX(alloc_lock);
+static DEFINE_SPINLOCK(alloc_lock);
 
 struct wcnss_prealloc {
 	int occupied;
@@ -57,15 +58,18 @@
 {
 	int i = 0;
 
-	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++)
+	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
 		kfree(wcnss_allocs[i].ptr);
+		wcnss_allocs[i].ptr = NULL;
+	}
 }
 
 void *wcnss_prealloc_get(unsigned int size)
 {
 	int i = 0;
+	unsigned long flags;
 
-	mutex_lock(&alloc_lock);
+	spin_lock_irqsave(&alloc_lock, flags);
 	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
 		if (wcnss_allocs[i].occupied)
 			continue;
@@ -73,12 +77,13 @@
 		if (wcnss_allocs[i].size > size) {
 			/* we found the slot */
 			wcnss_allocs[i].occupied = 1;
-			mutex_unlock(&alloc_lock);
+			spin_unlock_irqrestore(&alloc_lock, flags);
 			return wcnss_allocs[i].ptr;
 		}
 	}
-	pr_err("wcnss: %s: prealloc not available\n", __func__);
-	mutex_unlock(&alloc_lock);
+	spin_unlock_irqrestore(&alloc_lock, flags);
+	pr_err("wcnss: %s: prealloc not available for size: %d\n",
+			__func__, size);
 
 	return NULL;
 }
@@ -87,16 +92,17 @@
 int wcnss_prealloc_put(void *ptr)
 {
 	int i = 0;
+	unsigned long flags;
 
-	mutex_lock(&alloc_lock);
+	spin_lock_irqsave(&alloc_lock, flags);
 	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
 		if (wcnss_allocs[i].ptr == ptr) {
 			wcnss_allocs[i].occupied = 0;
-			mutex_unlock(&alloc_lock);
+			spin_unlock_irqrestore(&alloc_lock, flags);
 			return 1;
 		}
 	}
-	mutex_unlock(&alloc_lock);
+	spin_unlock_irqrestore(&alloc_lock, flags);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index e8b8fc2..0b4f0fe 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -79,6 +79,15 @@
 #define CCU_RIVA_LAST_ADDR1_OFFSET		0x108
 #define CCU_RIVA_LAST_ADDR2_OFFSET		0x10c
 
+#define PRONTO_PMU_SPARE_OFFSET       0x1088
+
+#define PRONTO_PMU_GDSCR_OFFSET       0x0024
+#define PRONTO_PMU_GDSCR_SW_COLLAPSE  BIT(0)
+#define PRONTO_PMU_GDSCR_HW_CTRL      BIT(1)
+
+#define PRONTO_PMU_CBCR_OFFSET        0x0008
+#define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
+
 #define MSM_PRONTO_A2XB_BASE		0xfb100400
 #define A2XB_CFG_OFFSET				0x00
 #define A2XB_INT_SRC_OFFSET			0x0c
@@ -419,6 +428,28 @@
 	void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
 	u32 reg = 0;
 
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_GDSCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	reg >>= 31;
+
+	if (!reg) {
+		pr_info_ratelimited("%s:  Cannot log, Pronto common SS is power collapsed\n",
+				__func__);
+		return;
+	}
+	reg &= ~(PRONTO_PMU_GDSCR_SW_COLLAPSE | PRONTO_PMU_GDSCR_HW_CTRL);
+	writel_relaxed(reg, reg_addr);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	reg |= PRONTO_PMU_CBCR_CLK_EN;
+	writel_relaxed(reg, reg_addr);
+
 	reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
@@ -675,7 +706,7 @@
 static int __devinit
 wcnss_wlan_ctrl_probe(struct platform_device *pdev)
 {
-	if (!penv)
+	if (!penv || !penv->triggered)
 		return -ENODEV;
 
 	penv->smd_channel_ready = 1;
@@ -730,7 +761,7 @@
 {
 	int ret = 0;
 
-	if (!penv)
+	if (!penv || !penv->triggered)
 		return -ENODEV;
 
 	ret = smd_named_open_on_edge(WCNSS_CTRL_CHANNEL, SMD_APPS_WCNSS,
@@ -1573,15 +1604,6 @@
 		goto fail_power;
 	}
 
-	/* trigger initialization of the WCNSS */
-	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
-	if (IS_ERR(penv->pil)) {
-		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
-		ret = PTR_ERR(penv->pil);
-		penv->pil = NULL;
-		goto fail_pil;
-	}
-
 	/* allocate resources */
 	penv->mmio_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 							"wcnss_mmio");
@@ -1613,7 +1635,7 @@
 	if (!penv->msm_wcnss_base) {
 		ret = -ENOMEM;
 		pr_err("%s: ioremap wcnss physical failed\n", __func__);
-		goto fail_wake;
+		goto fail_ioremap;
 	}
 
 	if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
@@ -1621,20 +1643,20 @@
 		if (!penv->riva_ccu_base) {
 			ret = -ENOMEM;
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
-			goto fail_ioremap;
+			goto fail_ioremap2;
 		}
 	} else {
 		penv->pronto_a2xb_base =  ioremap(MSM_PRONTO_A2XB_BASE, SZ_512);
 		if (!penv->pronto_a2xb_base) {
 			ret = -ENOMEM;
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
-			goto fail_ioremap;
+			goto fail_ioremap2;
 		}
 		penv->pronto_ccpu_base =  ioremap(MSM_PRONTO_CCPU_BASE, SZ_512);
 		if (!penv->pronto_ccpu_base) {
 			ret = -ENOMEM;
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
-			goto fail_ioremap2;
+			goto fail_ioremap3;
 		}
 		/* for reset FIQ */
 		res = platform_get_resource_byname(penv->pdev,
@@ -1642,31 +1664,45 @@
 		if (!res) {
 			dev_err(&pdev->dev, "insufficient irq mem resources\n");
 			ret = -ENOENT;
-			goto fail_ioremap3;
+			goto fail_ioremap4;
 		}
 		penv->fiq_reg = ioremap_nocache(res->start, resource_size(res));
 		if (!penv->fiq_reg) {
 			pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n",
 				__func__, &res->start);
 			ret = -ENOMEM;
-			goto fail_ioremap3;
+			goto fail_ioremap4;
 		}
 	}
 
+	/* trigger initialization of the WCNSS */
+	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
+	if (IS_ERR(penv->pil)) {
+		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+		ret = PTR_ERR(penv->pil);
+		penv->pil = NULL;
+		goto fail_pil;
+	}
+
 	return 0;
 
+fail_pil:
+	if (penv->riva_ccu_base)
+		iounmap(penv->riva_ccu_base);
+	if (penv->fiq_reg)
+		iounmap(penv->fiq_reg);
+fail_ioremap4:
+	if (penv->pronto_ccpu_base)
+		iounmap(penv->pronto_ccpu_base);
 fail_ioremap3:
-	iounmap(penv->pronto_ccpu_base);
+	if (penv->pronto_a2xb_base)
+		iounmap(penv->pronto_a2xb_base);
 fail_ioremap2:
-	iounmap(penv->pronto_a2xb_base);
+	if (penv->msm_wcnss_base)
+		iounmap(penv->msm_wcnss_base);
 fail_ioremap:
-	iounmap(penv->msm_wcnss_base);
-fail_wake:
 	wake_lock_destroy(&penv->wcnss_wake_lock);
 fail_res:
-	if (penv->pil)
-		subsystem_put(penv->pil);
-fail_pil:
 	wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 				WCNSS_WLAN_SWITCH_OFF);
 fail_power:
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 67c86b9..f4ad172 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -197,6 +197,8 @@
 	if (_IOC_NR(cmd) >= IPA_IOCTL_MAX)
 		return -ENOTTY;
 
+	ipa_inc_client_enable_clks();
+
 	switch (cmd) {
 	case IPA_IOC_ALLOC_NAT_MEM:
 		if (copy_from_user((u8 *)&nat_mem, (u8 *)arg,
@@ -639,10 +641,13 @@
 						rm_depend.depends_on_name);
 		break;
 	default:        /* redundant, as cmd was checked against MAXNR */
+		ipa_dec_client_disable_clks();
 		return -ENOTTY;
 	}
 	kfree(param);
 
+	ipa_dec_client_disable_clks();
+
 	return retval;
 }
 
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index ac0b1d9..d378838 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -38,9 +38,11 @@
 #define QPNP_PON_KPDPWR_S1_TIMER(base)		(base + 0x40)
 #define QPNP_PON_KPDPWR_S2_TIMER(base)		(base + 0x41)
 #define QPNP_PON_KPDPWR_S2_CNTL(base)		(base + 0x42)
+#define QPNP_PON_KPDPWR_S2_CNTL2(base)		(base + 0x43)
 #define QPNP_PON_RESIN_S1_TIMER(base)		(base + 0x44)
 #define QPNP_PON_RESIN_S2_TIMER(base)		(base + 0x45)
 #define QPNP_PON_RESIN_S2_CNTL(base)		(base + 0x46)
+#define QPNP_PON_RESIN_S2_CNTL2(base)		(base + 0x47)
 #define QPNP_PON_PS_HOLD_RST_CTL(base)		(base + 0x5A)
 #define QPNP_PON_PS_HOLD_RST_CTL2(base)		(base + 0x5B)
 #define QPNP_PON_TRIGGER_EN(base)		(base + 0x80)
@@ -75,6 +77,7 @@
 #define PON_S1_COUNT_MAX			0xF
 
 #define QPNP_KEY_STATUS_DELAY			msecs_to_jiffies(250)
+#define QPNP_PON_REV_B				0x01
 
 enum pon_type {
 	PON_KPDPWR,
@@ -92,6 +95,8 @@
 	u32 pull_up;
 	u32 state_irq;
 	u32 bark_irq;
+	u16 s2_cntl_addr;
+	u16 s2_cntl2_addr;
 };
 
 struct qpnp_pon {
@@ -379,8 +384,14 @@
 	struct qpnp_pon *pon =
 		container_of(work, struct qpnp_pon, bark_work.work);
 
+	cfg = qpnp_get_cfg(pon, PON_RESIN);
+	if (!cfg) {
+		dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+		goto err_return;
+	}
+
 	/* enable reset */
-	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+	rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
 				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -397,19 +408,13 @@
 	}
 
 	if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
-		cfg = qpnp_get_cfg(pon, PON_RESIN);
-		if (!cfg) {
-			dev_err(&pon->spmi->dev, "Invalid config pointer\n");
-			goto err_return;
-		}
 		/* report the key event and enable the bark IRQ */
 		input_report_key(pon->pon_input, cfg->key_code, 0);
 		input_sync(pon->pon_input);
 		enable_irq(cfg->bark_irq);
 	} else {
 		/* disable reset */
-		rc = qpnp_pon_masked_write(pon,
-				QPNP_PON_RESIN_S2_CNTL(pon->base),
+		rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
 				QPNP_PON_S2_CNTL_EN, 0);
 		if (rc) {
 			dev_err(&pon->spmi->dev,
@@ -433,20 +438,20 @@
 	/* disable the bark interrupt */
 	disable_irq_nosync(irq);
 
-	/* disable reset */
-	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
-						QPNP_PON_S2_CNTL_EN, 0);
-	if (rc) {
-		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
-		goto err_exit;
-	}
-
 	cfg = qpnp_get_cfg(pon, PON_RESIN);
 	if (!cfg) {
 		dev_err(&pon->spmi->dev, "Invalid config pointer\n");
 		goto err_exit;
 	}
 
+	/* disable reset */
+	rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
+					QPNP_PON_S2_CNTL_EN, 0);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		goto err_exit;
+	}
+
 	/* report the key event */
 	input_report_key(pon->pon_input, cfg->key_code, 1);
 	input_sync(pon->pon_input);
@@ -489,24 +494,22 @@
 {
 	int rc;
 	u8 i;
-	u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+	u16 s1_timer_addr, s2_timer_addr;
 
 	switch (cfg->pon_type) {
 	case PON_KPDPWR:
 		s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
 		s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
-		s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
 		break;
 	case PON_RESIN:
 		s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
 		s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
-		s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
 		break;
 	default:
 		return -EINVAL;
 	}
 	/* disable S2 reset */
-	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+	rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
 				QPNP_PON_S2_CNTL_EN, 0);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -540,7 +543,7 @@
 		return rc;
 	}
 
-	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+	rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr,
 				QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
@@ -548,7 +551,7 @@
 	}
 
 	/* enable S2 reset */
-	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+	rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
 				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -660,6 +663,17 @@
 	int rc = 0, i = 0;
 	struct device_node *pp = NULL;
 	struct qpnp_pon_config *cfg;
+	u8 reg;
+
+	/* Check if it is rev B */
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+			QPNP_PON_REVISION2(pon->base), &reg, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev,
+			"Unable to read addr=%x, rc(%d)\n",
+			QPNP_PON_REVISION2(pon->base), rc);
+		return rc;
+	}
 
 	/* iterate through the list of pon configs */
 	while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
@@ -699,6 +713,17 @@
 					return cfg->bark_irq;
 				}
 			}
+
+			if (reg == QPNP_PON_REV_B) {
+				cfg->s2_cntl_addr =
+					QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+				cfg->s2_cntl2_addr =
+					QPNP_PON_KPDPWR_S2_CNTL2(pon->base);
+			} else {
+				cfg->s2_cntl_addr = cfg->s2_cntl2_addr =
+					QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+			}
+
 			break;
 		case PON_RESIN:
 			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
@@ -726,6 +751,17 @@
 					return cfg->bark_irq;
 				}
 			}
+
+			if (reg == QPNP_PON_REV_B) {
+				cfg->s2_cntl_addr =
+					QPNP_PON_RESIN_S2_CNTL(pon->base);
+				cfg->s2_cntl2_addr =
+					QPNP_PON_RESIN_S2_CNTL2(pon->base);
+			} else {
+				cfg->s2_cntl_addr = cfg->s2_cntl2_addr =
+					QPNP_PON_RESIN_S2_CNTL(pon->base);
+			}
+
 			break;
 		case PON_CBLPWR:
 			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index be62408..4e94b90 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -858,7 +858,7 @@
 	struct qpnp_lpg_chip	*chip = pwm->chip;
 	u8			value1, value2, mask1, mask2;
 	u8			*reg1, *reg2;
-	u16			addr;
+	u16			addr, addr1;
 	int			rc;
 
 	value1 = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
@@ -878,7 +878,7 @@
 			value2 = QPNP_DISABLE_LPG_MODE;
 		}
 		mask1 = QPNP_RAMP_START_MASK;
-		addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+		addr1 = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
 					QPNP_RAMP_CONTROL);
 		break;
 	case QPNP_LPG_REVISION_1:
@@ -889,8 +889,8 @@
 			QPNP_DISABLE_LUT_V1(value1, pwm->pwm_config.channel_id);
 			value2 = QPNP_DISABLE_LPG_MODE;
 		}
-		mask1 = BIT(pwm->pwm_config.channel_id);
-		addr = lpg_config->lut_base_addr +
+		mask1 = value1;
+		addr1 = lpg_config->lut_base_addr +
 			SPMI_LPG_REV1_RAMP_CONTROL_OFFSET;
 		break;
 	default:
@@ -898,15 +898,16 @@
 		return -EINVAL;
 	}
 
-	rc = qpnp_lpg_save_and_write(value1, mask1, reg1,
+	addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+				QPNP_ENABLE_CONTROL);
+
+	rc = qpnp_lpg_save_and_write(value2, mask2, reg2,
 					addr, 1, chip);
 	if (rc)
 		return rc;
-	addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
-				QPNP_ENABLE_CONTROL);
-	return qpnp_lpg_save_and_write(value2, mask2, reg2,
-					addr, 1, chip);
 
+	return qpnp_lpg_save_and_write(value1, mask1, reg1,
+					addr1, 1, chip);
 }
 
 #define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index f218a5a..897dc2a 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -52,17 +52,20 @@
 }
 
 #define PM8941_PERIPHERAL_SUBTYPE	0x01
+#define PM8226_PERIPHERAL_SUBTYPE	0x04
 static size_t build_pmic_string(char *buf, size_t n, int sid,
 		u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4)
 {
 	size_t pos = 0;
 	/*
-	 * In early versions of PM8941, the major revision number started
-	 * incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
+	 * In early versions of PM8941 and PM8226, the major revision number
+	 * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
 	 * Increment the major revision number here if the chip is an early
-	 * version of PM8941.
+	 * version of PM8941 or PM8226.
 	 */
-	if ((int)subtype == PM8941_PERIPHERAL_SUBTYPE && rev4 < 0x02)
+	if (((int)subtype == PM8941_PERIPHERAL_SUBTYPE
+			|| (int)subtype == PM8226_PERIPHERAL_SUBTYPE)
+			&& rev4 < 0x02)
 		rev4++;
 
 	pos += snprintf(buf + pos, n - pos, "PMIC@SID%d", sid);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 6b77609..c39de83 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -94,6 +94,7 @@
 	u8 pipes_enabled_per_bam[MAX_BAMS];
 	u32 inactivity_timer_ms[MAX_BAMS];
 	bool is_bam_inactivity[MAX_BAMS];
+	struct completion reset_done;
 };
 
 static char *bam_enable_strings[MAX_BAMS] = {
@@ -1554,6 +1555,10 @@
 	}
 
 	peer_handshake_info.client_ready = ready;
+	if (peer_handshake_info.state == USB_BAM_SM_PLUG_ACKED && !ready) {
+		pr_debug("Starting reset sequence");
+		INIT_COMPLETION(ctx.reset_done);
+	}
 
 	spin_unlock(&usb_bam_peer_handshake_info_lock);
 	if (!queue_work(ctx.usb_bam_wq,
@@ -1755,6 +1760,7 @@
 	case USB_BAM_SM_PLUG_ACKED:
 		if (!peer_handshake_info.client_ready) {
 			spin_unlock(&usb_bam_peer_handshake_info_lock);
+			pr_debug("Starting A2 reset sequence");
 			smsm_change_state(SMSM_APPS_STATE,
 				SMSM_USB_PLUG_UNPLUG, 0);
 			spin_lock(&usb_bam_peer_handshake_info_lock);
@@ -1767,6 +1773,8 @@
 			peer_handshake_info.reset_event.
 				callback(peer_handshake_info.reset_event.param);
 			spin_lock(&usb_bam_peer_handshake_info_lock);
+			complete_all(&ctx.reset_done);
+			pr_debug("Finished reset sequence");
 			peer_handshake_info.state = USB_BAM_SM_INIT;
 			peer_handshake_info.ack_received = 0;
 		}
@@ -2054,7 +2062,17 @@
 }
 EXPORT_SYMBOL(usb_bam_disconnect_ipa);
 
-int usb_bam_a2_reset(void)
+void usb_bam_reset_complete(void)
+{
+	pr_debug("Waiting for reset compelte");
+	if (wait_for_completion_interruptible_timeout(&ctx.reset_done,
+			10*HZ) <= 0)
+		pr_warn("Timeout while waiting for reset");
+
+	pr_debug("Finished Waiting for reset complete");
+}
+
+int usb_bam_a2_reset(bool to_reconnect)
 {
 	struct usb_bam_pipe_connect *pipe_connect;
 	int i;
@@ -2095,6 +2113,9 @@
 	if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
 		pr_err("%s: BAM reset failed\n", __func__);
 
+	if (!to_reconnect)
+		return ret;
+
 	/* Reconnect A2 pipes */
 	for (i = 0; i < ctx.max_connections; i++) {
 		pipe_connect = &usb_bam_connections[i];
@@ -2574,6 +2595,8 @@
 
 	spin_lock_init(&usb_bam_peer_handshake_info_lock);
 	INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+	init_completion(&ctx.reset_done);
+	complete(&ctx.reset_done);
 
 	ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
 		WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c
index 69fa4a8..6b6b110 100644
--- a/drivers/power/battery_current_limit.c
+++ b/drivers/power/battery_current_limit.c
@@ -31,6 +31,7 @@
  * Mininum BCL poll interval 10 msec
  */
 #define MIN_BCL_POLL_INTERVAL 10
+#define BATTERY_VOLTAGE_MIN 3400
 
 static const char bcl_type[] = "bcl";
 
@@ -43,20 +44,20 @@
 };
 
 /*
- * Battery Current Limit IBat Imax Threshold Mode
+ * Battery Current Limit Iavail Threshold Mode set
  */
-enum bcl_ibat_imax_threshold_mode {
-	BCL_IBAT_IMAX_THRESHOLD_DISABLED = 0,
-	BCL_IBAT_IMAX_THRESHOLD_ENABLED,
+enum bcl_iavail_threshold_mode {
+	BCL_IAVAIL_THRESHOLD_DISABLED = 0,
+	BCL_IAVAIL_THRESHOLD_ENABLED,
 };
 
 /*
- * Battery Current Limit Ibat Imax Trip Type (High and Low Threshold)
+ * Battery Current Limit Iavail Threshold Mode
  */
-enum bcl_ibat_imax_threshold_type {
-	BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW = 0,
-	BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH,
-	BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX,
+enum bcl_iavail_threshold_type {
+	BCL_IAVAIL_LOW_THRESHOLD_TYPE = 0,
+	BCL_IAVAIL_HIGH_THRESHOLD_TYPE,
+	BCL_IAVAIL_THRESHOLD_TYPE_MAX,
 };
 
 /**
@@ -70,118 +71,137 @@
 	/* BCL related config parameter */
 	/* BCL mode enable or not */
 	enum bcl_device_mode bcl_mode;
-	/* BCL Ibat/IMax Threshold Activate or Not */
-	enum bcl_ibat_imax_threshold_mode
-		bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
-	/* BCL Ibat/IMax Threshold value in milli Amp */
-	int bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
+	/* BCL Iavail Threshold Activate or Not */
+	enum bcl_iavail_threshold_mode
+		bcl_threshold_mode[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
+	/* BCL Iavail Threshold value in milli Amp */
+	int bcl_threshold_value_ma[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
 	/* BCL Type */
 	char bcl_type[BCL_NAME_LENGTH];
-	/* BCL poll in usec */
+	/* BCL poll in msec */
 	int bcl_poll_interval_msec;
 
 	/* BCL realtime value based on poll */
-	/* BCL realtime ibat in milli Amp*/
-	int bcl_ibat_ma;
-	/* BCL realtime calculated imax in milli Amp*/
-	int bcl_imax_ma;
-	/* BCL realtime calculated ocv in uV*/
-	int bcl_ocv_uv;
 	/* BCL realtime vbat in mV*/
 	int bcl_vbat_mv;
 	/* BCL realtime rbat in mOhms*/
-	int bcl_rbat;
+	int bcl_rbat_mohm;
+	/*BCL realtime iavail in milli Amp*/
+	int bcl_iavail;
+	/*BCL vbatt min in mV*/
+	int bcl_vbat_min;
 	/* BCL period poll delay work structure  */
-	struct delayed_work     bcl_imax_work;
+	struct delayed_work     bcl_iavail_work;
 
 };
 
 static struct bcl_context *gbcl;
 
-/*
- * BCL imax calculation and trigger notification to user space
- * if imax cross threshold
- */
-static void bcl_calculate_imax_trigger(void)
+static int bcl_get_battery_voltage(int *vbatt_mv)
 {
-	int ibatt_ua, vbatt_uv;
-	int imax_ma;
-	int ibatt_ma, vbatt_mv;
-	int imax_low_threshold;
-	int imax_high_threshold;
-	bool threshold_cross = false;
-	union power_supply_propval ret = {0,};
 	static struct power_supply *psy;
+	union power_supply_propval ret = {0,};
+
+	if (psy == NULL) {
+		psy = power_supply_get_by_name("battery");
+		if (psy  == NULL) {
+			pr_err("failed to get ps battery\n");
+			return -EINVAL;
+		}
+	}
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
+		return -EINVAL;
+
+	if (ret.intval <= 0)
+		return -EINVAL;
+
+	*vbatt_mv = ret.intval / 1000;
+	return 0;
+}
+
+
+static int bcl_get_resistance(int *rbatt_mohm)
+{
+	static struct power_supply *psy;
+	union power_supply_propval ret = {0,};
+
+	if (psy == NULL) {
+		psy = power_supply_get_by_name("bms");
+		if (psy == NULL) {
+			pr_err("failed to get ps bms\n");
+			return -EINVAL;
+		}
+	}
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_RESISTANCE, &ret))
+		return -EINVAL;
+
+	if (ret.intval <= 0)
+		return -EINVAL;
+
+	*rbatt_mohm = ret.intval / 1000;
+
+	return 0;
+}
+
+/*
+ * BCL iavail calculation and trigger notification to user space
+ * if iavail cross threshold
+ */
+static void bcl_calculate_iavail_trigger(void)
+{
+	int iavail_ma = 0;
+	int vbatt_mv;
+	int rbatt_mohm;
+	bool threshold_cross = false;
 
 	if (!gbcl) {
 		pr_err("called before initialization\n");
 		return;
 	}
 
-	if (psy == NULL) {
-		psy = power_supply_get_by_name("battery");
-		if (psy == NULL) {
-			pr_err("failed to get ps battery\n");
-			return;
-		}
-	}
-
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret))
+	if (bcl_get_battery_voltage(&vbatt_mv))
 		return;
-	ibatt_ua = ret.intval;
 
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
+	if (bcl_get_resistance(&rbatt_mohm))
 		return;
-	vbatt_uv = ret.intval;
 
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &ret))
-		return;
-	imax_ma = ret.intval/1000;
+	iavail_ma = (vbatt_mv - gbcl->bcl_vbat_min) * 1000 / rbatt_mohm;
 
-	ibatt_ma = ibatt_ua/1000;
-	vbatt_mv = vbatt_uv/1000;
-
-	gbcl->bcl_ibat_ma = ibatt_ma;
-	gbcl->bcl_imax_ma = imax_ma;
+	gbcl->bcl_rbat_mohm = rbatt_mohm;
 	gbcl->bcl_vbat_mv = vbatt_mv;
+	gbcl->bcl_iavail = iavail_ma;
 
-	pr_debug("ibatt %d, imax %d, vbatt %d\n", ibatt_ma, imax_ma, vbatt_mv);
-	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
-		imax_high_threshold =
-		imax_ma - gbcl->bcl_threshold_value_ma
-			[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH];
-		if (ibatt_ma >= imax_high_threshold)
-			threshold_cross = true;
-	}
+	pr_debug("iavail %d, vbatt %d rbatt %d\n", iavail_ma, vbatt_mv,
+			rbatt_mohm);
 
-	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
-		imax_low_threshold =
-		imax_ma - gbcl->bcl_threshold_value_ma
-			[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW];
-		if (ibatt_ma <= imax_low_threshold)
-			threshold_cross = true;
-	}
+	if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] ==
+				BCL_IAVAIL_THRESHOLD_ENABLED)
+		&& (iavail_ma >=
+		gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]))
+		threshold_cross = true;
+	else if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+				== BCL_IAVAIL_THRESHOLD_ENABLED)
+		&& (iavail_ma <=
+		gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]))
+		threshold_cross = true;
 
-	if (threshold_cross) {
-		sysfs_notify(&gbcl->dev->kobj,
-				NULL, "type");
-	}
+	if (threshold_cross)
+		sysfs_notify(&gbcl->dev->kobj, NULL, "type");
 }
 
 /*
- * BCL imax work
+ * BCL iavail work
  */
-static void bcl_imax_work(struct work_struct *work)
+static void bcl_iavail_work(struct work_struct *work)
 {
 	struct bcl_context *bcl = container_of(work,
-			struct bcl_context, bcl_imax_work.work);
+			struct bcl_context, bcl_iavail_work.work);
 
 	if (gbcl->bcl_mode == BCL_DEVICE_ENABLED) {
-		bcl_calculate_imax_trigger();
+		bcl_calculate_iavail_trigger();
 		/* restart the delay work for caculating imax */
-		schedule_delayed_work(&bcl->bcl_imax_work,
+		schedule_delayed_work(&bcl->bcl_iavail_work,
 			msecs_to_jiffies(bcl->bcl_poll_interval_msec));
 	}
 }
@@ -200,12 +220,12 @@
 	if (gbcl->bcl_mode == BCL_DEVICE_DISABLED
 		&& mode == BCL_DEVICE_ENABLED) {
 		gbcl->bcl_mode = mode;
-		bcl_imax_work(&(gbcl->bcl_imax_work.work));
+		bcl_iavail_work(&(gbcl->bcl_iavail_work.work));
 		return;
 	} else if (gbcl->bcl_mode == BCL_DEVICE_ENABLED
 		&& mode == BCL_DEVICE_DISABLED) {
 		gbcl->bcl_mode = mode;
-		cancel_delayed_work_sync(&(gbcl->bcl_imax_work));
+		cancel_delayed_work_sync(&(gbcl->bcl_iavail_work));
 		return;
 	}
 
@@ -223,11 +243,10 @@
 }
 
 show_bcl(type, bcl_type, "%s\n")
-show_bcl(ibat, bcl_ibat_ma, "%d\n")
-show_bcl(imax, bcl_imax_ma, "%d\n")
 show_bcl(vbat, bcl_vbat_mv, "%d\n")
-show_bcl(rbat, bcl_rbat, "%d\n")
-show_bcl(ocv, bcl_ocv_uv, "%d\n")
+show_bcl(rbat, bcl_rbat_mohm, "%d\n")
+show_bcl(iavail, bcl_iavail, "%d\n")
+show_bcl(vbat_min, bcl_vbat_min, "%d\n");
 show_bcl(poll_interval, bcl_poll_interval_msec, "%d\n")
 
 static ssize_t
@@ -259,136 +278,6 @@
 }
 
 static ssize_t
-ibat_imax_low_threshold_mode_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-		== BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
-}
-
-static ssize_t
-ibat_imax_low_threshold_mode_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	if (!strncmp(buf, "enabled", 7))
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-			= BCL_IBAT_IMAX_THRESHOLD_ENABLED;
-	else if (!strncmp(buf, "disabled", 8))
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-			= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
-	else
-		return -EINVAL;
-
-	return count;
-}
-
-static ssize_t
-ibat_imax_low_threshold_value_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]);
-}
-
-static ssize_t
-ibat_imax_low_threshold_value_store(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	int value;
-
-	if (!gbcl)
-		return -EPERM;
-
-	if (!sscanf(buf, "%d", &value))
-		return -EINVAL;
-
-	if (value < 0)
-		return -EINVAL;
-
-	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-			= value;
-
-	return count;
-}
-
-static ssize_t
-ibat_imax_high_threshold_mode_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		== BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
-}
-
-static ssize_t
-ibat_imax_high_threshold_mode_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	if (!strncmp(buf, "enabled", 7))
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		= BCL_IBAT_IMAX_THRESHOLD_ENABLED;
-	else if (!strncmp(buf, "disabled", 8))
-		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
-	else
-		return -EINVAL;
-
-	return count;
-}
-
-static ssize_t
-ibat_imax_high_threshold_value_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	if (!gbcl)
-		return -EPERM;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]);
-}
-
-static ssize_t
-ibat_imax_high_threshold_value_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	int value;
-
-	if (!gbcl)
-		return -EPERM;
-
-	if (!sscanf(buf, "%d", &value))
-		return -EINVAL;
-
-	if (value < 0)
-		return -EINVAL;
-
-	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		= value;
-
-	return count;
-}
-
-static ssize_t
 poll_interval_store(struct device *dev,
 			struct device_attribute *attr,
 			const char *buf, size_t count)
@@ -409,31 +298,168 @@
 	return count;
 }
 
+static ssize_t vbat_min_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	int value;
+	int ret;
+
+	if (!gbcl)
+		return -EPERM;
+
+	ret = kstrtoint(buf, 10, &value);
+
+	if (ret || (value < 0)) {
+		pr_err("Incorrect vbatt min value\n");
+		return -EINVAL;
+	}
+
+	gbcl->bcl_vbat_min = value;
+	return count;
+}
+
+static ssize_t iavail_low_threshold_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+		== BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t iavail_low_threshold_mode_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	if (!strncmp(buf, "enabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+			= BCL_IAVAIL_THRESHOLD_ENABLED;
+	else if (!strncmp(buf, "disabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+			= BCL_IAVAIL_THRESHOLD_DISABLED;
+	else
+		return -EINVAL;
+
+	return count;
+}
+static ssize_t iavail_high_threshold_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+		== BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t iavail_high_threshold_mode_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	if (!strncmp(buf, "enabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+			= BCL_IAVAIL_THRESHOLD_ENABLED;
+	else if (!strncmp(buf, "disabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+			= BCL_IAVAIL_THRESHOLD_DISABLED;
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t iavail_low_threshold_value_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]);
+}
+
+
+static ssize_t iavail_low_threshold_value_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int val;
+	int ret;
+
+	ret = kstrtoint(buf, 10, &val);
+
+	if (ret || (val < 0)) {
+		pr_err("Incorrect available current threshold value\n");
+		return -EINVAL;
+	}
+
+	gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = val;
+
+	return count;
+}
+static ssize_t iavail_high_threshold_value_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]);
+}
+
+static ssize_t iavail_high_threshold_value_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int val;
+	int ret;
+
+	ret = kstrtoint(buf, 10, &val);
+
+	if (ret || (val < 0)) {
+		pr_err("Incorrect available current threshold value\n");
+		return -EINVAL;
+	}
+
+	gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = val;
+
+	return count;
+}
+
 /*
  * BCL device attributes
  */
 static struct device_attribute bcl_dev_attr[] = {
 	__ATTR(type, 0444, type_show, NULL),
-	__ATTR(ibat, 0444, ibat_show, NULL),
+	__ATTR(iavail, 0444, iavail_show, NULL),
+	__ATTR(vbat_min, 0644, vbat_min_show, vbat_min_store),
 	__ATTR(vbat, 0444, vbat_show, NULL),
 	__ATTR(rbat, 0444, rbat_show, NULL),
-	__ATTR(ocv, 0444, ocv_show, NULL),
-	__ATTR(imax, 0444, imax_show, NULL),
 	__ATTR(mode, 0644, mode_show, mode_store),
 	__ATTR(poll_interval, 0644,
 		poll_interval_show, poll_interval_store),
-	__ATTR(ibat_imax_low_threshold_mode, 0644,
-		ibat_imax_low_threshold_mode_show,
-		ibat_imax_low_threshold_mode_store),
-	__ATTR(ibat_imax_high_threshold_mode, 0644,
-		ibat_imax_high_threshold_mode_show,
-		ibat_imax_high_threshold_mode_store),
-	__ATTR(ibat_imax_low_threshold_value, 0644,
-		ibat_imax_low_threshold_value_show,
-		ibat_imax_low_threshold_value_store),
-	__ATTR(ibat_imax_high_threshold_value, 0644,
-		ibat_imax_high_threshold_value_show,
-		ibat_imax_high_threshold_value_store)
+	__ATTR(iavail_low_threshold_mode, 0644,
+		iavail_low_threshold_mode_show,
+		iavail_low_threshold_mode_store),
+	__ATTR(iavail_high_threshold_mode, 0644,
+		iavail_high_threshold_mode_show,
+		iavail_high_threshold_mode_store),
+	__ATTR(iavail_low_threshold_value, 0644,
+		iavail_low_threshold_value_show,
+		iavail_low_threshold_value_store),
+	__ATTR(iavail_high_threshold_value, 0644,
+		iavail_high_threshold_value_show,
+		iavail_high_threshold_value_store),
 };
 
 static int create_bcl_sysfs(struct bcl_context *bcl)
@@ -480,12 +506,13 @@
 	/* Init default BCL params */
 	bcl->dev = &pdev->dev;
 	bcl->bcl_mode = BCL_DEVICE_DISABLED;
-	bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
-		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
-	bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
-		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
-	bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW] = 0;
-	bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH] = 0;
+	bcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE] =
+					BCL_IAVAIL_THRESHOLD_DISABLED;
+	bcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] =
+					BCL_IAVAIL_THRESHOLD_DISABLED;
+	bcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = 0;
+	bcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = 0;
+	bcl->bcl_vbat_min = BATTERY_VOLTAGE_MIN;
 	snprintf(bcl->bcl_type, BCL_NAME_LENGTH, "%s", bcl_type);
 	bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;
 	ret = create_bcl_sysfs(bcl);
@@ -495,7 +522,7 @@
 		return ret;
 	}
 	platform_set_drvdata(pdev, bcl);
-	INIT_DELAYED_WORK(&bcl->bcl_imax_work, bcl_imax_work);
+	INIT_DELAYED_WORK_DEFERRABLE(&bcl->bcl_iavail_work, bcl_iavail_work);
 
 	return 0;
 }
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 28dd539..d9a216d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -74,8 +74,13 @@
 /* Extra bms registers */
 #define SOC_STORAGE_REG			0xB0
 #define IAVG_STORAGE_REG		0xB1
-#define BMS1_BMS_DATA_REG_2		0xB2
+#define BMS_BATT_REMOVED_REG		0xB2
 #define BMS1_BMS_DATA_REG_3		0xB3
+#define CHARGE_INCREASE_STORAGE		0xB4
+#define FCC_BATT_TEMP_STORAGE		0xB5
+#define FCC_STORAGE_LSB			0xBC /* LSB=0xBC, MSB=0xBD */
+#define CHARGE_CYCLE_STORAGE_LSB	0xBE /* LSB=0xBE, MSB=0xBF */
+
 /* IADC Channel Select */
 #define IADC1_BMS_ADC_CH_SEL_CTL	0x48
 
@@ -88,6 +93,10 @@
 
 #define IAVG_SAMPLES 16
 
+/* FCC learning constants */
+#define DELTA_FCC_PERCENT                       5
+#define VALID_FCC_CHGCYL_RANGE                  50
+
 #define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
 
 struct soc_params {
@@ -106,6 +115,12 @@
 	int		last_good_ocv_uv;
 };
 
+struct fcc_data {
+	int fcc_new;
+	int batt_temp;
+	int chargecycles;
+};
+
 struct qpnp_bms_chip {
 	struct device			*dev;
 	struct power_supply		bms_psy;
@@ -215,6 +230,23 @@
 	int				ocv_high_threshold_uv;
 	int				ocv_low_threshold_uv;
 	unsigned long			last_recalc_time;
+
+	struct fcc_data			*fcc_table;
+	int				enable_fcc_learning;
+	int				min_fcc_learning_soc;
+	int				min_fcc_ocv_pc;
+	int				min_fcc_learning_samples;
+	int				start_soc;
+	int				end_soc;
+	int				start_pc;
+	int				start_cc_uah;
+	int				start_real_soc;
+	int				end_cc_uah;
+	uint16_t			fcc_new_mah;
+	int				fcc_new_batt_temp;
+	uint16_t			charge_cycles;
+	u8				charge_increase;
+	int				fcc_new_sysfs;
 };
 
 static struct of_device_id qpnp_bms_match_table[] = {
@@ -232,9 +264,26 @@
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CYCLE_COUNT,
 };
 
 static bool bms_reset;
+static int min_fcc_cycles = -EINVAL;
+static int last_fcc_update_count;
+static int battery_removed;
+
+static int
+bms_ro_ops_set(const char *val, const struct kernel_param *kp)
+{
+	return -EINVAL;
+}
+static struct kernel_param_ops bms_ro_param_ops = {
+	.set = bms_ro_ops_set,
+	.get = param_get_int,
+};
+module_param_cb(min_fcc_cycles, &bms_ro_param_ops, &min_fcc_cycles, 0644);
+module_param_cb(battery_removed, &bms_ro_param_ops, &battery_removed, 0644);
+module_param(last_fcc_update_count, int, 0644);
 
 static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
 			u16 base, int count)
@@ -2262,14 +2311,275 @@
 	return 0;
 }
 
+static void readjust_fcc_table(struct qpnp_bms_chip *chip)
+{
+	struct single_row_lut *temp, *old;
+	int i, fcc, ratio;
+
+	if (!chip->enable_fcc_learning)
+		return;
+
+	if (!chip->fcc_temp_lut) {
+		pr_err("The static fcc lut table is NULL\n");
+		return;
+	}
+
+	temp = kzalloc(sizeof(struct single_row_lut), GFP_KERNEL);
+	if (!temp) {
+		pr_err("Cannot allocate memory for adjusted fcc table\n");
+		return;
+	}
+
+	fcc = interpolate_fcc(chip->fcc_temp_lut, chip->fcc_new_batt_temp);
+
+	temp->cols = chip->fcc_temp_lut->cols;
+	for (i = 0; i < chip->fcc_temp_lut->cols; i++) {
+		temp->x[i] = chip->fcc_temp_lut->x[i];
+		ratio = div_u64(chip->fcc_temp_lut->y[i] * 1000, fcc);
+		temp->y[i] =  (ratio * chip->fcc_new_mah);
+		temp->y[i] /= 1000;
+	}
+
+	old = chip->adjusted_fcc_temp_lut;
+	chip->adjusted_fcc_temp_lut = temp;
+	kfree(old);
+}
+
+
+static void backup_fcc_new(struct qpnp_bms_chip *chip)
+{
+	int rc = 0;
+	u8 temp = 0;
+
+	if (chip->fcc_new_mah > 0) {
+		rc = qpnp_write_wrapper(chip, (u8 *)&chip->fcc_new_mah,
+					chip->base + FCC_STORAGE_LSB, 2);
+		if (rc)
+			pr_err("Unable to backup new_fcc\n");
+
+		temp = chip->fcc_new_batt_temp / 10;
+		rc = qpnp_write_wrapper(chip, &temp,
+				chip->base + FCC_BATT_TEMP_STORAGE, 1);
+		if (rc)
+			pr_err("Unable to backup fcc temp.\n");
+	}
+}
+
+
+static void backup_charge_cycle(struct qpnp_bms_chip *chip)
+{
+	int rc = 0;
+
+	if (chip->charge_increase >= 0) {
+		rc = qpnp_write_wrapper(chip, &chip->charge_increase,
+				chip->base + CHARGE_INCREASE_STORAGE, 1);
+		if (rc)
+			pr_err("Unable to backup charge_increase\n");
+	}
+
+	if (chip->charge_cycles >= 0) {
+		rc = qpnp_write_wrapper(chip, (u8 *)&chip->charge_cycles,
+				chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
+		if (rc)
+			pr_err("Unable to backup charge_cycles\n");
+	}
+}
+
+static void restore_fcc_data(struct qpnp_bms_chip *chip)
+{
+	int rc = 0;
+	uint16_t temp_u16 = 0;
+	u8 temp_u8 = 0;
+
+	rc = qpnp_read_wrapper(chip, &temp_u8,
+				chip->base + CHARGE_INCREASE_STORAGE, 1);
+	if (!rc && temp_u8 != 0xFF)
+		chip->charge_increase = temp_u8;
+
+	rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
+				chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
+	if (!rc && temp_u16 != 0xFFFF)
+		chip->charge_cycles = temp_u16;
+
+	rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
+				chip->base + FCC_STORAGE_LSB, 2);
+	if (!rc && temp_u16 != 0xFFFF) {
+		chip->fcc_new_mah = temp_u16;
+	} else {
+		pr_debug("Backed-up FCC not initialized, FCC not updated\n");
+		return;
+	}
+
+	rc = qpnp_read_wrapper(chip, &temp_u8,
+				chip->base + FCC_BATT_TEMP_STORAGE, 1);
+	if (!rc && temp_u8 != 0xFF) {
+		chip->fcc_new_batt_temp = (s8)temp_u8 * 10;
+	} else {
+		pr_debug("Backed-up temp. not initialized, FCC not updated\n");
+		return;
+	}
+	/* readjust the FCC table if fcc and temp are valid */
+	readjust_fcc_table(chip);
+}
+
+static int calculate_real_soc(struct qpnp_bms_chip *chip,
+		int batt_temp, struct raw_soc_params *raw, int cc_uah)
+{
+	int fcc_uah, rc_uah;
+
+	fcc_uah = calculate_fcc(chip, batt_temp);
+	rc_uah = calculate_ocv_charge(chip, raw, fcc_uah);
+
+	return ((rc_uah - cc_uah) * 100) / fcc_uah;
+}
+
+static void update_fcc_table_for_temp(struct qpnp_bms_chip *chip,
+						int batt_temp_final)
+{
+	int i, fcc_t1, fcc_t2, fcc_final;
+	struct fcc_data *ft;
+
+	/* Interpolate all the FCC entries to the same temperature */
+	for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+		ft = &chip->fcc_table[i];
+		if (ft->batt_temp == batt_temp_final)
+			continue;
+		fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
+		fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
+		fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
+		ft->fcc_new = fcc_final;
+		ft->batt_temp = batt_temp_final;
+	}
+}
+
+static void update_fcc_learning_table(struct qpnp_bms_chip *chip,
+		int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+{
+	int i, count, new_fcc_avg = 0, temp_fcc_avg = 0, temp_fcc_delta = 0;
+	struct fcc_data *ft;
+
+	count = last_fcc_update_count % chip->min_fcc_learning_samples;
+	ft = &chip->fcc_table[count];
+	ft->fcc_new = chip->fcc_new_sysfs = new_fcc_uah;
+	ft->batt_temp = batt_temp;
+	ft->chargecycles = chargecycles;
+	last_fcc_update_count++;
+	/* update userspace */
+	sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+
+	pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
+		new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
+
+	if (last_fcc_update_count < chip->min_fcc_learning_samples) {
+		pr_debug("Not enough FCC samples. Current count = %d\n",
+						last_fcc_update_count);
+		return; /* Not enough samples to update fcc */
+	}
+
+	/* reject entries if they are > 50 chargecycles apart */
+	for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+		if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
+							< chargecycles) {
+			pr_debug("Charge cycle too old (> %d cycles apart)\n",
+							VALID_FCC_CHGCYL_RANGE);
+			return; /* Samples old, > 50 cycles apart*/
+		}
+	}
+	/* update the fcc table for temperature difference*/
+	update_fcc_table_for_temp(chip, batt_temp);
+
+	for (i = 0; i < chip->min_fcc_learning_samples; i++)
+		temp_fcc_avg += chip->fcc_table[i].fcc_new;
+
+	temp_fcc_avg /= chip->min_fcc_learning_samples;
+	temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+	/* fix the fcc if its an outlier i.e. > 5% of the average */
+	for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+		ft = &chip->fcc_table[i];
+		if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+			ft->fcc_new = temp_fcc_avg;
+		new_fcc_avg += ft->fcc_new;
+	}
+	new_fcc_avg /= chip->min_fcc_learning_samples;
+
+	chip->fcc_new_mah = new_fcc_avg / 1000;
+	chip->fcc_new_batt_temp = batt_temp;
+	pr_info("FCC update: New fcc_mah=%d, fcc_batt_temp=%d\n",
+					new_fcc_avg, batt_temp);
+	readjust_fcc_table(chip);
+	backup_fcc_new(chip);
+}
+
+static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
+{
+	if ((new_fcc_uah >= (fcc_uah / 2)) &&
+		((new_fcc_uah * 100) <= (fcc_uah * 105)))
+		return true;
+
+	pr_debug("FCC rejected - not within valid limit\n");
+	return false;
+}
+
+static void fcc_learning_config(struct qpnp_bms_chip *chip, bool start)
+{
+	int rc, batt_temp;
+	struct raw_soc_params raw;
+	struct qpnp_vadc_result result;
+	int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
+
+	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+	if (rc) {
+		pr_err("Unable to read batt_temp\n");
+		return;
+	} else {
+		batt_temp = (int)result.physical;
+	}
+
+	rc = read_soc_params_raw(chip, &raw, batt_temp);
+	if (rc) {
+		pr_err("Unable to read CC, cannot update FCC\n");
+		return;
+	}
+
+	if (start) {
+		chip->start_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+			batt_temp / 10, raw.last_good_ocv_uv / 1000);
+		chip->start_cc_uah = calculate_cc(chip, raw.cc, false);
+		chip->start_real_soc = calculate_real_soc(chip,
+				batt_temp, &raw, chip->start_cc_uah);
+		pr_debug("start_pc=%d, start_cc=%d, start_soc=%d real_soc=%d\n",
+			chip->start_pc, chip->start_cc_uah,
+			chip->start_soc, chip->start_real_soc);
+	} else {
+		chip->end_cc_uah = calculate_cc(chip, raw.cc, false);
+		delta_soc = 100 - chip->start_real_soc;
+		delta_cc_uah = abs(chip->end_cc_uah - chip->start_cc_uah);
+		new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
+		fcc_uah = calculate_fcc(chip, batt_temp);
+		pr_debug("start_soc=%d, start_pc=%d, start_real_soc=%d, start_cc=%d, end_cc=%d, new_fcc=%d\n",
+			chip->start_soc, chip->start_pc, chip->start_real_soc,
+			chip->start_cc_uah, chip->end_cc_uah, new_fcc_uah);
+
+		if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
+			update_fcc_learning_table(chip, fcc_uah,
+				new_fcc_uah, chip->charge_cycles, batt_temp);
+	}
+}
+
 static void charging_began(struct qpnp_bms_chip *chip)
 {
+
 	mutex_lock(&chip->last_soc_mutex);
 	chip->charge_start_tm_sec = 0;
 	chip->catch_up_time_sec = 0;
 	mutex_unlock(&chip->last_soc_mutex);
 
+	chip->start_soc = report_state_of_charge(chip);
+
 	mutex_lock(&chip->last_ocv_uv_mutex);
+	if (chip->enable_fcc_learning)
+		fcc_learning_config(chip, true);
 	chip->soc_at_cv = -EINVAL;
 	chip->prev_chg_soc = -EINVAL;
 	mutex_unlock(&chip->last_ocv_uv_mutex);
@@ -2282,10 +2592,28 @@
 	chip->catch_up_time_sec = 0;
 	mutex_unlock(&chip->last_soc_mutex);
 
+	chip->end_soc = report_state_of_charge(chip);
+
 	mutex_lock(&chip->last_ocv_uv_mutex);
 	chip->soc_at_cv = -EINVAL;
 	chip->prev_chg_soc = -EINVAL;
+
+	/* update the chargecycles */
+	if (chip->end_soc > chip->start_soc) {
+		chip->charge_increase += (chip->end_soc - chip->start_soc);
+		if (chip->charge_increase > 100) {
+			chip->charge_cycles++;
+			chip->charge_increase = chip->charge_increase % 100;
+		}
+		if (chip->enable_fcc_learning)
+			backup_charge_cycle(chip);
+	}
+
 	if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
+		if (chip->enable_fcc_learning &&
+			(chip->start_soc <= chip->min_fcc_learning_soc) &&
+			(chip->start_pc <= chip->min_fcc_ocv_pc))
+			fcc_learning_config(chip, false);
 		chip->done_charging = true;
 		chip->last_soc_invalid = true;
 	} else if (chip->charging_adjusted_ocv > 0) {
@@ -2293,6 +2621,7 @@
 				chip->charging_adjusted_ocv);
 		chip->last_ocv_uv = chip->charging_adjusted_ocv;
 	}
+
 	chip->charging_adjusted_ocv = -EINVAL;
 
 	mutex_unlock(&chip->last_ocv_uv_mutex);
@@ -2417,12 +2746,120 @@
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
+	case POWER_SUPPLY_PROP_CYCLE_COUNT:
+		val->intval = chip->charge_cycles;
+		break;
 	default:
 		return -EINVAL;
 	}
 	return 0;
 }
 
+static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+	static int i;
+	int fcc_new = 0, rc;
+
+	i %= chip->min_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &fcc_new);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].fcc_new = fcc_new;
+	pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	int count = 0;
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+	count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new_sysfs);
+	pr_debug("Sent: fcc_new=%d\n", chip->fcc_new_sysfs);
+
+	return count;
+}
+
+static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	static int i;
+	int batt_temp = 0, rc;
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+	i %= chip->min_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &batt_temp);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].batt_temp = batt_temp;
+	pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	static int i;
+	int chargecycle = 0, rc;
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+	i %= chip->min_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &chargecycle);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].chargecycles = chargecycle;
+	pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+	struct fcc_data *ft;
+	int i = 0, j, count = 0;
+
+	if (last_fcc_update_count < chip->min_fcc_learning_samples)
+		i = last_fcc_update_count;
+	else
+		i = chip->min_fcc_learning_samples;
+
+	for (j = 0; j < i; j++) {
+		ft = &chip->fcc_table[j];
+		count += snprintf(buf + count, PAGE_SIZE - count,
+			"%d %d %d\n", ft->fcc_new, ft->chargecycles,
+			ft->batt_temp);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
+static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
+static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
+static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
+
+static struct attribute *fcc_attrs[] = {
+	&dev_attr_fcc_data.attr,
+	&dev_attr_fcc_temp.attr,
+	&dev_attr_fcc_chgcyl.attr,
+	&dev_attr_fcc_list.attr,
+	NULL
+};
+
+static const struct attribute_group fcc_attr_group = {
+	.attrs = fcc_attrs,
+};
+
 #define OCV_USE_LIMIT_EN		BIT(7)
 static int set_ocv_voltage_thresholds(struct qpnp_bms_chip *chip,
 					int low_voltage_threshold,
@@ -2546,6 +2983,8 @@
 		batt_data = &oem_batt_data;
 	} else if (chip->batt_type == BATT_QRD_4V35_2000MAH) {
 		batt_data = &QRD_4v35_2000mAh_data;
+	} else if (chip->batt_type == BATT_QRD_4V2_1300MAH) {
+		batt_data = &qrd_4v2_1300mah_data;
 	} else {
 		battery_id = read_battery_id(chip);
 		if (battery_id < 0) {
@@ -2642,6 +3081,23 @@
 	if (chip->adjust_soc_low_threshold >= 45)
 		chip->adjust_soc_low_threshold = 45;
 
+	chip->enable_fcc_learning = of_property_read_bool(
+		chip->spmi->dev.of_node, "qcom,enable-fcc-learning");
+	if (chip->enable_fcc_learning) {
+		SPMI_PROP_READ(min_fcc_learning_soc,
+				"min-fcc-learning-soc", rc);
+		SPMI_PROP_READ(min_fcc_ocv_pc,
+				"min-fcc-ocv-pc", rc);
+		SPMI_PROP_READ(min_fcc_learning_samples,
+				"min-fcc-learning-samples", rc);
+		chip->fcc_table = kzalloc((sizeof(struct fcc_data) *
+			chip->min_fcc_learning_samples), GFP_KERNEL);
+		pr_debug("min-fcc-soc=%d, min-fcc-pc=%d, min-fcc-cycles=%d\n",
+			chip->min_fcc_learning_soc, chip->min_fcc_ocv_pc,
+			chip->min_fcc_learning_samples);
+		min_fcc_cycles = chip->min_fcc_learning_samples;
+	}
+
 	pr_debug("dts data: r_sense_uohm:%d, v_cutoff_uv:%d, max_v:%d\n",
 			chip->r_sense_uohm, chip->v_cutoff_uv,
 			chip->max_voltage_uv);
@@ -2870,6 +3326,28 @@
 	return 0;
 }
 
+static void check_battery_removal(struct qpnp_bms_chip *chip)
+{
+	int rc;
+	u8 temp = 0;
+
+	/* check if battery was removed at PON */
+	rc = qpnp_read_wrapper(chip, &temp,
+				chip->base + BMS_BATT_REMOVED_REG, 1);
+	if (temp == 0xFF) {
+		pr_debug("New battery inserted at PON\n");
+		temp = battery_removed = 1;
+		rc = qpnp_write_wrapper(chip, &temp,
+				chip->base + BMS_BATT_REMOVED_REG, 1);
+		if (rc)
+			pr_err("Unable to set BMS_BATT_REMOVED_REG\n");
+	} else {
+		if (rc)
+			pr_err("Unable to read BMS_BATT_REMOVED_REG\n");
+		battery_removed = 0;
+	}
+}
+
 static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
 {
 	struct qpnp_bms_chip *chip;
@@ -2972,9 +3450,21 @@
 
 	read_shutdown_soc_and_iavg(chip);
 
+	if (chip->enable_fcc_learning) {
+		restore_fcc_data(chip);
+		rc = sysfs_create_group(&spmi->dev.kobj, &fcc_attr_group);
+		if (rc) {
+			pr_err("Unable to create sysfs entries\n");
+			goto error_setup;
+		}
+	}
+
 	dev_set_drvdata(&spmi->dev, chip);
 	device_init_wakeup(&spmi->dev, 1);
 
+	check_battery_removal(chip);
+
+
 	rc = setup_vbat_monitoring(chip);
 	if (rc < 0) {
 		pr_err("failed to set up voltage notifications: %d\n", rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f051af2..439a8ae 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1053,6 +1053,7 @@
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
+	POWER_SUPPLY_PROP_CYCLE_COUNT,
 };
 
 static char *pm_power_supplied_to[] = {
@@ -1282,6 +1283,16 @@
 	return DEFAULT_TEMP;
 }
 
+static int get_prop_cycle_count(struct qpnp_chg_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+
+	if (chip->bms_psy)
+		chip->bms_psy->get_property(chip->bms_psy,
+			  POWER_SUPPLY_PROP_CYCLE_COUNT, &ret);
+	return ret.intval;
+}
+
 static void
 qpnp_batt_external_power_changed(struct power_supply *psy)
 {
@@ -1364,6 +1375,9 @@
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 		val->intval = chip->therm_lvl_sel;
 		break;
+	case POWER_SUPPLY_PROP_CYCLE_COUNT:
+		val->intval = get_prop_cycle_count(chip);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -2345,7 +2359,7 @@
 			return rc;
 
 		rc = qpnp_chg_masked_write(chip,
-			chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
+			chip->buck_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
 			BUCK_VBAT_REG_NODE_SEL_BIT,
 			BUCK_VBAT_REG_NODE_SEL_BIT, 1);
 		if (rc) {
@@ -2675,6 +2689,39 @@
 	if (rc)
 		goto fail_chg_enable;
 
+	/* Check if bat_if is set in DT and make sure VADC is present */
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			pr_err("qpnp_chg: spmi resource absent\n");
+			rc = -ENXIO;
+			goto fail_chg_enable;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+						IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			pr_err("node %s IO resource absent!\n",
+				spmi->dev.of_node->full_name);
+			rc = -ENXIO;
+			goto fail_chg_enable;
+		}
+
+		rc = qpnp_chg_read(chip, &subtype,
+				resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+		if (rc) {
+			pr_err("Peripheral subtype read failed rc=%d\n", rc);
+			goto fail_chg_enable;
+		}
+
+		if (subtype == SMBB_BAT_IF_SUBTYPE ||
+			subtype == SMBBP_BAT_IF_SUBTYPE ||
+			subtype == SMBCL_BAT_IF_SUBTYPE){
+			rc = qpnp_vadc_is_ready();
+			if (rc)
+				goto fail_chg_enable;
+		}
+	}
+
 	spmi_for_each_container_dev(spmi_resource, spmi) {
 		if (!spmi_resource) {
 			pr_err("qpnp_chg: spmi resource absent\n");
@@ -2806,10 +2853,6 @@
 	device_init_wakeup(&spmi->dev, 1);
 
 	if (chip->bat_if_base) {
-		rc = qpnp_vadc_is_ready();
-		if (rc)
-			goto fail_chg_enable;
-
 		chip->batt_psy.name = "battery";
 		chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 		chip->batt_psy.properties = msm_batt_power_props;
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 1a4c3f3..e91e5d6 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -43,6 +43,8 @@
 #include <mach/msm_spi.h>
 #include <mach/sps.h>
 #include <mach/dma.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 #include "spi_qsd.h"
 
 static int msm_spi_pm_resume_runtime(struct device *device);
@@ -200,6 +202,177 @@
 		dd->clock_speed = rate;
 }
 
+static void msm_spi_clk_path_vote(struct msm_spi *dd)
+{
+	if (dd->clk_path_vote.client_hdl)
+		msm_bus_scale_client_update_request(
+						dd->clk_path_vote.client_hdl,
+						MSM_SPI_CLK_PATH_RESUME_VEC);
+}
+
+static void msm_spi_clk_path_unvote(struct msm_spi *dd)
+{
+	if (dd->clk_path_vote.client_hdl)
+		msm_bus_scale_client_update_request(
+						dd->clk_path_vote.client_hdl,
+						MSM_SPI_CLK_PATH_SUSPEND_VEC);
+}
+
+static void msm_spi_clk_path_teardown(struct msm_spi *dd)
+{
+	if (dd->pdata->active_only)
+		msm_spi_clk_path_unvote(dd);
+
+	if (dd->clk_path_vote.client_hdl) {
+		msm_bus_scale_unregister_client(dd->clk_path_vote.client_hdl);
+		dd->clk_path_vote.client_hdl = 0;
+	}
+}
+
+/**
+ * msm_spi_clk_path_init_structs: internal impl detail of msm_spi_clk_path_init
+ *
+ * allocates and initilizes the bus scaling vectors.
+ */
+static int msm_spi_clk_path_init_structs(struct msm_spi *dd)
+{
+	struct msm_bus_vectors *paths    = NULL;
+	struct msm_bus_paths   *usecases = NULL;
+
+	dev_dbg(dd->dev, "initialises path clock voting structs");
+
+	paths = devm_kzalloc(dd->dev, sizeof(*paths) * 2, GFP_KERNEL);
+	if (!paths) {
+		dev_err(dd->dev,
+		"msm_bus_paths.paths memory allocation failed");
+		return -ENOMEM;
+	}
+
+	usecases = devm_kzalloc(dd->dev, sizeof(*usecases) * 2, GFP_KERNEL);
+	if (!usecases) {
+		dev_err(dd->dev,
+		"msm_bus_scale_pdata.usecases memory allocation failed");
+		goto path_init_err;
+	}
+
+	dd->clk_path_vote.pdata = devm_kzalloc(dd->dev,
+					    sizeof(*dd->clk_path_vote.pdata),
+					    GFP_KERNEL);
+	if (!dd->clk_path_vote.pdata) {
+		dev_err(dd->dev,
+		"msm_bus_scale_pdata memory allocation failed");
+		goto path_init_err;
+	}
+
+	paths[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_vectors) {
+		.src = dd->pdata->master_id,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	};
+
+	paths[MSM_SPI_CLK_PATH_RESUME_VEC]  = (struct msm_bus_vectors) {
+		.src = dd->pdata->master_id,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = MSM_SPI_CLK_PATH_AVRG_BW(dd),
+		.ib  = MSM_SPI_CLK_PATH_BRST_BW(dd),
+	};
+
+	usecases[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_paths) {
+		.num_paths = 1,
+		.vectors   = &paths[MSM_SPI_CLK_PATH_SUSPEND_VEC],
+	};
+
+	usecases[MSM_SPI_CLK_PATH_RESUME_VEC] = (struct msm_bus_paths) {
+		.num_paths = 1,
+		.vectors   = &paths[MSM_SPI_CLK_PATH_RESUME_VEC],
+	};
+
+	*dd->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
+		.active_only  = dd->pdata->active_only,
+		.name         = dev_name(dd->dev),
+		.num_usecases = 2,
+		.usecase      = usecases,
+	};
+
+	return 0;
+
+path_init_err:
+	devm_kfree(dd->dev, paths);
+	devm_kfree(dd->dev, usecases);
+	devm_kfree(dd->dev, dd->clk_path_vote.pdata);
+	dd->clk_path_vote.pdata = NULL;
+	return -ENOMEM;
+}
+
+/**
+ * msm_spi_clk_path_postponed_register: reg with bus-scaling after it is probed
+ *
+ * @return zero on success
+ *
+ * Workaround: SPI driver may be probed before the bus scaling driver. Calling
+ * msm_bus_scale_register_client() will fail if the bus scaling driver is not
+ * ready yet. Thus, this function should be called not from probe but from a
+ * later context. Also, this function may be called more then once before
+ * register succeed. At this case only one error message will be logged. At boot
+ * time all clocks are on, so earlier SPI transactions should succeed.
+ */
+static int msm_spi_clk_path_postponed_register(struct msm_spi *dd)
+{
+	dd->clk_path_vote.client_hdl = msm_bus_scale_register_client(
+						dd->clk_path_vote.pdata);
+
+	if (dd->clk_path_vote.client_hdl) {
+		if (dd->clk_path_vote.reg_err) {
+			/* log a success message if an error msg was logged */
+			dd->clk_path_vote.reg_err = false;
+			dev_info(dd->dev,
+				"msm_bus_scale_register_client(mstr-id:%d "
+				"actv-only:%d):0x%x",
+				dd->pdata->master_id, dd->pdata->active_only,
+				dd->clk_path_vote.client_hdl);
+		}
+
+		if (dd->pdata->active_only)
+			msm_spi_clk_path_vote(dd);
+	} else {
+		/* guard to log only one error on multiple failure */
+		if (!dd->clk_path_vote.reg_err) {
+			dd->clk_path_vote.reg_err = true;
+
+			dev_info(dd->dev,
+				"msm_bus_scale_register_client(mstr-id:%d "
+				"actv-only:%d):0",
+				dd->pdata->master_id, dd->pdata->active_only);
+		}
+	}
+
+	return dd->clk_path_vote.client_hdl ? 0 : -EAGAIN;
+}
+
+static void msm_spi_clk_path_init(struct msm_spi *dd)
+{
+	/*
+	 * bail out if path voting is diabled (master_id == 0) or if it is
+	 * already registered (client_hdl != 0)
+	 */
+	if (!dd->pdata->master_id || dd->clk_path_vote.client_hdl)
+		return;
+
+	/* if fail once then try no more */
+	if (!dd->clk_path_vote.pdata && msm_spi_clk_path_init_structs(dd)) {
+		dd->pdata->master_id = 0;
+		return;
+	};
+
+	/* on failure try again later */
+	if (msm_spi_clk_path_postponed_register(dd))
+		return;
+
+	if (dd->pdata->active_only)
+		msm_spi_clk_path_vote(dd);
+}
+
 static int msm_spi_calculate_size(int *fifo_size,
 				  int *block_size,
 				  int block,
@@ -1284,7 +1457,7 @@
 		}
 
 		if (tr->cs_change &&
-		   ((bpw != 8) || (bpw != 16) || (bpw != 32)))
+		   ((bpw != 8) && (bpw != 16) && (bpw != 32)))
 			return false;
 	}
 
@@ -2359,44 +2532,124 @@
 	return 0;
 }
 
+enum msm_spi_dt_entry_status {
+	DT_REQ,  /* Required:  fail if missing */
+	DT_SGST, /* Suggested: warn if missing */
+	DT_OPT,  /* Optional:  don't warn if missing */
+};
+
+enum msm_spi_dt_entry_type {
+	DT_U32,
+	DT_GPIO,
+	DT_BOOL,
+};
+
+struct msm_spi_dt_to_pdata_map {
+	const char                  *dt_name;
+	void                        *ptr_data;
+	enum msm_spi_dt_entry_status status;
+	enum msm_spi_dt_entry_type   type;
+	int                          default_val;
+};
+
+static int __init msm_spi_dt_to_pdata_populate(struct platform_device *pdev,
+					struct msm_spi_platform_data *pdata,
+					struct msm_spi_dt_to_pdata_map  *itr)
+{
+	int  ret, err = 0;
+	struct device_node *node = pdev->dev.of_node;
+
+	for (; itr->dt_name ; ++itr) {
+		switch (itr->type) {
+		case DT_GPIO:
+			ret = of_get_named_gpio(node, itr->dt_name, 0);
+			if (ret >= 0) {
+				*((int *) itr->ptr_data) = ret;
+				ret = 0;
+			}
+			break;
+		case DT_U32:
+			ret = of_property_read_u32(node, itr->dt_name,
+							 (u32 *) itr->ptr_data);
+			break;
+		case DT_BOOL:
+			*((bool *) itr->ptr_data) =
+				of_property_read_bool(node, itr->dt_name);
+			ret = 0;
+			break;
+		default:
+			dev_err(&pdev->dev, "%d is an unknown DT entry type\n",
+								itr->type);
+			ret = -EBADE;
+		}
+
+		dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
+				ret, itr->dt_name, *((int *)itr->ptr_data));
+
+		if (ret) {
+			*((int *)itr->ptr_data) = itr->default_val;
+
+			if (itr->status < DT_OPT) {
+				dev_err(&pdev->dev, "Missing '%s' DT entry\n",
+								itr->dt_name);
+
+				/* cont on err to dump all missing entries */
+				if (itr->status == DT_REQ && !err)
+					err = ret;
+			}
+		}
+	}
+
+	return err;
+}
+
 /**
  * msm_spi_dt_to_pdata: copy device-tree data to platfrom data struct
  */
 struct msm_spi_platform_data *
 __init msm_spi_dt_to_pdata(struct platform_device *pdev)
 {
-	struct device_node *node = pdev->dev.of_node;
 	struct msm_spi_platform_data *pdata;
-	int rc;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("Unable to allocate platform data\n");
 		return NULL;
+	} else {
+		struct msm_spi_dt_to_pdata_map map[] = {
+		{"spi-max-frequency",
+			&pdata->max_clock_speed,         DT_SGST, DT_U32,  0},
+		{"qcom,infinite-mode",
+			&pdata->infinite_mode,           DT_OPT,  DT_U32,  0},
+		{"qcom,active-only",
+			&pdata->active_only,             DT_OPT,  DT_BOOL, 0},
+		{"qcom,master-id",
+			&pdata->master_id,               DT_SGST, DT_U32,  0},
+		{"qcom,ver-reg-exists",
+			&pdata->ver_reg_exists,          DT_OPT,  DT_BOOL, 0},
+		{"qcom,use-bam",
+			&pdata->use_bam,                 DT_OPT,  DT_BOOL, 0},
+		{"qcom,bam-consumer-pipe-index",
+			&pdata->bam_consumer_pipe_index, DT_OPT,  DT_U32,  0},
+		{"qcom,bam-producer-pipe-index",
+			&pdata->bam_producer_pipe_index, DT_OPT,  DT_U32,  0},
+		{NULL,  NULL,                            0,       0,       0},
+		};
+
+		if (msm_spi_dt_to_pdata_populate(pdev, pdata, map)) {
+			devm_kfree(&pdev->dev, pdata);
+			return NULL;
+		}
 	}
 
-	of_property_read_u32(node, "spi-max-frequency",
-			&pdata->max_clock_speed);
-	of_property_read_u32(node, "qcom,infinite-mode",
-			&pdata->infinite_mode);
-
-	pdata->ver_reg_exists = of_property_read_bool(node
-						, "qcom,ver-reg-exists");
-
-	pdata->use_bam = of_property_read_bool(node, "qcom,use-bam");
-
 	if (pdata->use_bam) {
-		rc = of_property_read_u32(node, "qcom,bam-consumer-pipe-index",
-					&pdata->bam_consumer_pipe_index);
-		if (rc) {
+		if (!pdata->bam_consumer_pipe_index) {
 			dev_warn(&pdev->dev,
 			"missing qcom,bam-consumer-pipe-index entry in device-tree\n");
 			pdata->use_bam = false;
 		}
 
-		rc = of_property_read_u32(node, "qcom,bam-producer-pipe-index",
-					&pdata->bam_producer_pipe_index);
-		if (rc) {
+		if (pdata->bam_producer_pipe_index) {
 			dev_warn(&pdev->dev,
 			"missing qcom,bam-producer-pipe-index entry in device-tree\n");
 			pdata->use_bam = false;
@@ -2808,6 +3061,8 @@
 	msm_spi_disable_irqs(dd);
 	clk_disable_unprepare(dd->clk);
 	clk_disable_unprepare(dd->pclk);
+	if (!dd->pdata->active_only)
+		msm_spi_clk_path_unvote(dd);
 
 	/* Free  the spi clk, miso, mosi, cs gpio */
 	if (dd->pdata && dd->pdata->gpio_release)
@@ -2858,10 +3113,14 @@
 	if (ret)
 		return ret;
 
+	msm_spi_clk_path_init(dd);
+	if (!dd->pdata->active_only)
+		msm_spi_clk_path_vote(dd);
 	clk_prepare_enable(dd->clk);
 	clk_prepare_enable(dd->pclk);
 	msm_spi_enable_irqs(dd);
 	dd->suspended = 0;
+
 resume_exit:
 	return 0;
 }
@@ -2917,6 +3176,7 @@
 	pm_runtime_set_suspended(&pdev->dev);
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
+	msm_spi_clk_path_teardown(dd);
 	destroy_workqueue(dd->workqueue);
 	platform_set_drvdata(pdev, 0);
 	spi_unregister_master(master);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index fd1adf0..90d7481 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -173,6 +173,13 @@
 #define SPI_BAM_MAX_DESC_NUM      32
 #define SPI_MAX_TRFR_BTWN_RESETS  ((64 * 1024) - 16)  /* 64KB - 16byte */
 
+enum msm_spi_clk_path_vec_idx {
+	MSM_SPI_CLK_PATH_SUSPEND_VEC = 0,
+	MSM_SPI_CLK_PATH_RESUME_VEC  = 1,
+};
+#define MSM_SPI_CLK_PATH_AVRG_BW(dd) (dd->pdata->max_clock_speed * 8)
+#define MSM_SPI_CLK_PATH_BRST_BW(dd) (dd->pdata->max_clock_speed * 8)
+
 static char const * const spi_rsrcs[] = {
 	"spi_clk",
 	"spi_miso",
@@ -253,6 +260,22 @@
 };
 #endif
 
+/**
+ * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
+ *
+ * @client_hdl when zero, client is not registered with the bus scaling driver,
+ *      and bus scaling functionality should not be used. When non zero, it
+ *      is a bus scaling client id and may be used to vote for clock path.
+ * @reg_err when true, registration error was detected and an error message was
+ *      logged. i2c will attempt to re-register but will log error only once.
+ *      once registration succeed, the flag is set to false.
+ */
+struct qup_i2c_clk_path_vote {
+	u32                         client_hdl;
+	struct msm_bus_scale_pdata *pdata;
+	bool                        reg_err;
+};
+
 struct msm_spi_bam_pipe {
 	struct sps_pipe         *handle;
 	struct sps_connect       config;
@@ -284,6 +307,7 @@
 	struct completion        transfer_complete;
 	struct clk              *clk;    /* core clock */
 	struct clk              *pclk;   /* interface clock */
+	struct qup_i2c_clk_path_vote clk_path_vote;
 	unsigned long            mem_phys_addr;
 	size_t                   mem_size;
 	int                      input_fifo_size;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a27eb09..6aeb26e 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -37,6 +37,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/power_supply.h>
 #include <linux/qpnp/qpnp-adc.h>
+#include <linux/cdev.h>
+#include <linux/completion.h>
 
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
@@ -134,6 +136,7 @@
  *
  */
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
+#define QSCRATCH_CTRL_REG      (QSCRATCH_REG_OFFSET + 0x04)
 #define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
 #define HS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x10)
 #define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
@@ -218,6 +221,15 @@
 	unsigned long		lpm_flags;
 #define MDWC3_CORECLK_OFF		BIT(0)
 #define MDWC3_TCXO_SHUTDOWN		BIT(1)
+
+	u32 qscratch_ctl_val;
+	dev_t ext_chg_dev;
+	struct cdev ext_chg_cdev;
+	struct class *ext_chg_class;
+	struct device *ext_chg_device;
+	bool ext_chg_opened;
+	bool ext_chg_active;
+	struct completion ext_chg_wait;
 };
 
 #define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -1362,6 +1374,11 @@
 		dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
 
 	dwc3_msm_ss_phy_reg_init(msm);
+	/*
+	 * This is required to restore the POR value after userspace
+	 * is done with charger detection.
+	 */
+	msm->qscratch_ctl_val = dwc3_msm_read_reg(msm->base, QSCRATCH_CTRL_REG);
 }
 
 static void dwc3_msm_block_reset(bool core_reset)
@@ -1469,6 +1486,8 @@
 {
 	u32 chg_ctrl;
 
+	dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
+			mdwc->qscratch_ctl_val);
 	/* Clear charger detecting control bits */
 	dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
 
@@ -1562,9 +1581,14 @@
 	case USB_CHG_STATE_DETECTED:
 		dwc3_chg_block_reset(mdwc);
 		/* Enable VDP_SRC */
-		if (mdwc->charger.chg_type == DWC3_DCP_CHARGER)
+		if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
 			dwc3_msm_write_readback(mdwc->base,
 					CHARGING_DET_CTRL_REG, 0x1F, 0x10);
+			if (mdwc->ext_chg_opened) {
+				init_completion(&mdwc->ext_chg_wait);
+				mdwc->ext_chg_active = true;
+			}
+		}
 		dev_dbg(mdwc->dev, "chg_type = %s\n",
 			chg_to_string(mdwc->charger.chg_type));
 		mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
@@ -1626,6 +1650,10 @@
 	      (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
 
+	if (!dcp && !host_bus_suspend)
+		dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
+			mdwc->qscratch_ctl_val);
+
 	/* Sequence to put SSPHY in low power state:
 	 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
 	 * 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
@@ -1850,6 +1878,30 @@
 	return 0;
 }
 
+static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)
+{
+	unsigned long t;
+
+	/*
+	 * Defer next cable connect event till external charger
+	 * detection is completed.
+	 */
+
+	if (mdwc->ext_chg_active && (mdwc->ext_xceiv.bsv ||
+				!mdwc->ext_xceiv.id)) {
+
+		dev_dbg(mdwc->dev, "before ext chg wait\n");
+
+		t = wait_for_completion_timeout(&mdwc->ext_chg_wait,
+				msecs_to_jiffies(3000));
+		if (!t)
+			dev_err(mdwc->dev, "ext chg wait timeout\n");
+		else
+			dev_dbg(mdwc->dev, "ext chg wait done\n");
+	}
+
+}
+
 static void dwc3_resume_work(struct work_struct *w)
 {
 	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
@@ -1859,9 +1911,11 @@
 	/* handle any event that was queued while work was already running */
 	if (!atomic_read(&mdwc->in_lpm)) {
 		dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
-		if (mdwc->otg_xceiv)
+		if (mdwc->otg_xceiv) {
+			dwc3_wait_for_ext_chg_done(mdwc);
 			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
 							DWC3_EVENT_XCEIV_STATE);
+		}
 		return;
 	}
 
@@ -1874,9 +1928,11 @@
 			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
 							DWC3_EVENT_PHY_RESUME);
 		pm_runtime_put_noidle(mdwc->dev);
-		if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
+		if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability)) {
+			dwc3_wait_for_ext_chg_done(mdwc);
 			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
 							DWC3_EVENT_XCEIV_STATE);
+		}
 	}
 }
 
@@ -2089,6 +2145,7 @@
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
 	POWER_SUPPLY_PROP_SCOPE,
 };
 
@@ -2261,6 +2318,131 @@
 static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
 		adc_enable_store);
 
+static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
+{
+	struct dwc3_msm *mdwc = context;
+
+	pr_debug("dwc3-msm ext chg open\n");
+
+	mdwc->ext_chg_opened = true;
+	return 0;
+}
+
+static ssize_t
+dwc3_msm_ext_chg_write(struct file *file, const char __user *ubuf,
+				size_t size, loff_t *pos)
+{
+	struct dwc3_msm *mdwc = context;
+	char kbuf[16];
+
+	memset(kbuf, 0x00, sizeof(kbuf));
+	if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, size)))
+		return -EFAULT;
+
+	pr_debug("%s: buf = %s\n", __func__, kbuf);
+
+	if (!strncmp(kbuf, "enable", 6)) {
+		pr_info("%s: on\n", __func__);
+		if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
+			pm_runtime_get_sync(mdwc->dev);
+		} else {
+			mdwc->ext_chg_active = false;
+			complete(&mdwc->ext_chg_wait);
+			return -ENODEV;
+		}
+	} else if (!strncmp(kbuf, "disable", 7)) {
+		pr_info("%s: off\n", __func__);
+		mdwc->ext_chg_active = false;
+		complete(&mdwc->ext_chg_wait);
+		pm_runtime_put(mdwc->dev);
+	} else {
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	int ret;
+
+	pr_debug("%s: size = %lu %x\n", __func__, vsize, (int) vma->vm_pgoff);
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				 vsize, vma->vm_page_prot);
+	if (ret < 0)
+		pr_err("%s: failed with return val %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
+{
+	struct dwc3_msm *mdwc = context;
+
+	pr_debug("dwc3-msm ext chg release\n");
+
+	mdwc->ext_chg_opened = false;
+
+	return 0;
+}
+
+static const struct file_operations dwc3_msm_ext_chg_fops = {
+	.owner = THIS_MODULE,
+	.open = dwc3_msm_ext_chg_open,
+	.write = dwc3_msm_ext_chg_write,
+	.mmap = dwc3_msm_ext_chg_mmap,
+	.release = dwc3_msm_ext_chg_release,
+};
+
+static int dwc3_msm_setup_cdev(struct dwc3_msm *mdwc)
+{
+	int ret;
+
+	ret = alloc_chrdev_region(&mdwc->ext_chg_dev, 0, 1, "usb_ext_chg");
+	if (ret < 0) {
+		pr_err("Fail to allocate usb ext char dev region\n");
+		return ret;
+	}
+	mdwc->ext_chg_class = class_create(THIS_MODULE, "dwc_ext_chg");
+	if (ret < 0) {
+		pr_err("Fail to create usb ext chg class\n");
+		goto unreg_chrdev;
+	}
+	cdev_init(&mdwc->ext_chg_cdev, &dwc3_msm_ext_chg_fops);
+	mdwc->ext_chg_cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&mdwc->ext_chg_cdev, mdwc->ext_chg_dev, 1);
+	if (ret < 0) {
+		pr_err("Fail to add usb ext chg cdev\n");
+		goto destroy_class;
+	}
+	mdwc->ext_chg_device = device_create(mdwc->ext_chg_class,
+					NULL, mdwc->ext_chg_dev, NULL,
+					"usb_ext_chg");
+	if (IS_ERR(mdwc->ext_chg_device)) {
+		pr_err("Fail to create usb ext chg device\n");
+		ret = PTR_ERR(mdwc->ext_chg_device);
+		mdwc->ext_chg_device = NULL;
+		goto del_cdev;
+	}
+
+	pr_debug("dwc3 msm ext chg cdev setup success\n");
+	return 0;
+
+del_cdev:
+	cdev_del(&mdwc->ext_chg_cdev);
+destroy_class:
+	class_destroy(mdwc->ext_chg_class);
+unreg_chrdev:
+	unregister_chrdev_region(mdwc->ext_chg_dev, 1);
+
+	return ret;
+}
+
 static int __devinit dwc3_msm_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
@@ -2288,6 +2470,7 @@
 	INIT_WORK(&msm->restart_usb_work, dwc3_restart_usb_work);
 	INIT_WORK(&msm->id_work, dwc3_id_work);
 	INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
+	init_completion(&msm->ext_chg_wait);
 
 	msm->xo_clk = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(msm->xo_clk)) {
@@ -2651,6 +2834,11 @@
 		}
 		msm->otg_xceiv = NULL;
 	}
+	if (msm->ext_xceiv.otg_capability && msm->charger.start_detection) {
+		ret = dwc3_msm_setup_cdev(msm);
+		if (ret)
+			dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
+	}
 
 	wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
 	wake_lock(&msm->wlock);
@@ -2703,6 +2891,13 @@
 {
 	struct dwc3_msm	*msm = platform_get_drvdata(pdev);
 
+	if (!msm->ext_chg_device) {
+		device_destroy(msm->ext_chg_class, msm->ext_chg_dev);
+		cdev_del(&msm->ext_chg_cdev);
+		class_destroy(msm->ext_chg_class);
+		unregister_chrdev_region(msm->ext_chg_dev, 1);
+	}
+
 	if (msm->id_adc_detect)
 		qpnp_adc_tm_usbid_end();
 	if (dwc3_debugfs_root)
@@ -2791,8 +2986,27 @@
 
 static int dwc3_msm_runtime_idle(struct device *dev)
 {
+	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
 	dev_dbg(dev, "DWC3-msm runtime idle\n");
 
+	if (mdwc->ext_chg_active) {
+		dev_dbg(dev, "Deferring LPM\n");
+		/*
+		 * Charger detection may happen in user space.
+		 * Delay entering LPM by 3 sec.  Otherwise we
+		 * have to exit LPM when user space begins
+		 * charger detection.
+		 *
+		 * This timer will be canceled when user space
+		 * votes against LPM by incrementing PM usage
+		 * counter.  We enter low power mode when
+		 * PM usage counter is decremented.
+		 */
+		pm_schedule_suspend(dev, 3000);
+		return -EAGAIN;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index a3b2617..be9a4b5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -498,7 +498,7 @@
 
 	power_supply_set_supply_type(dotg->psy, power_supply_type);
 
-	if ((dotg->charger->chg_type == DWC3_CDP_CHARGER) && mA > 2)
+	if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
 		mA = DWC3_IDEV_CHG_MAX;
 
 	if (dotg->charger->max_power == mA)
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index aaacd43..15f20ca 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -74,7 +74,6 @@
 	struct usb_composite_dev	*cdev;
 
 	atomic_t	online;
-	bool		is_open;
 
 	atomic_t	open_excl;
 	atomic_t	ioctl_excl;
@@ -747,11 +746,6 @@
 	pr_debug("Queue empty packet for QBI");
 
 	spin_lock(&dev->lock);
-	if (!dev->is_open) {
-		pr_err("%s: mbim file handler %p is not open", __func__, dev);
-		spin_unlock(&dev->lock);
-		return;
-	}
 
 	cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
 	if (!cpkt) {
@@ -976,12 +970,6 @@
 	memcpy(cpkt->buf, req->buf, len);
 
 	spin_lock(&dev->lock);
-	if (!dev->is_open) {
-		pr_err("mbim file handler %p is not open", dev);
-		spin_unlock(&dev->lock);
-		mbim_free_ctrl_pkt(cpkt);
-		return;
-	}
 
 	list_add_tail(&cpkt->list, &dev->cpkt_req_q);
 	spin_unlock(&dev->lock);
@@ -1455,6 +1443,7 @@
 	mbim_union_desc.bSlaveInterface0 = status;
 
 	mbim->bam_port.cdev = cdev;
+	mbim->bam_port.func = &mbim->function;
 
 	status = -ENODEV;
 
@@ -1574,6 +1563,7 @@
 {
 	struct f_mbim	*mbim = func_to_mbim(f);
 
+	bam_data_destroy(mbim->port_num);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
@@ -1844,10 +1834,6 @@
 
 	atomic_set(&_mbim_dev->error, 0);
 
-	spin_lock(&_mbim_dev->lock);
-	_mbim_dev->is_open = true;
-	spin_unlock(&_mbim_dev->lock);
-
 	pr_info("Exit, mbim file opened\n");
 
 	return 0;
@@ -1855,14 +1841,8 @@
 
 static int mbim_release(struct inode *ip, struct file *fp)
 {
-	struct f_mbim *mbim = fp->private_data;
-
 	pr_info("Close mbim file");
 
-	spin_lock(&mbim->lock);
-	mbim->is_open = false;
-	spin_unlock(&mbim->lock);
-
 	mbim_unlock(&_mbim_dev->open_excl);
 
 	return 0;
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 37189d8..4586d80 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -696,8 +696,8 @@
 			break;
 		}
 
-		if (count > MTP_BULK_BUFFER_SIZE)
-			xfer = MTP_BULK_BUFFER_SIZE;
+		if (count > mtp_tx_req_len)
+			xfer = mtp_tx_req_len;
 		else
 			xfer = count;
 		if (xfer && copy_from_user(req->buf, buf, xfer)) {
@@ -789,8 +789,8 @@
 			break;
 		}
 
-		if (count > MTP_BULK_BUFFER_SIZE)
-			xfer = MTP_BULK_BUFFER_SIZE;
+		if (count > mtp_tx_req_len)
+			xfer = mtp_tx_req_len;
 		else
 			xfer = count;
 
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index a6b443f..3db5b51 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -846,6 +846,7 @@
 
 	DBG(c->cdev, "ecm unbind\n");
 
+	bam_data_destroy(0);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 267cf53..c1ab552 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,14 +725,14 @@
 		 */
 		rndis->port.cdc_filter = 0;
 
+		if (rndis_qc_bam_connect(rndis))
+			goto fail;
+
 		DBG(cdev, "RNDIS RX/TX early activation ...\n");
 		net = gether_qc_connect_name(&rndis->port, "rndis0", false);
 		if (IS_ERR(net))
 			return PTR_ERR(net);
 
-		if (rndis_qc_bam_connect(rndis))
-			goto fail;
-
 		rndis_set_param_dev(rndis->config, net,
 				&rndis->port.cdc_filter);
 	} else
@@ -976,6 +976,8 @@
 {
 	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
 
+	pr_debug("rndis_qc_unbind: free");
+	bam_data_destroy(0);
 	rndis_deregister(rndis->config);
 	rndis_exit();
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index b71f903..9dd9978 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -778,6 +778,7 @@
 	unsigned long flags;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
+		usb_bam_reset_complete();
 		ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
 		if (ret) {
 			pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
@@ -916,7 +917,7 @@
 	msm_hw_bam_disable(1);
 
 	/* Reset BAM */
-	ret = usb_bam_a2_reset();
+	ret = usb_bam_a2_reset(0);
 	if (ret) {
 		pr_err("%s: BAM reset failed %d\n", __func__, ret);
 		goto reenable_eps;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index c638164..5c7e52f 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -145,69 +145,24 @@
 	struct bam_data_port	*port = (struct bam_data_port *)param;
 	struct bam_data_ch_info *d;
 	int ret;
-	bool reenable_eps = false;
 
 	d = &port->data_ch;
 
 	pr_debug("%s: reset by peer\n", __func__);
 
-	/* Disable the relevant EPs if currently EPs are enabled */
-	if (port->port_usb && port->port_usb->in &&
-	  port->port_usb->in->driver_data) {
-		usb_ep_disable(port->port_usb->out);
-		usb_ep_disable(port->port_usb->in);
-
-		port->port_usb->in->driver_data = NULL;
-		port->port_usb->out->driver_data = NULL;
-		reenable_eps = true;
-	}
-
 	/* Disable BAM */
 	msm_hw_bam_disable(1);
 
 	/* Reset BAM */
-	ret = usb_bam_a2_reset();
+	ret = usb_bam_a2_reset(0);
 	if (ret) {
 		pr_err("%s: BAM reset failed %d\n", __func__, ret);
-		goto reenable_eps;
+		return ret;
 	}
 
 	/* Enable BAM */
 	msm_hw_bam_disable(0);
 
-reenable_eps:
-	/* Re-Enable the relevant EPs, if EPs were originally enabled */
-	if (reenable_eps) {
-		if (config_ep_by_speed(port->port_usb->cdev->gadget,
-			port->port_usb->func, port->port_usb->in) ||
-		    config_ep_by_speed(port->port_usb->cdev->gadget,
-			port->port_usb->func, port->port_usb->out)) {
-			pr_err("%s: config_ep_by_speed failed", __func__);
-				port->port_usb->in->desc = NULL;
-				port->port_usb->out->desc = NULL;
-				return -EINVAL;
-		}
-		ret = usb_ep_enable(port->port_usb->in);
-		if (ret) {
-			pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
-				__func__, port->port_usb->in);
-			return ret;
-		}
-		port->port_usb->in->driver_data = port;
-
-		ret = usb_ep_enable(port->port_usb->out);
-		if (ret) {
-			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
-				__func__, port->port_usb->out);
-			port->port_usb->in->driver_data = 0;
-			return ret;
-		}
-		port->port_usb->out->driver_data = port;
-
-		bam_data_start_endless_rx(port);
-		bam_data_start_endless_tx(port);
-	}
-
 	/* Unregister the peer reset callback */
 	usb_bam_register_peer_reset_cb(NULL, NULL);
 
@@ -244,6 +199,7 @@
 	int ret;
 
 	pr_debug("%s: Connect workqueue started", __func__);
+	usb_bam_reset_complete();
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
 		if (d->func_type == USB_FUNC_MBIM) {
@@ -504,6 +460,23 @@
 	return 0;
 }
 
+int bam_data_destroy(unsigned int no_bam2bam_port)
+{
+	struct bam_data_ch_info	*d;
+	struct bam_data_port	*port;
+
+	port = bam2bam_data_ports[no_bam2bam_port];
+	d = &port->data_ch;
+
+	pr_debug("bam_data_destroy: Freeing ports\n");
+	bam2bam_data_port_free(no_bam2bam_port);
+	if (bam_data_wq)
+		destroy_workqueue(bam_data_wq);
+	bam_data_wq = NULL;
+
+	return 0;
+}
+
 int bam_data_setup(unsigned int no_bam2bam_port)
 {
 	int	i;
@@ -516,6 +489,11 @@
 		return -EINVAL;
 	}
 
+	if (bam_data_wq) {
+		pr_debug("bam_data is already setup");
+		return 0;
+	}
+
 	bam_data_wq = alloc_workqueue("k_bam_data",
 				      WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
 	if (!bam_data_wq) {
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 5ce678d..61f653a 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -36,6 +36,8 @@
 
 int bam_data_setup(unsigned int no_bam2bam_port);
 
+int bam_data_destroy(unsigned int no_bam2bam_port);
+
 void bam_data_suspend(u8 port_num);
 
 void bam_data_resume(u8 port_num);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 734756c..98e7e29 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -125,7 +125,7 @@
 	if (enable)
 		INIT_COMPLETION(mdp3_session->vsync_comp);
 	else
-		complete_all(&mdp3_session->vsync_comp);
+		complete(&mdp3_session->vsync_comp);
 	spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index afabc20..366209b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -417,7 +417,7 @@
 	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
 
 	/* disable DSI phy */
-	mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
+	mdss_dsi_phy_enable(ctrl_pdata, 0);
 
 	mdss_dsi_disable_bus_clocks(ctrl_pdata);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index f612751..965a23f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -412,7 +412,7 @@
 int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
-void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
+void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on);
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
 void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
 void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 3ee4d08..72e3c64 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -212,7 +212,7 @@
 int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
 {
 
-	dp->start = kmalloc(size, GFP_KERNEL);
+	dp->start = dma_alloc_writecombine(NULL, size, &dp->dmap, GFP_KERNEL);
 	if (dp->start == NULL) {
 		pr_err("%s:%u\n", __func__, __LINE__);
 		return -ENOMEM;
@@ -1360,11 +1360,6 @@
 	len = ALIGN(tp->len, 4);
 	size = ALIGN(tp->len, SZ_4K);
 
-	tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
-	if (dma_mapping_error(&dsi_dev, tp->dmap)) {
-		pr_err("%s: dmap mapp failed\n", __func__);
-		return -ENOMEM;
-	}
 
 	if (is_mdss_iommu_attached()) {
 		int ret = msm_iommu_map_contig_buffer(tp->dmap,
@@ -1409,8 +1404,6 @@
 		msm_iommu_unmap_contig_buffer(addr,
 			mdss_get_iommu_domain(domain), 0, size);
 
-	dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
-	tp->dmap = 0;
 	return tp->len;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e16f2df..d9fffa8 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -634,8 +634,11 @@
 
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
+			mutex_lock(&mfd->bl_lock);
+			mdss_fb_set_backlight(mfd, 0);
 			mfd->panel_power_on = false;
 			bl_updated = 0;
+			mutex_unlock(&mfd->bl_lock);
 
 			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f59cdaa..7c9b5a9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -364,6 +364,12 @@
 	bool mixer_swap;
 };
 
+struct mdss_mdp_perf_params {
+	u32 ib_quota;
+	u32 ab_quota;
+	u32 mdp_clk_rate;
+};
+
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
@@ -430,6 +436,8 @@
 int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
+int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
+		struct mdss_mdp_perf_params *perf);
 
 struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
 int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 1cd2dbd..e81e3f5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -98,13 +98,80 @@
 	return 0;
 }
 
+/**
+ * mdss_mdp_perf_calc_pipe() - calculate performance numbers required by pipe
+ * @pipe:	Source pipe struct containing updated pipe params
+ * @perf:	Structure containing values that should be updated for
+ *		performance tuning
+ *
+ * Function calculates the minimum required performance calculations in order
+ * to avoid MDP underflow. The calculations are based on the way MDP
+ * fetches (bandwidth requirement) and processes data through MDP pipeline
+ * (MDP clock requirement) based on frame size and scaling requirements.
+ */
+int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
+		struct mdss_mdp_perf_params *perf)
+{
+	struct mdss_mdp_mixer *mixer;
+	int fps = DEFAULT_FRAME_RATE;
+	u32 quota, rate, v_total, src_h;
+
+	if (!pipe || !perf || !pipe->mixer)
+		return -EINVAL;
+
+	mixer = pipe->mixer;
+	if (mixer->rotator_mode) {
+		v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+	} else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		struct mdss_panel_info *pinfo;
+
+		pinfo = &mixer->ctl->panel_data->panel_info;
+		fps = mdss_panel_get_framerate(pinfo);
+		v_total = mdss_panel_get_vtotal(pinfo);
+	} else {
+		v_total = mixer->height;
+	}
+
+	/*
+	 * when doing vertical decimation lines will be skipped, hence there is
+	 * no need to account for these lines in MDP clock or request bus
+	 * bandwidth to fetch them.
+	 */
+	src_h = pipe->src.h >> pipe->vert_deci;
+
+	quota = fps * pipe->src.w * src_h;
+	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+		quota = (quota * 3) / 2;
+	else
+		quota *= pipe->src_fmt->bpp;
+
+	rate = pipe->dst.w;
+	if (src_h > pipe->dst.h)
+		rate = (rate * src_h) / pipe->dst.h;
+
+	rate *= v_total * fps;
+	if (mixer->rotator_mode) {
+		rate /= 4; /* block mode fetch at 4 pix/clk */
+		quota *= 2; /* bus read + write */
+		perf->ib_quota = quota;
+	} else {
+		perf->ib_quota = (quota / pipe->dst.h) * v_total;
+	}
+	perf->ab_quota = quota;
+	perf->mdp_clk_rate = rate;
+
+	pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+		 mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota);
+
+	return 0;
+}
+
 static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
 				       u32 *bus_ab_quota, u32 *bus_ib_quota,
 				       u32 *clk_rate)
 {
 	struct mdss_mdp_pipe *pipe;
-	const int fps = 60;
-	u32 quota, rate;
+	int fps = DEFAULT_FRAME_RATE;
 	u32 v_total;
 	int i;
 	u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;
@@ -113,17 +180,13 @@
 	*bus_ib_quota = 0;
 	*clk_rate = 0;
 
-	if (mixer->rotator_mode) {
-		pipe = mixer->stage_pipe[0]; /* rotator pipe */
-		v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
-	} else {
+	if (!mixer->rotator_mode) {
 		int is_writeback = false;
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
 			struct mdss_panel_info *pinfo;
 			pinfo = &mixer->ctl->panel_data->panel_info;
-			v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
-				   pinfo->lcdc.v_front_porch +
-				   pinfo->lcdc.v_pulse_width);
+			fps = mdss_panel_get_framerate(pinfo);
+			v_total = mdss_panel_get_vtotal(pinfo);
 
 			if (pinfo->type == WRITEBACK_PANEL)
 				is_writeback = true;
@@ -142,7 +205,7 @@
 	}
 
 	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
-		u32 ib_quota;
+		struct mdss_mdp_perf_params perf;
 		pipe = mixer->stage_pipe[i];
 		if (pipe == NULL)
 			continue;
@@ -152,33 +215,13 @@
 			max_clk_rate = 0;
 		}
 
-		quota = fps * pipe->src.w * pipe->src.h;
-		if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
-			quota = (quota * 3) / 2;
-		else
-			quota *= pipe->src_fmt->bpp;
+		if (mdss_mdp_perf_calc_pipe(pipe, &perf))
+			continue;
 
-		rate = pipe->dst.w;
-		if (pipe->src.h > pipe->dst.h)
-			rate = (rate * pipe->src.h) / pipe->dst.h;
-
-		rate *= v_total * fps;
-		if (mixer->rotator_mode) {
-			rate /= 4; /* block mode fetch at 4 pix/clk */
-			quota *= 2; /* bus read + write */
-			ib_quota = quota;
-		} else {
-			ib_quota = (quota / pipe->dst.h) * v_total;
-		}
-
-
-		pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
-			 mixer->num, pipe->num, rate, quota, ib_quota);
-
-		ab_total += quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
-		ib_total += ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
-		if (rate > max_clk_rate)
-			max_clk_rate = rate;
+		ab_total += perf.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+		ib_total += perf.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+		if (perf.mdp_clk_rate > max_clk_rate)
+			max_clk_rate = perf.mdp_clk_rate;
 	}
 
 	*bus_ab_quota += ab_total;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index fcaa80b..808800a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -289,6 +289,32 @@
 	return ret;
 }
 
+static int __mdp_pipe_tune_perf(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_data_type *mdata = pipe->mixer->ctl->mdata;
+	struct mdss_mdp_perf_params perf;
+	int rc;
+
+	for (;;) {
+		rc = mdss_mdp_perf_calc_pipe(pipe, &perf);
+
+		if (!rc && (perf.mdp_clk_rate <= mdata->max_mdp_clk_rate))
+			break;
+
+		/*
+		 * if decimation is available try to reduce minimum clock rate
+		 * requirement by applying vertical decimation and reduce
+		 * mdp clock requirement
+		 */
+		if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION))
+			pipe->vert_deci++;
+		else
+			return -EPERM;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
 				       struct mdp_overlay *req,
 				       struct mdss_mdp_pipe **ppipe)
@@ -497,6 +523,12 @@
 		}
 	}
 
+	ret = __mdp_pipe_tune_perf(pipe);
+	if (ret) {
+		pr_debug("unable to satisfy performance. ret=%d\n", ret);
+		goto exit_fail;
+	}
+
 	ret = mdss_mdp_smp_reserve(pipe);
 	if (ret) {
 		pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -506,6 +538,7 @@
 	pipe->params_changed++;
 
 	req->id = pipe->ndx;
+	req->vert_deci = pipe->vert_deci;
 
 	*ppipe = pipe;
 
@@ -1667,7 +1700,7 @@
 	switch (metadata->op) {
 	case metadata_op_frame_rate:
 		metadata->data.panel_frame_rate =
-			mdss_get_panel_framerate(mfd);
+			mdss_panel_get_framerate(mfd->panel_info);
 		break;
 	case metadata_op_get_caps:
 		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 305c3cb..539ed22 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -28,7 +28,6 @@
 #include "mdss_mdp.h"
 #include "mdss_mdp_formats.h"
 #include "mdss_debug.h"
-#define DEFAULT_FRAME_RATE	60
 
 enum {
 	MDP_INTR_VSYNC_INTF_0,
@@ -246,6 +245,9 @@
 			ps->rau_h[1] = 4;
 		} else
 			ps->ystride[1] = 32 * 2;
+
+		/* account for both chroma components */
+		ps->ystride[1] <<= 1;
 	} else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
 		ps->rau_cnt = DIV_ROUND_UP(w, 32);
 		ps->ystride[0] = 32 * 4 * fmt->bpp;
@@ -261,6 +263,10 @@
 	ps->ystride[1] *= ps->rau_cnt;
 	ps->num_planes = 2;
 
+	pr_debug("BWC rau_cnt=%d strides={%d,%d} heights={%d,%d}\n",
+		ps->rau_cnt, ps->ystride[0], ps->ystride[1],
+		ps->rau_h[0], ps->rau_h[1]);
+
 	return 0;
 }
 
@@ -269,7 +275,7 @@
 {
 	struct mdss_mdp_format_params *fmt;
 	int i, rc;
-	u32 bpp, ystride0_off, ystride1_off;
+	u32 bpp;
 	if (ps == NULL)
 		return -EINVAL;
 
@@ -284,24 +290,23 @@
 	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
 
 	if (bwc_mode) {
-		u32 meta_size;
+		u32 height, meta_size;
 
 		rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
 		if (rc)
 			return rc;
 
+		height = DIV_ROUND_UP(h, ps->rau_h[0]);
 		meta_size = DIV_ROUND_UP(ps->rau_cnt, 8);
-		ps->ystride[0] += meta_size;
 		ps->ystride[1] += meta_size;
+		ps->ystride[0] += ps->ystride[1] + meta_size;
+		ps->plane_size[0] = ps->ystride[0] * height;
 
-		ystride0_off = DIV_ROUND_UP(h, ps->rau_h[0]);
-		ystride1_off = DIV_ROUND_UP(h, ps->rau_h[1]);
-		ps->plane_size[0] = (ps->ystride[0] * ystride0_off) +
-				    (ps->ystride[1] * ystride1_off);
-		ps->ystride[0] += ps->ystride[1];
 		ps->ystride[1] = 2;
-		ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] *
-				   (ystride0_off + ystride1_off);
+		ps->plane_size[1] = 2 * ps->rau_cnt * height;
+
+		pr_debug("BWC data stride=%d size=%d meta size=%d\n",
+			ps->ystride[0], ps->plane_size[0], ps->plane_size[1]);
 	} else {
 		if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
 			ps->num_planes = 1;
@@ -551,27 +556,3 @@
 
 	return ret;
 }
-
-u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
-{
-	u32 frame_rate = DEFAULT_FRAME_RATE;
-	u32 pixel_total;
-	struct mdss_panel_info *panel_info = mfd->panel_info;
-
-	if ((panel_info->type == MIPI_VIDEO_PANEL) ||
-			(panel_info->type == MIPI_CMD_PANEL)) {
-		frame_rate = panel_info->mipi.frame_rate;
-	} else {
-		pixel_total = (panel_info->lcdc.h_back_porch +
-			  panel_info->lcdc.h_front_porch +
-			  panel_info->lcdc.h_pulse_width +
-			  panel_info->xres) *
-			 (panel_info->lcdc.v_back_porch +
-			  panel_info->lcdc.v_front_porch +
-			  panel_info->lcdc.v_pulse_width +
-			  panel_info->yres);
-		if (pixel_total)
-			frame_rate = panel_info->clk_rate / pixel_total;
-	}
-	return frame_rate;
-}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 1bf414f..e8a6312 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -23,6 +23,8 @@
 	u16 type;
 };
 
+#define DEFAULT_FRAME_RATE	60
+
 /* panel type list */
 #define NO_PANEL		0xffff	/* No Panel */
 #define MDDI_PANEL		1	/* MDDI */
@@ -270,6 +272,58 @@
 	struct mdss_panel_data *next;
 };
 
+/**
+ * mdss_get_panel_framerate() - get panel frame rate based on panel information
+ * @panel_info:	Pointer to panel info containing all panel information
+ */
+static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info)
+{
+	u32 frame_rate, pixel_total;
+
+	if (panel_info == NULL)
+		return DEFAULT_FRAME_RATE;
+
+	switch (panel_info->type) {
+	case MIPI_VIDEO_PANEL:
+	case MIPI_CMD_PANEL:
+		frame_rate = panel_info->mipi.frame_rate;
+		break;
+	case WRITEBACK_PANEL:
+		frame_rate = DEFAULT_FRAME_RATE;
+		break;
+	default:
+		pixel_total = (panel_info->lcdc.h_back_porch +
+			  panel_info->lcdc.h_front_porch +
+			  panel_info->lcdc.h_pulse_width +
+			  panel_info->xres) *
+			 (panel_info->lcdc.v_back_porch +
+			  panel_info->lcdc.v_front_porch +
+			  panel_info->lcdc.v_pulse_width +
+			  panel_info->yres);
+		if (pixel_total)
+			frame_rate = panel_info->clk_rate / pixel_total;
+		else
+			frame_rate = DEFAULT_FRAME_RATE;
+
+		break;
+	}
+	return frame_rate;
+}
+
+/*
+ * mdss_panel_get_vtotal() - return panel vertical height
+ * @pinfo:	Pointer to panel info containing all panel information
+ *
+ * Returns the total height of the panel including any blanking regions
+ * which are not visible to user but used to calculate panel pixel clock.
+ */
+static inline int mdss_panel_get_vtotal(struct mdss_panel_info *pinfo)
+{
+	return pinfo->yres + pinfo->lcdc.v_back_porch +
+			pinfo->lcdc.v_front_porch +
+			pinfo->lcdc.v_pulse_width;
+}
+
 int mdss_register_panel(struct platform_device *pdev,
 	struct mdss_panel_data *pdata);
 #endif /* MDSS_PANEL_H */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index d4eb716..aab67df 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -287,42 +287,66 @@
 	wmb();
 }
 
-void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
+void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on)
 {
+	static struct mdss_dsi_ctrl_pdata *left_ctrl;
+
+	if (ctrl == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	if (!left_ctrl
+		&& ctrl->shared_pdata.broadcast_enable)
+		if ((ctrl->panel_data).panel_info.pdest
+						== DISPLAY_1)
+			left_ctrl = ctrl;
+
 	if (on) {
-		MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
+		MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x03);
 		wmb();
 		usleep(100);
-		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
 		wmb();
 		usleep(100);
-		MIPI_OUTP(ctrl_base + 0x0268, 0x001);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x001);
 		wmb();
 		usleep(100);
-		MIPI_OUTP(ctrl_base + 0x0268, 0x000);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x000);
 		wmb();
 		usleep(100);
-		MIPI_OUTP(ctrl_base + 0x0220, 0x007);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x007);
 		wmb();
-		MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
+		MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x01);
 		wmb();
 		usleep(100);
 
 		/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-		MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x06e);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x06c);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x064);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x065);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x075);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x077);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x07f);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07e);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06e);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06c);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x064);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x065);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x075);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x077);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07f);
 		wmb();
-
 	} else {
-		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
-		MIPI_OUTP(ctrl_base + 0x0470, 0x000);
-		MIPI_OUTP(ctrl_base + 0x0598, 0x000);
+		if (left_ctrl &&
+			(ctrl->panel_data.panel_info.pdest
+						== DISPLAY_1))
+			return;
+
+		if (left_ctrl &&
+			(ctrl->panel_data.panel_info.pdest
+						== DISPLAY_2)) {
+			MIPI_OUTP(left_ctrl->ctrl_base + 0x0220, 0x006);
+			MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, 0x000);
+			MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, 0x000);
+		}
+		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
+		MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
 		wmb();
 	}
 }
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 47a2b7b..644eede 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -75,6 +75,7 @@
 	BATT_DESAY,
 	BATT_OEM,
 	BATT_QRD_4V35_2000MAH,
+	BATT_QRD_4V2_1300MAH,
 };
 
 /**
@@ -116,6 +117,7 @@
 extern struct bms_battery_data  desay_5200_data;
 extern struct bms_battery_data  oem_batt_data;
 extern struct bms_battery_data QRD_4v35_2000mAh_data;
+extern struct bms_battery_data  qrd_4v2_1300mah_data;
 
 int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
 int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
diff --git a/include/linux/mfd/pm8xxx/pwm.h b/include/linux/mfd/pm8xxx/pwm.h
index 6d95e3a..47ebe06 100644
--- a/include/linux/mfd/pm8xxx/pwm.h
+++ b/include/linux/mfd/pm8xxx/pwm.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
@@ -32,6 +32,9 @@
 
 #define PM_PWM_LUT_NO_TABLE	0x100
 
+#define PM_PWM_BANK_LO		0x1000
+#define PM_PWM_BANK_HI		0x2000
+
 /**
  * PWM frequency/period control
  *
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 25d528d7..4d36688 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -375,6 +375,7 @@
 #define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
 #define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4')
 #define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1')
+#define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T')
 
 #define VIDIOC_MSM_VFE_REG_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index c9eb12a..61dfd52 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -1,8 +1,10 @@
 #ifndef MSM_CAM_ISPIF_H
 #define MSM_CAM_ISPIF_H
 
-#define CSID_VERSION_V2                       0x02000011
-#define CSID_VERSION_V3                       0x30000000
+#define CSID_VERSION_V20                      0x02000011
+#define CSID_VERSION_V22                      0x02001000
+#define CSID_VERSION_V30                      0x30000000
+#define CSID_VERSION_V3                      0x30000000
 
 enum msm_ispif_vfe_intf {
 	VFE0,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 67c03d6..a4f3c21 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -5885,6 +5885,9 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
 	TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
+
+	/* Set HPH Path to low power mode */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x55),
 };
 
 static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5912,8 +5915,6 @@
 	 * Rx PA bring up.
 	 */
 	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
-	/* Reduce HPH DAC bias to 70% */
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 	/*Reduce EAR DAC bias to 70% */
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
 	/* Reduce LINE DAC bias to 70% */
@@ -5955,7 +5956,6 @@
 	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
 	TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_OCP_CTL, 0x69),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CNP_WG_CTL, 0xDA),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CNP_WG_TIME, 0x15),
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index e853061..3c226f7 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -677,7 +677,7 @@
 				&mbhc->hph_pa_dac_state)) {
 		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL,
-				    0xC0, 0xC0);
+				    0x80, 0x80);
 	}
 
 	if (test_and_clear_bit(WCD9XXX_HPHR_PA_OFF_ACK,
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 9990ae8..22cd61a 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -295,10 +295,10 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	switch (ucontrol->value.integer.value[0]) {
-	case 0:
+	case 8000:
 		msm_btsco_rate = BTSCO_RATE_8KHZ;
 		break;
-	case 1:
+	case 16000:
 		msm_btsco_rate = BTSCO_RATE_16KHZ;
 		break;
 	default:
@@ -310,11 +310,6 @@
 	return 0;
 }
 
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
-	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
-		     msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
 static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -549,6 +544,8 @@
 		     msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
 	SOC_ENUM_EXT("AUX PCM SampleRate", msm8226_auxpcm_enum[0],
 			msm8226_auxpcm_rate_get, msm8226_auxpcm_rate_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		     msm_btsco_rate_get, msm_btsco_rate_put),
 };
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 9fc0adb..a39a18b 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -862,10 +862,10 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	switch (ucontrol->value.integer.value[0]) {
-	case 0:
+	case 8000:
 		msm_btsco_rate = BTSCO_RATE_8KHZ;
 		break;
-	case 1:
+	case 16000:
 		msm_btsco_rate = BTSCO_RATE_16KHZ;
 		break;
 	default:
@@ -940,11 +940,6 @@
 	return 1;
 }
 
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
-	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
-		     msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
 static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -1350,6 +1345,8 @@
 			hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
 	SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
 			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		     msm_btsco_rate_get, msm_btsco_rate_put),
 };
 
 static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index a1c1aef..4a20af1 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -150,7 +150,7 @@
 		 * check for underrun
 		 */
 		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
-			pr_err("render stopped");
+			pr_info("render stopped");
 			runtime->render_flag |= SNDRV_RENDER_STOPPED;
 			break;
 		}
@@ -519,12 +519,14 @@
 			}
 		}
 		atomic_set(&prtd->start, 0);
+		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
 		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
 		atomic_set(&prtd->start, 0);
+		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
 		break;
 	default:
 		ret = -EINVAL;
@@ -745,7 +747,7 @@
 	int dir = -1;
 
 	prtd->mmap_flag = 1;
-
+	runtime->render_flag = SNDRV_NON_DMA_MODE;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
 	else