Merge "arm/dt: msm8610: Adjust Y-clipping data for Atmel touch Controller"
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/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/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/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index fbe2d25..e3a6721 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -135,6 +135,21 @@
 		qcom,usb2-power-budget = <500>;
 	};
 
+MSM HSUSB controller
+
+Required properties :
+- compatible : should be "qcom,ci13xxx_msm"
+
+Optional properties :
+- qcom,itc-level: value of 2^itc-level will be used for as the interrupt threshold
+	(ITC), when itc-level is between 0 to 6.
+
+Example MSM HSUSB controller device node :
+	msm_hsusb: qcom,ci13xxx_msm {
+		compatible = "qcom,ci13xxx_msm";
+		qcom,itc-level = <4>;
+};
+
 ANDROID USB:
 
 Required properties:
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 d4adb2a..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";
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/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1877f40..0e446e2 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index d429f72..2008e1e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,6 +22,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
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 5f9365a..4d7a38a 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -157,6 +157,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x61>;
+				qcom,mode = "manual";
 			};
 		};
 
@@ -171,6 +172,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x10>;
+				qcom,mode = "manual";
 			};
 		};
 	};
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 054c460..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 {
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..f184a00 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -175,6 +175,11 @@
 				<87 512 40000 640000>;
 	};
 
+	msm_hsusb: qcom,ci13xxx_msm {
+		compatible = "qcom,ci13xxx_msm";
+		qcom,itc-level = <4>;
+	};
+
 	hsic_host: hsic@f9a15000 {
 		compatible = "qcom,hsic-host";
 		reg = <0xf9a15000 0x400>;
@@ -244,9 +249,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 +521,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/boot/dts/msmkrypton-sim.dts b/arch/arm/boot/dts/msmkrypton-sim.dts
index 1872a36..29f0df4 100644
--- a/arch/arm/boot/dts/msmkrypton-sim.dts
+++ b/arch/arm/boot/dts/msmkrypton-sim.dts
@@ -23,3 +23,13 @@
 &uartdm3{
 	status = "ok";
 };
+
+&spi_6 {
+	ethernet-switch@0 {
+		compatible = "simtec,ks8851";
+		reg = <0>;
+		interrupt-parent = <&msmgpio>;
+		spi-max-frequency = <19200000>;
+		interrupts = <75 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index 4b032d8..7bbd528 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -117,4 +117,19 @@
 		interrupts = <0 109 0>;
 		status = "disabled";
 	};
+
+	spi_6: spi@f9928000 { /* BLSP1 QUP6 */
+		cell-index = <0>;
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xf9928000 0x1000>;
+		interrupts = <0 100 0>;
+		spi-max-frequency = <19200000>;
+
+		gpios = <&msmgpio 23 0>, /* CLK  */
+		<&msmgpio 21 0>, /* MISO */
+		<&msmgpio 20 0>; /* MOSI */
+		cs-gpios = <&msmgpio 22 0>;
+	};
 };
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..ae26f96 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
@@ -364,16 +359,8 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=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 +400,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..f8fbdb7 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
@@ -389,6 +384,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=y
@@ -438,12 +434,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..5cad31e 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
@@ -347,6 +348,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V0=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index d11773f..95b4f0c 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
@@ -367,6 +367,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V0=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=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 6c12216..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
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 967f62d..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
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/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
index 69bc36e..f073d2b 100644
--- a/arch/arm/configs/msmkrypton_defconfig
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -65,9 +65,28 @@
 CONFIG_MTD_BLOCK=y
 # CONFIG_MTD_MSM_NAND is not set
 CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
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/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-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.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-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 f1df505..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),
 	},
@@ -2868,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);
@@ -3236,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 9a66b78..58c5745 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -1828,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,
 };
@@ -2997,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 adb1101..facd6ba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -1574,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/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/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/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index 3a997be..a4021d4 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -18,13 +18,13 @@
 
 #define QSEECOM_KEY_ID_SIZE   32
 
-#define	QSEOS_RESULT_FAIL_LOAD_KS         -48
-#define	QSEOS_RESULT_FAIL_SAVE_KS         -49
-#define	QSEOS_RESULT_FAIL_MAX_KEYS        -50
-#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -51
-#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -52
-#define	QSEOS_RESULT_FAIL_KS_OP           -53
-#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -54
+#define	QSEOS_RESULT_FAIL_LOAD_KS         -57
+#define	QSEOS_RESULT_FAIL_SAVE_KS         -58
+#define	QSEOS_RESULT_FAIL_MAX_KEYS        -59
+#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -60
+#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -61
+#define	QSEOS_RESULT_FAIL_KS_OP           -62
+#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63
 
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
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/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index a5e04cd..7b1a4c3 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -952,8 +952,8 @@
 static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
 {
 	struct subsys_device *subsys_dev = subsys;
-	pr_info("Error ready interrupt occured for %s\n",
-		 subsys_dev->desc->name);
+	dev_info(subsys_dev->desc->dev,
+		"Subsystem error monitoring/handling services are up\n");
 
 	if (subsys_dev->desc->is_not_loadable)
 		return IRQ_HANDLED;
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/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 5ad2394..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.
@@ -544,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;
 }
 
@@ -1799,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++;
@@ -1834,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);
 
@@ -2714,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);
 	}
@@ -2905,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));
 
@@ -3300,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;
@@ -3320,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
@@ -3352,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],
@@ -3387,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;
 
@@ -3463,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)
 {
@@ -3560,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;
@@ -3588,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
@@ -3618,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 782209d..531a77c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -247,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)
@@ -285,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);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d12853f..70223db 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -66,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));
 
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_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_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/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/mmc/core/bus.c b/drivers/mmc/core/bus.c
index ac2ecbb..a990f43 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -128,6 +128,16 @@
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
+	if (!drv) {
+		pr_debug("%s: %s: drv is NULL\n", dev_name(dev), __func__);
+		return;
+	}
+
+	if (!card) {
+		pr_debug("%s: %s: card is NULL\n", dev_name(dev), __func__);
+		return;
+	}
+
 	if (drv->shutdown)
 		drv->shutdown(card);
 }
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/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 0d77741..8e79185 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -278,7 +278,8 @@
 					A2_MUX_COMPLETION_TIMEOUT);
 		a2_mux_ctx->wait_for_ack = 0;
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout previous ack\n", __func__);
+			IPAERR("%s previous ack from modem timed out\n",
+				__func__);
 			goto bail;
 		}
 	}
@@ -288,7 +289,7 @@
 	ret = wait_for_completion_timeout(&a2_mux_ctx->ul_wakeup_ack_completion,
 					A2_MUX_COMPLETION_TIMEOUT);
 	if (unlikely(ret == 0)) {
-		IPADBG("%s timeout wakeup ack\n", __func__);
+		IPAERR("%s wakup ack from modem timed out\n", __func__);
 		goto bail;
 	}
 	INIT_COMPLETION(a2_mux_ctx->bam_connection_completion);
@@ -297,7 +298,7 @@
 			&a2_mux_ctx->bam_connection_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout power on\n", __func__);
+			IPAERR("%s modem power on timed out\n", __func__);
 			goto bail;
 		}
 	}
@@ -450,7 +451,8 @@
 			&a2_mux_ctx->dl_wakeup_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPAERR("%s timeout A2 PROD\n", __func__);
+			IPAERR("%s timeout waiting for A2 PROD granted\n",
+				__func__);
 			BUG();
 			return;
 		}
@@ -475,8 +477,8 @@
 			&a2_mux_ctx->request_resource_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout request A2 PROD resource\n",
-				     __func__);
+			IPAERR("%s timeout waiting for A2 PROD granted\n",
+				__func__);
 			BUG();
 			return;
 		}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 67c86b9..1cbd514 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,7 +50,6 @@
 #define IPA_AGGR_STR_IN_BYTES(str) \
 	(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
 
-
 static struct ipa_plat_drv_res ipa_res = {0, };
 static struct of_device_id ipa_plat_drv_match[] = {
 	{
@@ -197,6 +196,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 +640,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;
 }
 
@@ -1730,6 +1734,22 @@
 		result = -ENOMEM;
 		goto fail_rt_tbl_cache;
 	}
+	ipa_ctx->tx_pkt_wrapper_cache =
+	   kmem_cache_create("IPA TX PKT WRAPPER",
+			   sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
+	if (!ipa_ctx->tx_pkt_wrapper_cache) {
+		IPAERR(":ipa tx pkt wrapper cache create failed\n");
+		result = -ENOMEM;
+		goto fail_tx_pkt_wrapper_cache;
+	}
+	ipa_ctx->rx_pkt_wrapper_cache =
+	   kmem_cache_create("IPA RX PKT WRAPPER",
+			   sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
+	if (!ipa_ctx->rx_pkt_wrapper_cache) {
+		IPAERR(":ipa rx pkt wrapper cache create failed\n");
+		result = -ENOMEM;
+		goto fail_rx_pkt_wrapper_cache;
+	}
 	ipa_ctx->tree_node_cache =
 	   kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
 			   NULL);
@@ -1798,8 +1818,6 @@
 	mutex_init(&ipa_ctx->lock);
 	mutex_init(&ipa_ctx->nat_mem.lock);
 
-	skb_queue_head_init(&ipa_ctx->rx_list);
-
 	for (i = 0; i < IPA_A5_SYS_MAX; i++) {
 		INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
 		spin_lock_init(&ipa_ctx->sys[i].spinlock);
@@ -1813,15 +1831,15 @@
 			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
 	}
 
-	ipa_ctx->rx_wq = alloc_workqueue("ipa rx wq", WQ_MEM_RECLAIM |
-			WQ_CPU_INTENSIVE, 1);
+	ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
 	if (!ipa_ctx->rx_wq) {
 		IPAERR(":fail to create rx wq\n");
 		result = -ENOMEM;
 		goto fail_rx_wq;
 	}
 
-	ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+	ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+			WQ_CPU_INTENSIVE, 2);
 	if (!ipa_ctx->tx_wq) {
 		IPAERR(":fail to create tx wq\n");
 		result = -ENOMEM;
@@ -1974,6 +1992,10 @@
 fail_dma_pool:
 	kmem_cache_destroy(ipa_ctx->tree_node_cache);
 fail_tree_node_cache:
+	kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
+fail_rx_pkt_wrapper_cache:
+	kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
+fail_tx_pkt_wrapper_cache:
 	kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
 fail_rt_tbl_cache:
 	kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index ae59f37..5c343e8 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/delay.h>
 #include "ipa_i.h"
 
@@ -251,26 +250,6 @@
 
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 
-	if (IPA_CLIENT_IS_CONS(in->client)) {
-		ep->cmd = kzalloc(sizeof(struct ipa_ip_packet_init),
-				GFP_KERNEL);
-		if (!ep->cmd) {
-			IPAERR("failed to alloc immediate command object\n");
-			result = -ENOMEM;
-			goto fail;
-		}
-		ep->cmd->destination_pipe_index = ipa_ep_idx;
-		ep->dma_addr = dma_map_single(NULL, ep->cmd,
-				sizeof(struct ipa_ip_packet_init),
-				DMA_TO_DEVICE);
-		if (ep->dma_addr == 0 || ep->dma_addr == ~0) {
-			IPAERR("failed to DMA MAP pkt_init\n");
-			result = -ENOMEM;
-			kfree(ep->cmd);
-			goto fail;
-		}
-	}
-
 	ep->valid = 1;
 	ep->client = in->client;
 	ep->client_notify = in->notify;
@@ -447,13 +426,6 @@
 		return -EPERM;
 	}
 
-	if (IPA_CLIENT_IS_CONS(ep->client)) {
-		dma_unmap_single(NULL, ep->dma_addr,
-				sizeof(struct ipa_ip_packet_init),
-				DMA_TO_DEVICE);
-		kfree(ep->cmd);
-	}
-
 	ipa_enable_data_path(clnt_hdl);
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index c564922..ba81e5d 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -17,23 +17,21 @@
 #include <linux/netdevice.h>
 #include "ipa_i.h"
 
+
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
+#define IPA_LAST_DESC_CNT 0xFFFF
 #define POLLING_INACTIVITY_RX 40
-#define POLLING_MIN_SLEEP_RX 2350
-#define POLLING_MAX_SLEEP_RX 2450
-#define POLLING_INACTIVITY_TX 10
-#define POLLING_MIN_SLEEP_TX 100
-#define POLLING_MAX_SLEEP_TX 200
-#define RX_MAX_IND 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
 
 static void replenish_rx_work_func(struct work_struct *work);
 static struct delayed_work replenish_rx_work;
 static void ipa_wq_handle_rx(struct work_struct *work);
 static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
-static void ipa_wq_handle_tx(struct work_struct *work);
-static DECLARE_WORK(tx_work, ipa_wq_handle_tx);
-
 /**
  * ipa_write_done() - this function will be (eventually) called when a Tx
  * operation is complete
@@ -83,7 +81,7 @@
 	if (tx_pkt->callback)
 		tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
 
-	kfree(tx_pkt);
+	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 }
 
 int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
@@ -121,13 +119,23 @@
 
 		IPADBG("--curr_cnt=%d\n", sys->len);
 
-		if (tx_pkt->callback) {
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+			dma_pool_free(ipa_ctx->dma_pool,
+					tx_pkt->bounce,
+					tx_pkt->mem.phys_base);
+		else
 			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
-					tx_pkt->mem.size, DMA_TO_DEVICE);
-			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
-		}
+					tx_pkt->mem.size,
+					DMA_TO_DEVICE);
 
-		kfree(tx_pkt);
+		if (tx_pkt->callback)
+			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+		if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+			dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+					tx_pkt->mult.phys_base);
+
+		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 		cnt++;
 	};
 
@@ -146,6 +154,11 @@
 		goto fail;
 	}
 
+	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_get_config() failed %d\n", ret);
+		goto fail;
+	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -192,7 +205,9 @@
 
 static void ipa_wq_handle_tx(struct work_struct *work)
 {
-	ipa_handle_tx(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT]);
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+	ipa_handle_tx(tx_pkt->sys);
 }
 
 /**
@@ -225,7 +240,7 @@
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
 
-	tx_pkt = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), mem_flag);
+	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
 	if (!tx_pkt) {
 		IPAERR("failed to alloc tx wrapper\n");
 		goto fail_mem_alloc;
@@ -281,11 +296,14 @@
 		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
 				desc->opcode, desc->len, sps_flags);
 		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	} else {
 		len = desc->len;
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 	}
 
-	INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+	if (unlikely(ipa_ctx->polling_mode))
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -309,12 +327,192 @@
 	else
 		dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
 fail_dma_map:
-	kfree(tx_pkt);
+	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 fail_mem_alloc:
 	return -EFAULT;
 }
 
 /**
+ * ipa_send() - Send multiple descriptors in one HW transaction
+ * @sys: system pipe context
+ * @num_desc: number of packets
+ * @desc: packets to send (may be immediate command or data)
+ * @in_atomic:  whether caller is in atomic context
+ *
+ * This function is used for system-to-bam connection.
+ * - SPS driver expect struct sps_transfer which will contain all the data
+ *   for a transaction
+ * - The sps_transfer struct will be pointing to bounce buffers for
+ *   its DMA command (immediate command and data)
+ * - ipa_tx_pkt_wrapper will be used for each ipa
+ *   descriptor (allocated from wrappers cache)
+ * - The wrapper struct will be configured for each ipa-desc payload and will
+ *   contain information which will be later used by the user callbacks
+ * - each transfer will be made by calling to sps_transfer()
+ * - Each packet (command or data) that will be sent will also be saved in
+ *   ipa_sys_context for later check that all data was sent
+ *
+ * Return codes: 0: success, -EFAULT: failure
+ */
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+		bool in_atomic)
+{
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	struct ipa_tx_pkt_wrapper *next_pkt;
+	struct sps_transfer transfer = { 0 };
+	struct sps_iovec *iovec;
+	unsigned long irq_flags;
+	dma_addr_t dma_addr;
+	int i = 0;
+	int j;
+	int result;
+	int fail_dma_wrap = 0;
+	uint size = num_desc * sizeof(struct sps_iovec);
+	u32 mem_flag = GFP_ATOMIC;
+
+	if (unlikely(!in_atomic))
+		mem_flag = GFP_KERNEL;
+
+	transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
+	transfer.iovec_phys = dma_addr;
+	transfer.iovec_count = num_desc;
+	spin_lock_irqsave(&sys->spinlock, irq_flags);
+	if (!transfer.iovec) {
+		IPAERR("fail to alloc DMA mem for sps xfr buff\n");
+		goto failure_coherent;
+	}
+
+	for (i = 0; i < num_desc; i++) {
+		fail_dma_wrap = 0;
+		tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
+					   mem_flag);
+		if (!tx_pkt) {
+			IPAERR("failed to alloc tx wrapper\n");
+			goto failure;
+		}
+		/*
+		 * first desc of set is "special" as it holds the count and
+		 * other info
+		 */
+		if (i == 0) {
+			transfer.user = tx_pkt;
+			tx_pkt->mult.phys_base = dma_addr;
+			tx_pkt->mult.base = transfer.iovec;
+			tx_pkt->mult.size = size;
+			tx_pkt->cnt = num_desc;
+			INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+		}
+
+		iovec = &transfer.iovec[i];
+		iovec->flags = 0;
+
+		INIT_LIST_HEAD(&tx_pkt->link);
+		tx_pkt->type = desc[i].type;
+
+		tx_pkt->mem.base = desc[i].pyld;
+		tx_pkt->mem.size = desc[i].len;
+
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+			WARN_ON(tx_pkt->mem.size > 512);
+
+			/*
+			 * Due to a HW limitation, we need to make sure that the
+			 * packet does not cross a 1KB boundary
+			 */
+			tx_pkt->bounce =
+			   dma_pool_alloc(ipa_ctx->dma_pool,
+					   mem_flag,
+					   &tx_pkt->mem.phys_base);
+			if (!tx_pkt->bounce) {
+				tx_pkt->mem.phys_base = 0;
+			} else {
+				WARN_ON(!ipa_straddle_boundary(
+						(u32)tx_pkt->mem.phys_base,
+						(u32)tx_pkt->mem.phys_base +
+						tx_pkt->mem.size - 1, 1024));
+				memcpy(tx_pkt->bounce, tx_pkt->mem.base,
+						tx_pkt->mem.size);
+			}
+		} else {
+			tx_pkt->mem.phys_base =
+			   dma_map_single(NULL, tx_pkt->mem.base,
+					   tx_pkt->mem.size,
+					   DMA_TO_DEVICE);
+		}
+		if (!tx_pkt->mem.phys_base) {
+			IPAERR("failed to alloc tx wrapper\n");
+			fail_dma_wrap = 1;
+			goto failure;
+		}
+
+		tx_pkt->sys = sys;
+		tx_pkt->callback = desc[i].callback;
+		tx_pkt->user1 = desc[i].user1;
+		tx_pkt->user2 = desc[i].user2;
+
+		/*
+		 * Point the iovec to the bounce buffer and
+		 * add this packet to system pipe context.
+		 */
+		iovec->addr = tx_pkt->mem.phys_base;
+		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+
+		/*
+		 * Special treatment for immediate commands, where the structure
+		 * of the descriptor is different
+		 */
+		if (desc[i].type == IPA_IMM_CMD_DESC) {
+			iovec->size = desc[i].opcode;
+			iovec->flags |= SPS_IOVEC_FLAG_IMME;
+		} else {
+			iovec->size = desc[i].len;
+		}
+
+		if (i == (num_desc - 1)) {
+			iovec->flags |= SPS_IOVEC_FLAG_EOT;
+			/* "mark" the last desc */
+			tx_pkt->cnt = IPA_LAST_DESC_CNT;
+		}
+	}
+
+	result = sps_transfer(sys->ep->ep_hdl, &transfer);
+	if (result) {
+		IPAERR("sps_transfer failed rc=%d\n", result);
+		goto failure;
+	}
+
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	return 0;
+
+failure:
+	tx_pkt = transfer.user;
+	for (j = 0; j < i; j++) {
+		next_pkt = list_next_entry(tx_pkt, link);
+		list_del(&tx_pkt->link);
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+			dma_pool_free(ipa_ctx->dma_pool,
+					tx_pkt->bounce,
+					tx_pkt->mem.phys_base);
+		else
+			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+					tx_pkt->mem.size,
+					DMA_TO_DEVICE);
+		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+		tx_pkt = next_pkt;
+	}
+	if (i < num_desc)
+		/* last desc failed */
+		if (fail_dma_wrap)
+			kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+	if (transfer.iovec_phys)
+		dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
+				  transfer.iovec_phys);
+failure_coherent:
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	return -EFAULT;
+}
+
+/**
  * ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
  * immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
@@ -345,6 +543,7 @@
  */
 int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
 {
+	struct ipa_desc *desc;
 	int result = 0;
 
 	ipa_inc_client_enable_clks();
@@ -364,10 +563,22 @@
 		}
 		wait_for_completion(&descr->xfer_done);
 	} else {
-		IPAERR("unsupported chaining multiple IC\n");
+		desc = &descr[num_desc - 1];
+		init_completion(&desc->xfer_done);
+
+		if (desc->callback || desc->user1)
+			WARN_ON(1);
+
+		desc->callback = ipa_sps_irq_cmd_ack;
+		desc->user1 = desc;
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
+					descr, false)) {
+			IPAERR("fail to send multiple immediate command set\n");
 			result = -EFAULT;
 			goto bail;
 		}
+		wait_for_completion(&desc->xfer_done);
+	}
 
 	IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
 bail:
@@ -386,13 +597,21 @@
 static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
 {
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+	struct ipa_tx_pkt_wrapper *tx_pkt;
 	int ret;
 
 	IPADBG("event %d notified\n", notify->event_id);
 
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
+		tx_pkt = notify->data.transfer.user;
 		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -402,7 +621,7 @@
 				break;
 			}
 			atomic_set(&sys->curr_polling_state, 1);
-			queue_work(ipa_ctx->tx_wq, &tx_work);
+			queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
 		}
 		break;
 	default:
@@ -435,47 +654,6 @@
 	}
 }
 
-static void ipa_handle_tag_rsp(struct ipa_a5_mux_hdr *mux_hdr)
-{
-	struct completion *compl;
-	struct ipa_tree_node *node;
-
-	/* retrieve the compl object from tag value */
-	mux_hdr++;
-	compl = (struct completion *) ntohl(*((u32 *)mux_hdr));
-	IPADBG("%x %x %p\n", *(u32 *)mux_hdr, *((u32 *)mux_hdr + 1), compl);
-
-	mutex_lock(&ipa_ctx->lock);
-	node = ipa_search(&ipa_ctx->tag_tree, (u32)compl);
-	if (node) {
-		complete_all(compl);
-		rb_erase(&node->node, &ipa_ctx->tag_tree);
-		kmem_cache_free(ipa_ctx->tree_node_cache, node);
-	} else {
-		WARN_ON(1);
-	}
-	mutex_unlock(&ipa_ctx->lock);
-}
-
-static void ipa_dejitter(bool limit)
-{
-	struct sk_buff *skb;
-	int len = skb_queue_len(&ipa_ctx->rx_list);
-	int i;
-	void *cookie;
-	ipa_notify_cb cb;
-
-	if (limit && len >= RX_MAX_IND)
-		len = RX_MAX_IND;
-
-	for (i = len; i > 0; i--) {
-		skb = __skb_dequeue(&ipa_ctx->rx_list);
-		cb = (ipa_notify_cb)*(u32 *)&(skb->cb[0]);
-		cookie = (void *)*(u32 *)&(skb->cb[4]);
-		cb(cookie, IPA_RECEIVE, (unsigned long)skb);
-	}
-}
-
 /**
  * ipa_handle_rx_core() - The core functionality of packet reception. This
  * function is read from multiple code paths.
@@ -497,9 +675,13 @@
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	struct sk_buff *rx_skb;
 	struct sps_iovec iov;
+	unsigned int pull_len;
+	unsigned int padding;
 	int ret;
 	struct ipa_ep_context *ep;
 	int cnt = 0;
+	struct completion *compl;
+	struct ipa_tree_node *node;
 	unsigned int src_pipe;
 
 	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
@@ -539,7 +721,7 @@
 		rx_skb->tail = rx_skb->data + rx_pkt->len;
 		rx_skb->len = rx_pkt->len;
 		rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
-		kfree(rx_pkt);
+		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 
 		mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
 
@@ -554,9 +736,29 @@
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
 		IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
 
-		if (mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG) {
-			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL)
-				ipa_handle_tag_rsp(mux_hdr);
+		if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
+			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
+				/* retrieve the compl object from tag value */
+				mux_hdr++;
+				compl = (struct completion *)
+					ntohl(*((u32 *)mux_hdr));
+				IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
+						*((u32 *)mux_hdr + 1), compl);
+
+				mutex_lock(&ipa_ctx->lock);
+				node = ipa_search(&ipa_ctx->tag_tree,
+						(u32)compl);
+				if (node) {
+					complete_all(compl);
+					rb_erase(&node->node,
+							&ipa_ctx->tag_tree);
+					kmem_cache_free(
+						ipa_ctx->tree_node_cache, node);
+				} else {
+					WARN_ON(1);
+				}
+				mutex_unlock(&ipa_ctx->lock);
+			}
 			dev_kfree_skb(rx_skb);
 			ipa_replenish_rx_cache();
 			++cnt;
@@ -567,22 +769,38 @@
 		 * Any packets arriving over AMPDU_TX should be dispatched
 		 * to the regular WLAN RX data-path.
 		 */
-		if (src_pipe == WLAN_AMPDU_TX_EP)
+		if (unlikely(src_pipe == WLAN_AMPDU_TX_EP))
 			src_pipe = WLAN_PROD_TX_EP;
 
-		WARN_ON(src_pipe >= IPA_NUM_PIPES);
+		if (unlikely(src_pipe >= IPA_NUM_PIPES ||
+			!ipa_ctx->ep[src_pipe].valid ||
+			!ipa_ctx->ep[src_pipe].client_notify)) {
+			IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
+			  src_pipe, ipa_ctx->ep[src_pipe].valid,
+			  ipa_ctx->ep[src_pipe].client_notify);
+			dev_kfree_skb(rx_skb);
+			ipa_replenish_rx_cache();
+			++cnt;
+			continue;
+		}
 
 		ep = &ipa_ctx->ep[src_pipe];
-		IPADBG("pulling %d bytes from skb\n", ep->pull_len);
-		skb_pull(rx_skb, ep->pull_len);
+		pull_len = sizeof(struct ipa_a5_mux_hdr);
+
+		/*
+		 * IP packet starts on word boundary
+		 * remove the MUX header and any padding and pass the frame to
+		 * the client which registered a rx callback on the "src pipe"
+		 */
+		padding = ep->cfg.hdr.hdr_len & 0x3;
+		if (padding)
+			pull_len += 4 - padding;
+
+		IPADBG("pulling %d bytes from skb\n", pull_len);
+		skb_pull(rx_skb, pull_len);
 		ipa_replenish_rx_cache();
-		if (ep->client_notify) {
-			__skb_queue_tail(&ipa_ctx->rx_list, rx_skb);
-			*(u32 *)&(rx_skb->cb[0]) = (u32)ep->client_notify;
-			*(u32 *)&(rx_skb->cb[4]) = (u32)ep->priv;
-		} else {
-			dev_kfree_skb(rx_skb);
-		}
+		ep->client_notify(ep->priv, IPA_RECEIVE,
+				(unsigned long)(rx_skb));
 		cnt++;
 	};
 
@@ -601,6 +819,11 @@
 		goto fail;
 	}
 
+	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_get_config() failed %d\n", ret);
+		goto fail;
+	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -647,6 +870,12 @@
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
 		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -696,10 +925,8 @@
 		} else {
 			inactive_cycles = 0;
 		}
-		ipa_dejitter(true);
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
-	ipa_dejitter(false);
 	ipa_rx_switch_to_intr_mode(sys);
 	ipa_dec_client_disable_clks();
 }
@@ -835,7 +1062,6 @@
 		break;
 	case 2:
 		sys_idx = ipa_ep_idx;
-		ipa_ctx->sys[sys_idx].max_len = sys_in->desc_fifo_sz / 8 - 2;
 		INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
 				switch_to_intr_tx_work_func);
 		break;
@@ -950,87 +1176,9 @@
 		dev_kfree_skb(skb);
 }
 
-static int ipa_send_two(struct sk_buff *skb, struct ipa_sys_context *sys,
-		int dst_ep_idx)
+static void ipa_tx_cmd_comp(void *user1, void *user2)
 {
-	struct ipa_tx_pkt_wrapper *tx_pktc;
-	struct ipa_tx_pkt_wrapper *tx_pktd;
-	struct ipa_ep_context *ep = &ipa_ctx->ep[dst_ep_idx];
-	unsigned long irq_flags;
-	dma_addr_t dma_addrd;
-	int rc = -ENOMEM;
-
-	tx_pktc = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
-	if (!tx_pktc) {
-		IPAERR("failed to alloc tx wrapper C\n");
-		goto fail_mem_alloc_c;
-	}
-
-	tx_pktd = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
-	if (!tx_pktd) {
-		IPAERR("failed to alloc tx wrapper D\n");
-		goto fail_mem_alloc_d;
-	}
-
-	dma_addrd = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
-	if (!dma_addrd) {
-		IPAERR("failed to DMA wrap\n");
-		goto fail_dma_map_d;
-	}
-
-	INIT_LIST_HEAD(&tx_pktc->link);
-	tx_pktc->callback = NULL;
-
-	INIT_LIST_HEAD(&tx_pktd->link);
-	tx_pktd->mem.phys_base = dma_addrd;
-	tx_pktd->mem.base = skb->data;
-	tx_pktd->mem.size = skb->len;
-	tx_pktd->callback = ipa_tx_comp_usr_notify_release;
-	tx_pktd->user1 = skb;
-	tx_pktd->user2 = (void *)dst_ep_idx;
-
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
-	if (sys->len >= sys->max_len)
-		goto fail_oom;
-	list_add_tail(&tx_pktc->link, &sys->head_desc_list);
-	if (sps_transfer_one(sys->ep->ep_hdl, ep->dma_addr, IPA_IP_PACKET_INIT,
-			tx_pktc, SPS_IOVEC_FLAG_IMME |
-			SPS_IOVEC_FLAG_NO_SUBMIT))
-		IPAERR("sps_transfer_one 0 failed\n");
-	list_add_tail(&tx_pktd->link, &sys->head_desc_list);
-	if (sps_transfer_one(sys->ep->ep_hdl, dma_addrd, skb->len, tx_pktd,
-			SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT))
-		IPAERR("sps_transfer_one 1 failed\n");
-	sys->len += 2;
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-	return 0;
-
-fail_oom:
-	dma_unmap_single(NULL, dma_addrd, skb->len, DMA_TO_DEVICE);
-fail_dma_map_d:
-	kfree(tx_pktd);
-fail_mem_alloc_d:
-	kfree(tx_pktc);
-fail_mem_alloc_c:
-	return rc;
-}
-
-static int ipa_send_data_hw_path(struct sk_buff *skb,
-		struct ipa_sys_context *sys, int dst_ep_idx)
-{
-	struct ipa_desc desc;
-
-	desc.pyld = skb->data;
-	desc.len = skb->len;
-	desc.type = IPA_DATA_DESC_SKB;
-	desc.callback = ipa_tx_comp_usr_notify_release;
-	desc.user1 = skb;
-	desc.user2 = (void *)dst_ep_idx;
-
-	if (ipa_send_one(sys, &desc, true))
-		return -EFAULT;
-
-	return 0;
+	kfree(user1);
 }
 
 /**
@@ -1063,42 +1211,76 @@
 int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
 		struct ipa_tx_meta *meta)
 {
+	struct ipa_desc desc[2];
 	int ipa_ep_idx;
+	struct ipa_ip_packet_init *cmd;
+
+	memset(&desc, 0, 2 * sizeof(struct ipa_desc));
 
 	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
 	if (unlikely(ipa_ep_idx == -1)) {
 		IPAERR("dest EP does not exist.\n");
-		goto fail;
+		goto fail_gen;
 	}
 
 	if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
 		IPAERR("dest EP not valid.\n");
-		goto fail;
+		goto fail_gen;
 	}
 
 	if (IPA_CLIENT_IS_CONS(dst)) {
-		if (ipa_send_two(skb, &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT],
-					ipa_ep_idx)) {
-			IPAERR("fail to send pkt_init+skb dst=%d skb=%p\n",
-					dst, skb);
-			goto fail;
+		cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
+		if (!cmd) {
+			IPAERR("failed to alloc immediate command object\n");
+			goto fail_mem_alloc;
+		}
+
+		cmd->destination_pipe_index = ipa_ep_idx;
+		if (meta && meta->mbim_stream_id_valid)
+			cmd->metadata = meta->mbim_stream_id;
+		desc[0].opcode = IPA_IP_PACKET_INIT;
+		desc[0].pyld = cmd;
+		desc[0].len = sizeof(struct ipa_ip_packet_init);
+		desc[0].type = IPA_IMM_CMD_DESC;
+		desc[0].callback = ipa_tx_cmd_comp;
+		desc[0].user1 = cmd;
+		desc[1].pyld = skb->data;
+		desc[1].len = skb->len;
+		desc[1].type = IPA_DATA_DESC_SKB;
+		desc[1].callback = ipa_tx_comp_usr_notify_release;
+		desc[1].user1 = skb;
+		desc[1].user2 = (void *)ipa_ep_idx;
+
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
+					true)) {
+			IPAERR("fail to send immediate command\n");
+			goto fail_send;
 		}
 		IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
 	} else if (dst == IPA_CLIENT_A5_WLAN_AMPDU_PROD) {
-		if (ipa_send_data_hw_path(skb,
-					&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
-					ipa_ep_idx)) {
-			IPAERR("fail to send skb dst=%d skb=%p\n", dst, skb);
-			goto fail;
+		desc[0].pyld = skb->data;
+		desc[0].len = skb->len;
+		desc[0].type = IPA_DATA_DESC_SKB;
+		desc[0].callback = ipa_tx_comp_usr_notify_release;
+		desc[0].user1 = skb;
+		desc[0].user2 = (void *)ipa_ep_idx;
+
+		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
+					&desc[0], true)) {
+			IPAERR("fail to send skb\n");
+			goto fail_gen;
 		}
 	} else {
 		IPAERR("%d PROD is not supported.\n", dst);
-		goto fail;
+		goto fail_gen;
 	}
 
 	return 0;
 
-fail:
+fail_send:
+	kfree(cmd);
+fail_mem_alloc:
+fail_gen:
 	return -EFAULT;
 }
 EXPORT_SYMBOL(ipa_tx_dp);
@@ -1134,7 +1316,8 @@
 	rx_len_cached = sys->len;
 
 	while (rx_len_cached < IPA_RX_POOL_CEIL) {
-		rx_pkt = kmalloc(sizeof(struct ipa_rx_pkt_wrapper), flag);
+		rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
+					   flag);
 		if (!rx_pkt) {
 			IPAERR("failed to alloc rx wrapper\n");
 			goto fail_kmem_cache_alloc;
@@ -1182,7 +1365,7 @@
 fail_dma_mapping:
 	dev_kfree_skb(rx_pkt->skb);
 fail_skb_alloc:
-	kfree(rx_pkt);
+	kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 fail_kmem_cache_alloc:
 	if (rx_len_cached == 0) {
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
@@ -1214,7 +1397,7 @@
 		dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_FROM_DEVICE);
 		dev_kfree_skb(rx_pkt->skb);
-		kfree(rx_pkt);
+		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 	}
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 790898a..8ad0b5a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -119,7 +119,6 @@
 #define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
 #define IPA_INVALID_L4_PROTOCOL 0xFF
 
-
 #define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
 #define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
 #define IPA_SETFIELD(val, shift, mask) (((val) << (shift)) & (mask))
@@ -364,9 +363,6 @@
 	bool desc_fifo_client_allocated;
 	bool data_fifo_client_allocated;
 	bool suspended;
-	unsigned int pull_len;
-	struct ipa_ip_packet_init *cmd;
-	dma_addr_t dma_addr;
 };
 
 /**
@@ -382,7 +378,6 @@
 struct ipa_sys_context {
 	struct list_head head_desc_list;
 	u32 len;
-	u32 max_len;
 	spinlock_t spinlock;
 	struct sps_register_event event;
 	struct ipa_ep_context *ep;
@@ -641,6 +636,8 @@
 	struct kmem_cache *hdr_cache;
 	struct kmem_cache *hdr_offset_cache;
 	struct kmem_cache *rt_tbl_cache;
+	struct kmem_cache *tx_pkt_wrapper_cache;
+	struct kmem_cache *rx_pkt_wrapper_cache;
 	struct kmem_cache *tree_node_cache;
 	unsigned long rt_idx_bitmap[IPA_IP_MAX];
 	struct mutex lock;
@@ -687,7 +684,6 @@
 	/* featurize if memory footprint becomes a concern */
 	struct ipa_stats stats;
 	void *smem_pipe_mem;
-	struct sk_buff_head rx_list;
 };
 
 /**
@@ -776,6 +772,8 @@
 		u32 *consumer_handle);
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
 		bool in_atomic);
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+		bool in_atomic);
 int ipa_get_ep_mapping(enum ipa_operating_mode mode,
 		       enum ipa_client_type client);
 int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 912d93c..23de300 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -32,24 +32,6 @@
 	{ 19, -1, -1, -1, -1, 11, 15, 8, 6, 2, 1, 5, 14, 16, 17, 18, -1, 10, 9, 7, 3, 4 },
 };
 
-static unsigned int ipa_calc_pull_len(u32 hdr_len)
-{
-	unsigned int pull_len, padding;
-
-	pull_len = sizeof(struct ipa_a5_mux_hdr);
-
-	/*
-	 * IP packet starts on word boundary
-	 * remove the MUX header and any padding and pass the frame to
-	 * the client which registered a rx callback on the "src pipe"
-	 */
-	padding = hdr_len & 0x3;
-	if (padding)
-		pull_len += 4 - padding;
-
-	return pull_len;
-}
-
 /**
  * ipa_cfg_route() - configure IPA route
  * @route: IPA route
@@ -769,9 +751,6 @@
 		ipa_write_reg(ipa_ctx->mmio,
 			IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
 
-	if (IPA_CLIENT_IS_PROD(ep->client))
-		ep->pull_len = ipa_calc_pull_len(ipa_ep_cfg->hdr_len);
-
 	return 0;
 }
 EXPORT_SYMBOL(ipa_cfg_ep_hdr);
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/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 6a8ba46..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;
 	}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 1a4c3f3..53aa475 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -14,6 +14,7 @@
  * SPI driver for Qualcomm MSM platforms
  *
  */
+
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -43,6 +44,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 +203,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 +1458,7 @@
 		}
 
 		if (tr->cs_change &&
-		   ((bpw != 8) || (bpw != 16) || (bpw != 32)))
+		   ((bpw != 8) && (bpw != 16) && (bpw != 32)))
 			return false;
 	}
 
@@ -2359,49 +2533,148 @@
 	return 0;
 }
 
-/**
- * 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)
+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: create pdata and read gpio config from device tree
+ */
+struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
+			struct platform_device *pdev, struct msm_spi *dd)
+{
+	int i;
 	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},
+		{"qcom,gpio-clk",
+			&dd->spi_gpios[0],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-miso",
+			&dd->spi_gpios[1],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-mosi",
+			&dd->spi_gpios[2],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs0",
+			&dd->cs_gpios[0].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs1",
+			&dd->cs_gpios[1].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs2",
+			&dd->cs_gpios[2].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs3",
+			&dd->cs_gpios[3].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{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;
 		}
 	}
+
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+		dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
+
 	return pdata;
 }
 
@@ -2461,7 +2734,6 @@
 	int                     clk_enabled = 0;
 	int                     pclk_enabled = 0;
 	struct msm_spi_platform_data *pdata;
-	enum of_gpio_flags flags;
 
 	master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
 	if (!master) {
@@ -2481,7 +2753,7 @@
 	if (pdev->dev.of_node) {
 		dd->qup_ver = SPI_QUP_VERSION_BFAM;
 		master->dev.of_node = pdev->dev.of_node;
-		pdata = msm_spi_dt_to_pdata(pdev);
+		pdata = msm_spi_dt_to_pdata(pdev, dd);
 		if (!pdata) {
 			rc = -ENOMEM;
 			goto err_probe_exit;
@@ -2493,18 +2765,6 @@
 				"using default bus_num %d\n", pdev->id);
 		else
 			master->bus_num = pdev->id = rc;
-
-		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
-			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
-								i, &flags);
-		}
-
-		for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
-			dd->cs_gpios[i].gpio_num = of_get_named_gpio_flags(
-						pdev->dev.of_node, "cs-gpios",
-						i, &flags);
-			dd->cs_gpios[i].valid = 0;
-		}
 	} else {
 		pdata = pdev->dev.platform_data;
 		dd->qup_ver = SPI_QUP_VERSION_NONE;
@@ -2808,6 +3068,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 +3120,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 +3183,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/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 3cad3ce..8d8c30e 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,8 @@
 
 #define MSM_USB_BASE	(udc->regs)
 
+#define CI13XXX_MSM_MAX_ITC_LEVEL	6
+
 struct ci13xxx_udc_context {
 	int irq;
 	void __iomem *regs;
@@ -177,7 +179,7 @@
 				  CI13XXX_ZERO_ITC |
 				  CI13XXX_DISABLE_STREAMING |
 				  CI13XXX_IS_OTG,
-
+	.nz_itc			= 0,
 	.notify_event		= ci13xxx_msm_notify_event,
 };
 
@@ -230,10 +232,21 @@
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	int ret;
+	int ret, rc;
+	int itc_level = 0;
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 
+	if (pdev->dev.of_node) {
+		rc = of_property_read_u32(pdev->dev.of_node, "qcom,itc-level",
+			&itc_level);
+		/* Acceptable values for nz_itc are: 0,1,2,4,8,16,32,64 */
+		if (itc_level > CI13XXX_MSM_MAX_ITC_LEVEL || rc)
+			ci13xxx_msm_udc_driver.nz_itc = 0;
+		else
+			ci13xxx_msm_udc_driver.nz_itc = 1 << itc_level;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get platform resource mem\n");
@@ -313,9 +326,18 @@
 	writel_relaxed(val, USB_GENCONFIG);
 }
 
+static const struct of_device_id ci13xx_msm_dt_match[] = {
+	{ .compatible = "qcom,ci13xxx_msm",
+	},
+	{}
+};
+
 static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
-	.driver = { .name = "msm_hsusb", },
+	.driver = {
+		.name = "msm_hsusb",
+		.of_match_table = ci13xx_msm_dt_match,
+	},
 	.remove = ci13xxx_msm_remove,
 };
 MODULE_ALIAS("platform:msm_hsusb");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 939eb6d..e7074a2 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -367,7 +367,10 @@
 	 * 8 micro frames. If CPU can handle interrupts at faster rate, ITC
 	 * can be set to lesser value to gain performance.
 	 */
-	if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
+	if (udc->udc_driver->nz_itc)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK,
+			USBCMD_ITC(udc->udc_driver->nz_itc));
+	else if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
 		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK, USBCMD_ITC(0));
 
 	if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 4c5b38d..09404c8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -129,6 +129,7 @@
 struct ci13xxx_udc_driver {
 	const char	*name;
 	unsigned long	 flags;
+	unsigned int nz_itc;
 #define CI13XXX_REGS_SHARED		BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
 #define CI13XXX_PULLUP_ON_VBUS		BIT(2)
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 9dd9978..edcafcc 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -848,6 +848,7 @@
 	d->rx_req->context = port;
 	d->rx_req->complete = gbam_endless_rx_complete;
 	d->rx_req->length = 0;
+	d->rx_req->no_interrupt = 1;
 	sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
 				 MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
 	d->rx_req->udc_priv = sps_params;
@@ -863,6 +864,7 @@
 	d->tx_req->context = port;
 	d->tx_req->complete = gbam_endless_tx_complete;
 	d->tx_req->length = 0;
+	d->tx_req->no_interrupt = 1;
 	sps_params = (MSM_SPS_MODE | d->dst_pipe_idx |
 				 MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
 	d->tx_req->udc_priv = sps_params;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 5c7e52f..d470edf 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -296,6 +296,7 @@
 	d->rx_req->context = port;
 	d->rx_req->complete = bam_data_endless_rx_complete;
 	d->rx_req->length = 0;
+	d->rx_req->no_interrupt = 1;
 	sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
 				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
 	d->rx_req->udc_priv = sps_params;
@@ -306,6 +307,7 @@
 	d->tx_req->context = port;
 	d->tx_req->complete = bam_data_endless_tx_complete;
 	d->tx_req->length = 0;
+	d->tx_req->no_interrupt = 1;
 	sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
 				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
 	d->tx_req->udc_priv = sps_params;
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index cbdd241..273fb54 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -437,5 +437,9 @@
 
 void msm_dsi_phy_off(unsigned char *ctrl_base)
 {
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x05f);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, 0x02);
 	MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_1, 0x7f);
+	MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0);
 }
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_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_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 5d7a0c9..963d3fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -288,7 +288,8 @@
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config);
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
-static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd);
+static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
+					struct mdss_ad_info **ad);
 static int pp_update_ad_input(struct msm_fb_data_type *mfd);
 static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
 static void pp_ad_cfg_write(struct mdss_ad_info *ad);
@@ -2548,7 +2549,7 @@
 				hist_info = &mdss_pp_res->dspp_hist[dspp_num];
 				mutex_lock(&hist_info->hist_mutex);
 				for (j = 0; j < HIST_V_SIZE; j++)
-					hist_concat[i] += hist_info->data[i];
+					hist_concat[j] += hist_info->data[j];
 				mutex_unlock(&hist_info->hist_mutex);
 			}
 			hist_data_addr = hist_concat;
@@ -2731,8 +2732,12 @@
 	}
 
 	mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
-	if (!mixer_num || mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_err("invalid mixer_num, %d", mixer_num);
+	if (!mixer_num) {
+		pr_debug("no mixers connected, %d", mixer_num);
+		return -EHOSTDOWN;
+	}
+	if (mixer_num > MDSS_AD_MAX_MIXERS) {
+		pr_warn("too many mixers, not supported, %d", mixer_num);
 		return ret;
 	}
 
@@ -2747,9 +2752,10 @@
 	return mixer_id[0];
 }
 
-static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd)
+static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
+					struct mdss_ad_info **ret_ad)
 {
-	int ad_num;
+	int ad_num, ret = 0;
 	struct mdss_data_type *mdata;
 	struct mdss_ad_info *ad = NULL;
 	mdata = mfd_to_mdata(mfd);
@@ -2757,11 +2763,15 @@
 	ad_num = mdss_ad_init_checks(mfd);
 	if (ad_num >= 0)
 		ad = &mdata->ad_cfgs[ad_num];
-	return ad;
+	else
+		ret = ad_num;
+	*ret_ad = ad;
+	return ret;
 }
 
 static int pp_update_ad_input(struct msm_fb_data_type *mfd)
 {
+	int ret;
 	struct mdss_ad_info *ad;
 	struct mdss_ad_input input;
 	struct mdss_mdp_ctl *ctl;
@@ -2772,7 +2782,9 @@
 	if (!ctl)
 		return -EINVAL;
 
-	ad = mdss_mdp_get_ad(mfd);
+	ret = mdss_mdp_get_ad(mfd, &ad);
+	if (ret)
+		return ret;
 	if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
 		return -EINVAL;
 
@@ -2795,9 +2807,9 @@
 	int lin_ret = -1, inv_ret = -1, ret = 0;
 	u32 ratio_temp, shift = 0;
 
-	ad = mdss_mdp_get_ad(mfd);
-	if (!ad)
-		return -EINVAL;
+	ret = mdss_mdp_get_ad(mfd, &ad);
+	if (ret)
+		return ret;
 
 	mutex_lock(&ad->lock);
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
@@ -2862,9 +2874,9 @@
 	struct mdss_mdp_ctl *ctl;
 	u32 bl;
 
-	ad = mdss_mdp_get_ad(mfd);
-	if (!ad)
-		return -EINVAL;
+	ret = mdss_mdp_get_ad(mfd, &ad);
+	if (ret)
+		return ret;
 
 	mutex_lock(&ad->lock);
 	if ((!PP_AD_STATE_IS_INITCFG(ad->state) &&
@@ -3074,9 +3086,9 @@
 	char __iomem *base;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
-	ad = mdss_mdp_get_ad(mfd);
-	if (!ad)
-		return -EINVAL;
+	ret = mdss_mdp_get_ad(mfd, &ad);
+	if (ret)
+		return ret;
 
 	base = ad->base;
 
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/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