Merge "msm: Enable CONFIG_DEBUG_SET_MODULE_RONX=y for targets"
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index ce797d3..8d1d46d 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -226,8 +226,9 @@
 		compatible = "qcom,coresight-hwevent";
 		reg = <0xfdf30018 0x80>,
 		      <0xf9011080 0x80>,
-		      <0xfd4ab160 0x80>;
-		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+		      <0xfd4ab160 0x80>,
+		      <0xfc401600 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
 
 		coresight-id = <29>;
 		coresight-name = "coresight-hwevent";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index a2503cd..c01193c 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -37,8 +37,10 @@
 MSM sensor node contains properties of camera sensor
 
 Required properties:
-- compatible : should be "qcom" followed by sensor name
+- compatible : should be manufacturer name followed by sensor name
     - "qcom,s5k3l1yx"
+    - "shinetech,gc0339"
+    - "shinetech,hi256"
 - reg : should contain i2c slave address of the device
 - qcom,slave-id : should contain i2c slave address, device id address
     and expected id read value
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
new file mode 100644
index 0000000..f70d90f
--- /dev/null
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -0,0 +1,28 @@
+Qualcomm QCA199x NFC NCI device
+
+Near Field Communication (NFC) device is based on NFC Controller Interface (NCI)
+
+Required properties:
+
+- compatible: "qcom,nfc-nci"
+- reg: NCI i2c slave address.
+- qcom,dis-gpio: specific gpio for hardware reset.
+- qcom,irq-gpio: specific gpio for read interrupt.
+- interrupt-parent: Should be phandle for the interrupt controller
+                    that services interrupts for this device.
+- interrupts: should contain the NFC interrupt. NFC has one read interrupt.
+- qcom,clk-gpio: pmic gpio on which bbclk2 signal is coming.
+
+Example:
+
+	i2c@f9925000 { /* BLSP1 QUP3 */
+	    nfc-nci@0e {
+	        compatible = "qcom,nfc-nci";
+		reg = <0x0e>;
+		qcom,irq-gpio = <&msmgpio 21 0x00>;
+		qcom,dis-gpio = <&msmgpio 20 0x00>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <21 0>;
+		qcom,clk-gpio = <&pm8226_gpios 3 0>;
+	    };
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index ebb3134..ac314ea 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -50,7 +50,10 @@
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
     - qcom,msm_bus,name
-    - qcom,msm_bus,num_cases
+    - qcom,msm_bus,num_cases - There are three valid cases for this: NONE, MAX
+		and MIN bandwidth votes. Minimum two cases must be defined for
+		both NONE and MAX votes. If MIN vote is different from NONE VOTE
+		then specify third case for MIN VOTE.
     - qcom,msm_bus,active_only
     - qcom,msm_bus,num_paths
     - qcom,msm_bus,vectors
@@ -76,6 +79,8 @@
 	HSPHY.
 - qcom,hsusb-log2-itc: value of 2^(log2_itc-1) will be used as the
 	interrupt threshold (ITC), when log2_itc is between 1 to 7.
+- qcom,hsusb-l1-supported: If present, the device supports l1 (Link power
+	management).
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 8fa9f4a..0ebbe63 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -40,6 +40,7 @@
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
 schindler	Schindler
+shinetech	Shine Tech Corporation, Ltd.
 sil	Silicon Image
 simtek
 sirf	SiRF Technology, Inc.
diff --git a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
new file mode 100644
index 0000000..25c1851
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -0,0 +1,107 @@
+/* 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 {
+	qcom,mdss_dsi_hx8394a_720p_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "hx8394a 720p video mode dsi panel";
+		status = "disable";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 25 0>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <59 60 79 10 2 7>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 4095>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <2>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x2d 0x1f>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
+						    20 00 01];
+		qcom,panel-phy-timingSettings = [8d 24 19 00 34 34
+						    1d 26 2a 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [00 00 b1 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+					     00 00 00 00 05 00 00 01 97 /* lane1 config */
+					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
+					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
+					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+		qcom,panel-on-cmds = [39 01 00 00 00 00 04
+						b9 ff 83 94
+					39 01 00 00 00 00 05
+						c7 00 10 00 10
+					39 01 00 00 00 00 02
+						bc 07
+					39 01 00 00 00 00 02
+						ba 13
+					39 01 00 00 00 00 10
+						b1 01 00 07 83 01
+						12 0f 32 38 29 29
+						50 02 00 00
+					39 01 00 00 00 00 07
+						b2 00 c8 09 05 00
+						71
+					39 01 00 00 00 00 02
+						cc 05
+					05 01 00 00 00 00 02 00 00
+					39 01 00 00 00 00 35
+						d5 00 00 00 00 0a
+						00 01 00 00 00 33
+						00 23 45 67 01 01
+						23 88 88 88 88 88
+						88 88 99 99 99 88
+						88 99 88 54 32 10
+						76 32 10 88 88 88
+						88 88 88 88 99 99
+						99 88 88 88 99
+					39 01 00 00 00 00 17
+						b4 80 08 32 10 00
+						32 15 08 32 12 20
+						33 05 4c 05 37 05
+						3f 1e 5f 5f 06
+					39 01 00 00 00 00 02
+						b6 00
+					39 01 00 00 00 00 23
+						e0 01 05 07 25 35
+						3f 0b 32 04 09 0e
+						10 13 10 14 16 1b
+						01 05 07 25 35 3f
+						0b 32 04 09 0e 10
+						13 10 14 16 1b
+					05 01 00 00 00 00 02 00 00
+					39 01 00 00 00 00 04
+						bf 06 00 10
+					05 01 00 00 c8 00 02 11 00
+					05 01 00 00 32 00 02 29 00];
+
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00
+					05 01 00 00 96 00 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index 7942567..2a6bbf9 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc {
 	qcom,mdss_dsi_nt35590_720p_cmd {
 		compatible = "qcom,mdss-dsi-panel";
 		label = "nt35590 720p command mode dsi panel";
@@ -58,473 +58,474 @@
 					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
 					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
 					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
-		qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
-					29 01 00 00 00 02 26 08
-					29 01 00 00 00 02 26 00
-					29 01 00 00 10 02 FF 00
-					29 01 00 00 00 02 BA 03
-					29 01 00 00 00 02 C2 08
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 00 4A
-					29 01 00 00 00 02 01 33
-					29 01 00 00 00 02 02 53
-					29 01 00 00 00 02 03 55
-					29 01 00 00 00 02 04 55
-					29 01 00 00 00 02 05 33
-					29 01 00 00 00 02 06 22
-					29 01 00 00 00 02 08 56
-					29 01 00 00 00 02 09 8F
-					29 01 00 00 00 02 36 73
-					29 01 00 00 00 02 0B 9F
-					29 01 00 00 00 02 0C 9F
-					29 01 00 00 00 02 0D 2F
-					29 01 00 00 00 02 0E 24
-					29 01 00 00 00 02 11 83
-					29 01 00 00 00 02 12 03
-					29 01 00 00 00 02 71 2C
-					29 01 00 00 00 02 6F 03
-					29 01 00 00 00 02 0F 0A
-					29 01 00 00 00 02 FF 05
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 01 00
-					29 01 00 00 00 02 02 8B
-					29 01 00 00 00 02 03 82
-					29 01 00 00 00 02 04 82
-					29 01 00 00 00 02 05 30
-					29 01 00 00 00 02 06 33
-					29 01 00 00 00 02 07 01
-					29 01 00 00 00 02 08 00
-					29 01 00 00 00 02 09 46
-					29 01 00 00 00 02 0A 46
-					29 01 00 00 00 02 0D 0B
-					29 01 00 00 00 02 0E 1D
-					29 01 00 00 00 02 0F 08
-					29 01 00 00 00 02 10 53
-					29 01 00 00 00 02 11 00
-					29 01 00 00 00 02 12 00
-					29 01 00 00 00 02 14 01
-					29 01 00 00 00 02 15 00
-					29 01 00 00 00 02 16 05
-					29 01 00 00 00 02 17 00
-					29 01 00 00 00 02 19 7F
-					29 01 00 00 00 02 1A FF
-					29 01 00 00 00 02 1B 0F
-					29 01 00 00 00 02 1C 00
-					29 01 00 00 00 02 1D 00
-					29 01 00 00 00 02 1E 00
-					29 01 00 00 00 02 1F 07
-					29 01 00 00 00 02 20 00
-					29 01 00 00 00 02 21 06
-					29 01 00 00 00 02 22 55
-					29 01 00 00 00 02 23 4D
-					29 01 00 00 00 02 2D 02
-					29 01 00 00 00 02 28 01
-					29 01 00 00 00 02 2F 02
-					29 01 00 00 00 02 83 01
-					29 01 00 00 00 02 9E 58
-					29 01 00 00 00 02 9F 6A
-					29 01 00 00 00 02 A0 01
-					29 01 00 00 00 02 A2 10
-					29 01 00 00 00 02 BB 0A
-					29 01 00 00 00 02 BC 0A
-					29 01 00 00 00 02 32 08
-					29 01 00 00 00 02 33 B8
-					29 01 00 00 00 02 36 01
-					29 01 00 00 00 02 37 00
-					29 01 00 00 00 02 43 00
-					29 01 00 00 00 02 4B 21
-					29 01 00 00 00 02 4C 03
-					29 01 00 00 00 02 50 21
-					29 01 00 00 00 02 51 03
-					29 01 00 00 00 02 58 21
-					29 01 00 00 00 02 59 03
-					29 01 00 00 00 02 5D 21
-					29 01 00 00 00 02 5E 03
-					29 01 00 00 00 02 6C 00
-					29 01 00 00 00 02 6D 00
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 75 00
-					29 01 00 00 00 02 76 7D
-					29 01 00 00 00 02 77 00
-					29 01 00 00 00 02 78 8A
-					29 01 00 00 00 02 79 00
-					29 01 00 00 00 02 7A 9C
-					29 01 00 00 00 02 7B 00
-					29 01 00 00 00 02 7C B1
-					29 01 00 00 00 02 7D 00
-					29 01 00 00 00 02 7E BF
-					29 01 00 00 00 02 7F 00
-					29 01 00 00 00 02 80 CF
-					29 01 00 00 00 02 81 00
-					29 01 00 00 00 02 82 DD
-					29 01 00 00 00 02 83 00
-					29 01 00 00 00 02 84 E8
-					29 01 00 00 00 02 85 00
-					29 01 00 00 00 02 86 F2
-					29 01 00 00 00 02 87 01
-					29 01 00 00 00 02 88 1F
-					29 01 00 00 00 02 89 01
-					29 01 00 00 00 02 8A 41
-					29 01 00 00 00 02 8B 01
-					29 01 00 00 00 02 8C 78
-					29 01 00 00 00 02 8D 01
-					29 01 00 00 00 02 8E A5
-					29 01 00 00 00 02 8F 01
-					29 01 00 00 00 02 90 EE
-					29 01 00 00 00 02 91 02
-					29 01 00 00 00 02 92 29
-					29 01 00 00 00 02 93 02
-					29 01 00 00 00 02 94 2A
-					29 01 00 00 00 02 95 02
-					29 01 00 00 00 02 96 5D
-					29 01 00 00 00 02 97 02
-					29 01 00 00 00 02 98 93
-					29 01 00 00 00 02 99 02
-					29 01 00 00 00 02 9A B8
-					29 01 00 00 00 02 9B 02
-					29 01 00 00 00 02 9C E7
-					29 01 00 00 00 02 9D 03
-					29 01 00 00 00 02 9E 07
-					29 01 00 00 00 02 9F 03
-					29 01 00 00 00 02 A0 37
-					29 01 00 00 00 02 A2 03
-					29 01 00 00 00 02 A3 46
-					29 01 00 00 00 02 A4 03
-					29 01 00 00 00 02 A5 56
-					29 01 00 00 00 02 A6 03
-					29 01 00 00 00 02 A7 66
-					29 01 00 00 00 02 A9 03
-					29 01 00 00 00 02 AA 7A
-					29 01 00 00 00 02 AB 03
-					29 01 00 00 00 02 AC 93
-					29 01 00 00 00 02 AD 03
-					29 01 00 00 00 02 AE A3
-					29 01 00 00 00 02 AF 03
-					29 01 00 00 00 02 B0 B4
-					29 01 00 00 00 02 B1 03
-					29 01 00 00 00 02 B2 CB
-					29 01 00 00 00 02 B3 00
-					29 01 00 00 00 02 B4 7D
-					29 01 00 00 00 02 B5 00
-					29 01 00 00 00 02 B6 8A
-					29 01 00 00 00 02 B7 00
-					29 01 00 00 00 02 B8 9C
-					29 01 00 00 00 02 B9 00
-					29 01 00 00 00 02 BA B1
-					29 01 00 00 00 02 BB 00
-					29 01 00 00 00 02 BC BF
-					29 01 00 00 00 02 BD 00
-					29 01 00 00 00 02 BE CF
-					29 01 00 00 00 02 BF 00
-					29 01 00 00 00 02 C0 DD
-					29 01 00 00 00 02 C1 00
-					29 01 00 00 00 02 C2 E8
-					29 01 00 00 00 02 C3 00
-					29 01 00 00 00 02 C4 F2
-					29 01 00 00 00 02 C5 01
-					29 01 00 00 00 02 C6 1F
-					29 01 00 00 00 02 C7 01
-					29 01 00 00 00 02 C8 41
-					29 01 00 00 00 02 C9 01
-					29 01 00 00 00 02 CA 78
-					29 01 00 00 00 02 CB 01
-					29 01 00 00 00 02 CC A5
-					29 01 00 00 00 02 CD 01
-					29 01 00 00 00 02 CE EE
-					29 01 00 00 00 02 CF 02
-					29 01 00 00 00 02 D0 29
-					29 01 00 00 00 02 D1 02
-					29 01 00 00 00 02 D2 2A
-					29 01 00 00 00 02 D3 02
-					29 01 00 00 00 02 D4 5D
-					29 01 00 00 00 02 D5 02
-					29 01 00 00 00 02 D6 93
-					29 01 00 00 00 02 D7 02
-					29 01 00 00 00 02 D8 B8
-					29 01 00 00 00 02 D9 02
-					29 01 00 00 00 02 DA E7
-					29 01 00 00 00 02 DB 03
-					29 01 00 00 00 02 DC 07
-					29 01 00 00 00 02 DD 03
-					29 01 00 00 00 02 DE 37
-					29 01 00 00 00 02 DF 03
-					29 01 00 00 00 02 E0 46
-					29 01 00 00 00 02 E1 03
-					29 01 00 00 00 02 E2 56
-					29 01 00 00 00 02 E3 03
-					29 01 00 00 00 02 E4 66
-					29 01 00 00 00 02 E5 03
-					29 01 00 00 00 02 E6 7A
-					29 01 00 00 00 02 E7 03
-					29 01 00 00 00 02 E8 93
-					29 01 00 00 00 02 E9 03
-					29 01 00 00 00 02 EA A3
-					29 01 00 00 00 02 EB 03
-					29 01 00 00 00 02 EC B4
-					29 01 00 00 00 02 ED 03
-					29 01 00 00 00 02 EE CB
-					29 01 00 00 00 02 EF 00
-					29 01 00 00 00 02 F0 ED
-					29 01 00 00 00 02 F1 00
-					29 01 00 00 00 02 F2 F3
-					29 01 00 00 00 02 F3 00
-					29 01 00 00 00 02 F4 FE
-					29 01 00 00 00 02 F5 01
-					29 01 00 00 00 02 F6 09
-					29 01 00 00 00 02 F7 01
-					29 01 00 00 00 02 F8 13
-					29 01 00 00 00 02 F9 01
-					29 01 00 00 00 02 FA 1D
-					29 01 00 00 00 02 FF 02
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 00 01
-					29 01 00 00 00 02 01 26
-					29 01 00 00 00 02 02 01
-					29 01 00 00 00 02 03 2F
-					29 01 00 00 00 02 04 01
-					29 01 00 00 00 02 05 37
-					29 01 00 00 00 02 06 01
-					29 01 00 00 00 02 07 56
-					29 01 00 00 00 02 08 01
-					29 01 00 00 00 02 09 70
-					29 01 00 00 00 02 0A 01
-					29 01 00 00 00 02 0B 9D
-					29 01 00 00 00 02 0C 01
-					29 01 00 00 00 02 0D C2
-					29 01 00 00 00 02 0E 01
-					29 01 00 00 00 02 0F FF
-					29 01 00 00 00 02 10 02
-					29 01 00 00 00 02 11 31
-					29 01 00 00 00 02 12 02
-					29 01 00 00 00 02 13 32
-					29 01 00 00 00 02 14 02
-					29 01 00 00 00 02 15 60
-					29 01 00 00 00 02 16 02
-					29 01 00 00 00 02 17 94
-					29 01 00 00 00 02 18 02
-					29 01 00 00 00 02 19 B5
-					29 01 00 00 00 02 1A 02
-					29 01 00 00 00 02 1B E3
-					29 01 00 00 00 02 1C 03
-					29 01 00 00 00 02 1D 03
-					29 01 00 00 00 02 1E 03
-					29 01 00 00 00 02 1F 2D
-					29 01 00 00 00 02 20 03
-					29 01 00 00 00 02 21 3A
-					29 01 00 00 00 02 22 03
-					29 01 00 00 00 02 23 48
-					29 01 00 00 00 02 24 03
-					29 01 00 00 00 02 25 57
-					29 01 00 00 00 02 26 03
-					29 01 00 00 00 02 27 68
-					29 01 00 00 00 02 28 03
-					29 01 00 00 00 02 29 7B
-					29 01 00 00 00 02 2A 03
-					29 01 00 00 00 02 2B 90
-					29 01 00 00 00 02 2D 03
-					29 01 00 00 00 02 2F A0
-					29 01 00 00 00 02 30 03
-					29 01 00 00 00 02 31 CB
-					29 01 00 00 00 02 32 00
-					29 01 00 00 00 02 33 ED
-					29 01 00 00 00 02 34 00
-					29 01 00 00 00 02 35 F3
-					29 01 00 00 00 02 36 00
-					29 01 00 00 00 02 37 FE
-					29 01 00 00 00 02 38 01
-					29 01 00 00 00 02 39 09
-					29 01 00 00 00 02 3A 01
-					29 01 00 00 00 02 3B 13
-					29 01 00 00 00 02 3D 01
-					29 01 00 00 00 02 3F 1D
-					29 01 00 00 00 02 40 01
-					29 01 00 00 00 02 41 26
-					29 01 00 00 00 02 42 01
-					29 01 00 00 00 02 43 2F
-					29 01 00 00 00 02 44 01
-					29 01 00 00 00 02 45 37
-					29 01 00 00 00 02 46 01
-					29 01 00 00 00 02 47 56
-					29 01 00 00 00 02 48 01
-					29 01 00 00 00 02 49 70
-					29 01 00 00 00 02 4A 01
-					29 01 00 00 00 02 4B 9D
-					29 01 00 00 00 02 4C 01
-					29 01 00 00 00 02 4D C2
-					29 01 00 00 00 02 4E 01
-					29 01 00 00 00 02 4F FF
-					29 01 00 00 00 02 50 02
-					29 01 00 00 00 02 51 31
-					29 01 00 00 00 02 52 02
-					29 01 00 00 00 02 53 32
-					29 01 00 00 00 02 54 02
-					29 01 00 00 00 02 55 60
-					29 01 00 00 00 02 56 02
-					29 01 00 00 00 02 58 94
-					29 01 00 00 00 02 59 02
-					29 01 00 00 00 02 5A B5
-					29 01 00 00 00 02 5B 02
-					29 01 00 00 00 02 5C E3
-					29 01 00 00 00 02 5D 03
-					29 01 00 00 00 02 5E 03
-					29 01 00 00 00 02 5F 03
-					29 01 00 00 00 02 60 2D
-					29 01 00 00 00 02 61 03
-					29 01 00 00 00 02 62 3A
-					29 01 00 00 00 02 63 03
-					29 01 00 00 00 02 64 48
-					29 01 00 00 00 02 65 03
-					29 01 00 00 00 02 66 57
-					29 01 00 00 00 02 67 03
-					29 01 00 00 00 02 68 68
-					29 01 00 00 00 02 69 03
-					29 01 00 00 00 02 6A 7B
-					29 01 00 00 00 02 6B 03
-					29 01 00 00 00 02 6C 90
-					29 01 00 00 00 02 6D 03
-					29 01 00 00 00 02 6E A0
-					29 01 00 00 00 02 6F 03
-					29 01 00 00 00 02 70 CB
-					29 01 00 00 00 02 71 00
-					29 01 00 00 00 02 72 19
-					29 01 00 00 00 02 73 00
-					29 01 00 00 00 02 74 36
-					29 01 00 00 00 02 75 00
-					29 01 00 00 00 02 76 55
-					29 01 00 00 00 02 77 00
-					29 01 00 00 00 02 78 70
-					29 01 00 00 00 02 79 00
-					29 01 00 00 00 02 7A 83
-					29 01 00 00 00 02 7B 00
-					29 01 00 00 00 02 7C 99
-					29 01 00 00 00 02 7D 00
-					29 01 00 00 00 02 7E A8
-					29 01 00 00 00 02 7F 00
-					29 01 00 00 00 02 80 B7
-					29 01 00 00 00 02 81 00
-					29 01 00 00 00 02 82 C5
-					29 01 00 00 00 02 83 00
-					29 01 00 00 00 02 84 F7
-					29 01 00 00 00 02 85 01
-					29 01 00 00 00 02 86 1E
-					29 01 00 00 00 02 87 01
-					29 01 00 00 00 02 88 60
-					29 01 00 00 00 02 89 01
-					29 01 00 00 00 02 8A 95
-					29 01 00 00 00 02 8B 01
-					29 01 00 00 00 02 8C E1
-					29 01 00 00 00 02 8D 02
-					29 01 00 00 00 02 8E 20
-					29 01 00 00 00 02 8F 02
-					29 01 00 00 00 02 90 23
-					29 01 00 00 00 02 91 02
-					29 01 00 00 00 02 92 59
-					29 01 00 00 00 02 93 02
-					29 01 00 00 00 02 94 94
-					29 01 00 00 00 02 95 02
-					29 01 00 00 00 02 96 B4
-					29 01 00 00 00 02 97 02
-					29 01 00 00 00 02 98 E1
-					29 01 00 00 00 02 99 03
-					29 01 00 00 00 02 9A 01
-					29 01 00 00 00 02 9B 03
-					29 01 00 00 00 02 9C 28
-					29 01 00 00 00 02 9D 03
-					29 01 00 00 00 02 9E 30
-					29 01 00 00 00 02 9F 03
-					29 01 00 00 00 02 A0 37
-					29 01 00 00 00 02 A2 03
-					29 01 00 00 00 02 A3 3B
-					29 01 00 00 00 02 A4 03
-					29 01 00 00 00 02 A5 40
-					29 01 00 00 00 02 A6 03
-					29 01 00 00 00 02 A7 50
-					29 01 00 00 00 02 A9 03
-					29 01 00 00 00 02 AA 6D
-					29 01 00 00 00 02 AB 03
-					29 01 00 00 00 02 AC 80
-					29 01 00 00 00 02 AD 03
-					29 01 00 00 00 02 AE CB
-					29 01 00 00 00 02 AF 00
-					29 01 00 00 00 02 B0 19
-					29 01 00 00 00 02 B1 00
-					29 01 00 00 00 02 B2 36
-					29 01 00 00 00 02 B3 00
-					29 01 00 00 00 02 B4 55
-					29 01 00 00 00 02 B5 00
-					29 01 00 00 00 02 B6 70
-					29 01 00 00 00 02 B7 00
-					29 01 00 00 00 02 B8 83
-					29 01 00 00 00 02 B9 00
-					29 01 00 00 00 02 BA 99
-					29 01 00 00 00 02 BB 00
-					29 01 00 00 00 02 BC A8
-					29 01 00 00 00 02 BD 00
-					29 01 00 00 00 02 BE B7
-					29 01 00 00 00 02 BF 00
-					29 01 00 00 00 02 C0 C5
-					29 01 00 00 00 02 C1 00
-					29 01 00 00 00 02 C2 F7
-					29 01 00 00 00 02 C3 01
-					29 01 00 00 00 02 C4 1E
-					29 01 00 00 00 02 C5 01
-					29 01 00 00 00 02 C6 60
-					29 01 00 00 00 02 C7 01
-					29 01 00 00 00 02 C8 95
-					29 01 00 00 00 02 C9 01
-					29 01 00 00 00 02 CA E1
-					29 01 00 00 00 02 CB 02
-					29 01 00 00 00 02 CC 20
-					29 01 00 00 00 02 CD 02
-					29 01 00 00 00 02 CE 23
-					29 01 00 00 00 02 CF 02
-					29 01 00 00 00 02 D0 59
-					29 01 00 00 00 02 D1 02
-					29 01 00 00 00 02 D2 94
-					29 01 00 00 00 02 D3 02
-					29 01 00 00 00 02 D4 B4
-					29 01 00 00 00 02 D5 02
-					29 01 00 00 00 02 D6 E1
-					29 01 00 00 00 02 D7 03
-					29 01 00 00 00 02 D8 01
-					29 01 00 00 00 02 D9 03
-					29 01 00 00 00 02 DA 28
-					29 01 00 00 00 02 DB 03
-					29 01 00 00 00 02 DC 30
-					29 01 00 00 00 02 DD 03
-					29 01 00 00 00 02 DE 37
-					29 01 00 00 00 02 DF 03
-					29 01 00 00 00 02 E0 3B
-					29 01 00 00 00 02 E1 03
-					29 01 00 00 00 02 E2 40
-					29 01 00 00 00 02 E3 03
-					29 01 00 00 00 02 E4 50
-					29 01 00 00 00 02 E5 03
-					29 01 00 00 00 02 E6 6D
-					29 01 00 00 00 02 E7 03
-					29 01 00 00 00 02 E8 80
-					29 01 00 00 00 02 E9 03
-					29 01 00 00 00 02 EA CB
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 02
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 04
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 00
-					29 01 00 00 64 02 11 00
-					29 01 00 00 00 02 FF EE
-					29 01 00 00 00 02 12 50
-					29 01 00 00 00 02 13 02
-					29 01 00 00 00 02 6A 60
-					29 01 00 00 00 02 FF 00
-					29 01 00 00 78 02 29 00];
+		qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+					29 01 00 00 00 00 02 26 08
+					29 01 00 00 00 00 02 26 00
+					29 01 00 00 10 00 02 FF 00
+					29 01 00 00 00 00 02 BA 03
+					29 01 00 00 00 00 02 C2 08
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 00 4A
+					29 01 00 00 00 00 02 01 33
+					29 01 00 00 00 00 02 02 53
+					29 01 00 00 00 00 02 03 55
+					29 01 00 00 00 00 02 04 55
+					29 01 00 00 00 00 02 05 33
+					29 01 00 00 00 00 02 06 22
+					29 01 00 00 00 00 02 08 56
+					29 01 00 00 00 00 02 09 8F
+					29 01 00 00 00 00 02 36 73
+					29 01 00 00 00 00 02 0B 9F
+					29 01 00 00 00 00 02 0C 9F
+					29 01 00 00 00 00 02 0D 2F
+					29 01 00 00 00 00 02 0E 24
+					29 01 00 00 00 00 02 11 83
+					29 01 00 00 00 00 02 12 03
+					29 01 00 00 00 00 02 71 2C
+					29 01 00 00 00 00 02 6F 03
+					29 01 00 00 00 00 02 0F 0A
+					29 01 00 00 00 00 02 FF 05
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 01 00
+					29 01 00 00 00 00 02 02 8B
+					29 01 00 00 00 00 02 03 82
+					29 01 00 00 00 00 02 04 82
+					29 01 00 00 00 00 02 05 30
+					29 01 00 00 00 00 02 06 33
+					29 01 00 00 00 00 02 07 01
+					29 01 00 00 00 00 02 08 00
+					29 01 00 00 00 00 02 09 46
+					29 01 00 00 00 00 02 0A 46
+					29 01 00 00 00 00 02 0D 0B
+					29 01 00 00 00 00 02 0E 1D
+					29 01 00 00 00 00 02 0F 08
+					29 01 00 00 00 00 02 10 53
+					29 01 00 00 00 00 02 11 00
+					29 01 00 00 00 00 02 12 00
+					29 01 00 00 00 00 02 14 01
+					29 01 00 00 00 00 02 15 00
+					29 01 00 00 00 00 02 16 05
+					29 01 00 00 00 00 02 17 00
+					29 01 00 00 00 00 02 19 7F
+					29 01 00 00 00 00 02 1A FF
+					29 01 00 00 00 00 02 1B 0F
+					29 01 00 00 00 00 02 1C 00
+					29 01 00 00 00 00 02 1D 00
+					29 01 00 00 00 00 02 1E 00
+					29 01 00 00 00 00 02 1F 07
+					29 01 00 00 00 00 02 20 00
+					29 01 00 00 00 00 02 21 06
+					29 01 00 00 00 00 02 22 55
+					29 01 00 00 00 00 02 23 4D
+					29 01 00 00 00 00 02 2D 02
+					29 01 00 00 00 00 02 28 01
+					29 01 00 00 00 00 02 2F 02
+					29 01 00 00 00 00 02 83 01
+					29 01 00 00 00 00 02 9E 58
+					29 01 00 00 00 00 02 9F 6A
+					29 01 00 00 00 00 02 A0 01
+					29 01 00 00 00 00 02 A2 10
+					29 01 00 00 00 00 02 BB 0A
+					29 01 00 00 00 00 02 BC 0A
+					29 01 00 00 00 00 02 32 08
+					29 01 00 00 00 00 02 33 B8
+					29 01 00 00 00 00 02 36 01
+					29 01 00 00 00 00 02 37 00
+					29 01 00 00 00 00 02 43 00
+					29 01 00 00 00 00 02 4B 21
+					29 01 00 00 00 00 02 4C 03
+					29 01 00 00 00 00 02 50 21
+					29 01 00 00 00 00 02 51 03
+					29 01 00 00 00 00 02 58 21
+					29 01 00 00 00 00 02 59 03
+					29 01 00 00 00 00 02 5D 21
+					29 01 00 00 00 00 02 5E 03
+					29 01 00 00 00 00 02 6C 00
+					29 01 00 00 00 00 02 6D 00
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 75 00
+					29 01 00 00 00 00 02 76 7D
+					29 01 00 00 00 00 02 77 00
+					29 01 00 00 00 00 02 78 8A
+					29 01 00 00 00 00 02 79 00
+					29 01 00 00 00 00 02 7A 9C
+					29 01 00 00 00 00 02 7B 00
+					29 01 00 00 00 00 02 7C B1
+					29 01 00 00 00 00 02 7D 00
+					29 01 00 00 00 00 02 7E BF
+					29 01 00 00 00 00 02 7F 00
+					29 01 00 00 00 00 02 80 CF
+					29 01 00 00 00 00 02 81 00
+					29 01 00 00 00 00 02 82 DD
+					29 01 00 00 00 00 02 83 00
+					29 01 00 00 00 00 02 84 E8
+					29 01 00 00 00 00 02 85 00
+					29 01 00 00 00 00 02 86 F2
+					29 01 00 00 00 00 02 87 01
+					29 01 00 00 00 00 02 88 1F
+					29 01 00 00 00 00 02 89 01
+					29 01 00 00 00 00 02 8A 41
+					29 01 00 00 00 00 02 8B 01
+					29 01 00 00 00 00 02 8C 78
+					29 01 00 00 00 00 02 8D 01
+					29 01 00 00 00 00 02 8E A5
+					29 01 00 00 00 00 02 8F 01
+					29 01 00 00 00 00 02 90 EE
+					29 01 00 00 00 00 02 91 02
+					29 01 00 00 00 00 02 92 29
+					29 01 00 00 00 00 02 93 02
+					29 01 00 00 00 00 02 94 2A
+					29 01 00 00 00 00 02 95 02
+					29 01 00 00 00 00 02 96 5D
+					29 01 00 00 00 00 02 97 02
+					29 01 00 00 00 00 02 98 93
+					29 01 00 00 00 00 02 99 02
+					29 01 00 00 00 00 02 9A B8
+					29 01 00 00 00 00 02 9B 02
+					29 01 00 00 00 00 02 9C E7
+					29 01 00 00 00 00 02 9D 03
+					29 01 00 00 00 00 02 9E 07
+					29 01 00 00 00 00 02 9F 03
+					29 01 00 00 00 00 02 A0 37
+					29 01 00 00 00 00 02 A2 03
+					29 01 00 00 00 00 02 A3 46
+					29 01 00 00 00 00 02 A4 03
+					29 01 00 00 00 00 02 A5 56
+					29 01 00 00 00 00 02 A6 03
+					29 01 00 00 00 00 02 A7 66
+					29 01 00 00 00 00 02 A9 03
+					29 01 00 00 00 00 02 AA 7A
+					29 01 00 00 00 00 02 AB 03
+					29 01 00 00 00 00 02 AC 93
+					29 01 00 00 00 00 02 AD 03
+					29 01 00 00 00 00 02 AE A3
+					29 01 00 00 00 00 02 AF 03
+					29 01 00 00 00 00 02 B0 B4
+					29 01 00 00 00 00 02 B1 03
+					29 01 00 00 00 00 02 B2 CB
+					29 01 00 00 00 00 02 B3 00
+					29 01 00 00 00 00 02 B4 7D
+					29 01 00 00 00 00 02 B5 00
+					29 01 00 00 00 00 02 B6 8A
+					29 01 00 00 00 00 02 B7 00
+					29 01 00 00 00 00 02 B8 9C
+					29 01 00 00 00 00 02 B9 00
+					29 01 00 00 00 00 02 BA B1
+					29 01 00 00 00 00 02 BB 00
+					29 01 00 00 00 00 02 BC BF
+					29 01 00 00 00 00 02 BD 00
+					29 01 00 00 00 00 02 BE CF
+					29 01 00 00 00 00 02 BF 00
+					29 01 00 00 00 00 02 C0 DD
+					29 01 00 00 00 00 02 C1 00
+					29 01 00 00 00 00 02 C2 E8
+					29 01 00 00 00 00 02 C3 00
+					29 01 00 00 00 00 02 C4 F2
+					29 01 00 00 00 00 02 C5 01
+					29 01 00 00 00 00 02 C6 1F
+					29 01 00 00 00 00 02 C7 01
+					29 01 00 00 00 00 02 C8 41
+					29 01 00 00 00 00 02 C9 01
+					29 01 00 00 00 00 02 CA 78
+					29 01 00 00 00 00 02 CB 01
+					29 01 00 00 00 00 02 CC A5
+					29 01 00 00 00 00 02 CD 01
+					29 01 00 00 00 00 02 CE EE
+					29 01 00 00 00 00 02 CF 02
+					29 01 00 00 00 00 02 D0 29
+					29 01 00 00 00 00 02 D1 02
+					29 01 00 00 00 00 02 D2 2A
+					29 01 00 00 00 00 02 D3 02
+					29 01 00 00 00 00 02 D4 5D
+					29 01 00 00 00 00 02 D5 02
+					29 01 00 00 00 00 02 D6 93
+					29 01 00 00 00 00 02 D7 02
+					29 01 00 00 00 00 02 D8 B8
+					29 01 00 00 00 00 02 D9 02
+					29 01 00 00 00 00 02 DA E7
+					29 01 00 00 00 00 02 DB 03
+					29 01 00 00 00 00 02 DC 07
+					29 01 00 00 00 00 02 DD 03
+					29 01 00 00 00 00 02 DE 37
+					29 01 00 00 00 00 02 DF 03
+					29 01 00 00 00 00 02 E0 46
+					29 01 00 00 00 00 02 E1 03
+					29 01 00 00 00 00 02 E2 56
+					29 01 00 00 00 00 02 E3 03
+					29 01 00 00 00 00 02 E4 66
+					29 01 00 00 00 00 02 E5 03
+					29 01 00 00 00 00 02 E6 7A
+					29 01 00 00 00 00 02 E7 03
+					29 01 00 00 00 00 02 E8 93
+					29 01 00 00 00 00 02 E9 03
+					29 01 00 00 00 00 02 EA A3
+					29 01 00 00 00 00 02 EB 03
+					29 01 00 00 00 00 02 EC B4
+					29 01 00 00 00 00 02 ED 03
+					29 01 00 00 00 00 02 EE CB
+					29 01 00 00 00 00 02 EF 00
+					29 01 00 00 00 00 02 F0 ED
+					29 01 00 00 00 00 02 F1 00
+					29 01 00 00 00 00 02 F2 F3
+					29 01 00 00 00 00 02 F3 00
+					29 01 00 00 00 00 02 F4 FE
+					29 01 00 00 00 00 02 F5 01
+					29 01 00 00 00 00 02 F6 09
+					29 01 00 00 00 00 02 F7 01
+					29 01 00 00 00 00 02 F8 13
+					29 01 00 00 00 00 02 F9 01
+					29 01 00 00 00 00 02 FA 1D
+					29 01 00 00 00 00 02 FF 02
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 00 01
+					29 01 00 00 00 00 02 01 26
+					29 01 00 00 00 00 02 02 01
+					29 01 00 00 00 00 02 03 2F
+					29 01 00 00 00 00 02 04 01
+					29 01 00 00 00 00 02 05 37
+					29 01 00 00 00 00 02 06 01
+					29 01 00 00 00 00 02 07 56
+					29 01 00 00 00 00 02 08 01
+					29 01 00 00 00 00 02 09 70
+					29 01 00 00 00 00 02 0A 01
+					29 01 00 00 00 00 02 0B 9D
+					29 01 00 00 00 00 02 0C 01
+					29 01 00 00 00 00 02 0D C2
+					29 01 00 00 00 00 02 0E 01
+					29 01 00 00 00 00 02 0F FF
+					29 01 00 00 00 00 02 10 02
+					29 01 00 00 00 00 02 11 31
+					29 01 00 00 00 00 02 12 02
+					29 01 00 00 00 00 02 13 32
+					29 01 00 00 00 00 02 14 02
+					29 01 00 00 00 00 02 15 60
+					29 01 00 00 00 00 02 16 02
+					29 01 00 00 00 00 02 17 94
+					29 01 00 00 00 00 02 18 02
+					29 01 00 00 00 00 02 19 B5
+					29 01 00 00 00 00 02 1A 02
+					29 01 00 00 00 00 02 1B E3
+					29 01 00 00 00 00 02 1C 03
+					29 01 00 00 00 00 02 1D 03
+					29 01 00 00 00 00 02 1E 03
+					29 01 00 00 00 00 02 1F 2D
+					29 01 00 00 00 00 02 20 03
+					29 01 00 00 00 00 02 21 3A
+					29 01 00 00 00 00 02 22 03
+					29 01 00 00 00 00 02 23 48
+					29 01 00 00 00 00 02 24 03
+					29 01 00 00 00 00 02 25 57
+					29 01 00 00 00 00 02 26 03
+					29 01 00 00 00 00 02 27 68
+					29 01 00 00 00 00 02 28 03
+					29 01 00 00 00 00 02 29 7B
+					29 01 00 00 00 00 02 2A 03
+					29 01 00 00 00 00 02 2B 90
+					29 01 00 00 00 00 02 2D 03
+					29 01 00 00 00 00 02 2F A0
+					29 01 00 00 00 00 02 30 03
+					29 01 00 00 00 00 02 31 CB
+					29 01 00 00 00 00 02 32 00
+					29 01 00 00 00 00 02 33 ED
+					29 01 00 00 00 00 02 34 00
+					29 01 00 00 00 00 02 35 F3
+					29 01 00 00 00 00 02 36 00
+					29 01 00 00 00 00 02 37 FE
+					29 01 00 00 00 00 02 38 01
+					29 01 00 00 00 00 02 39 09
+					29 01 00 00 00 00 02 3A 01
+					29 01 00 00 00 00 02 3B 13
+					29 01 00 00 00 00 02 3D 01
+					29 01 00 00 00 00 02 3F 1D
+					29 01 00 00 00 00 02 40 01
+					29 01 00 00 00 00 02 41 26
+					29 01 00 00 00 00 02 42 01
+					29 01 00 00 00 00 02 43 2F
+					29 01 00 00 00 00 02 44 01
+					29 01 00 00 00 00 02 45 37
+					29 01 00 00 00 00 02 46 01
+					29 01 00 00 00 00 02 47 56
+					29 01 00 00 00 00 02 48 01
+					29 01 00 00 00 00 02 49 70
+					29 01 00 00 00 00 02 4A 01
+					29 01 00 00 00 00 02 4B 9D
+					29 01 00 00 00 00 02 4C 01
+					29 01 00 00 00 00 02 4D C2
+					29 01 00 00 00 00 02 4E 01
+					29 01 00 00 00 00 02 4F FF
+					29 01 00 00 00 00 02 50 02
+					29 01 00 00 00 00 02 51 31
+					29 01 00 00 00 00 02 52 02
+					29 01 00 00 00 00 02 53 32
+					29 01 00 00 00 00 02 54 02
+					29 01 00 00 00 00 02 55 60
+					29 01 00 00 00 00 02 56 02
+					29 01 00 00 00 00 02 58 94
+					29 01 00 00 00 00 02 59 02
+					29 01 00 00 00 00 02 5A B5
+					29 01 00 00 00 00 02 5B 02
+					29 01 00 00 00 00 02 5C E3
+					29 01 00 00 00 00 02 5D 03
+					29 01 00 00 00 00 02 5E 03
+					29 01 00 00 00 00 02 5F 03
+					29 01 00 00 00 00 02 60 2D
+					29 01 00 00 00 00 02 61 03
+					29 01 00 00 00 00 02 62 3A
+					29 01 00 00 00 00 02 63 03
+					29 01 00 00 00 00 02 64 48
+					29 01 00 00 00 00 02 65 03
+					29 01 00 00 00 00 02 66 57
+					29 01 00 00 00 00 02 67 03
+					29 01 00 00 00 00 02 68 68
+					29 01 00 00 00 00 02 69 03
+					29 01 00 00 00 00 02 6A 7B
+					29 01 00 00 00 00 02 6B 03
+					29 01 00 00 00 00 02 6C 90
+					29 01 00 00 00 00 02 6D 03
+					29 01 00 00 00 00 02 6E A0
+					29 01 00 00 00 00 02 6F 03
+					29 01 00 00 00 00 02 70 CB
+					29 01 00 00 00 00 02 71 00
+					29 01 00 00 00 00 02 72 19
+					29 01 00 00 00 00 02 73 00
+					29 01 00 00 00 00 02 74 36
+					29 01 00 00 00 00 02 75 00
+					29 01 00 00 00 00 02 76 55
+					29 01 00 00 00 00 02 77 00
+					29 01 00 00 00 00 02 78 70
+					29 01 00 00 00 00 02 79 00
+					29 01 00 00 00 00 02 7A 83
+					29 01 00 00 00 00 02 7B 00
+					29 01 00 00 00 00 02 7C 99
+					29 01 00 00 00 00 02 7D 00
+					29 01 00 00 00 00 02 7E A8
+					29 01 00 00 00 00 02 7F 00
+					29 01 00 00 00 00 02 80 B7
+					29 01 00 00 00 00 02 81 00
+					29 01 00 00 00 00 02 82 C5
+					29 01 00 00 00 00 02 83 00
+					29 01 00 00 00 00 02 84 F7
+					29 01 00 00 00 00 02 85 01
+					29 01 00 00 00 00 02 86 1E
+					29 01 00 00 00 00 02 87 01
+					29 01 00 00 00 00 02 88 60
+					29 01 00 00 00 00 02 89 01
+					29 01 00 00 00 00 02 8A 95
+					29 01 00 00 00 00 02 8B 01
+					29 01 00 00 00 00 02 8C E1
+					29 01 00 00 00 00 02 8D 02
+					29 01 00 00 00 00 02 8E 20
+					29 01 00 00 00 00 02 8F 02
+					29 01 00 00 00 00 02 90 23
+					29 01 00 00 00 00 02 91 02
+					29 01 00 00 00 00 02 92 59
+					29 01 00 00 00 00 02 93 02
+					29 01 00 00 00 00 02 94 94
+					29 01 00 00 00 00 02 95 02
+					29 01 00 00 00 00 02 96 B4
+					29 01 00 00 00 00 02 97 02
+					29 01 00 00 00 00 02 98 E1
+					29 01 00 00 00 00 02 99 03
+					29 01 00 00 00 00 02 9A 01
+					29 01 00 00 00 00 02 9B 03
+					29 01 00 00 00 00 02 9C 28
+					29 01 00 00 00 00 02 9D 03
+					29 01 00 00 00 00 02 9E 30
+					29 01 00 00 00 00 02 9F 03
+					29 01 00 00 00 00 02 A0 37
+					29 01 00 00 00 00 02 A2 03
+					29 01 00 00 00 00 02 A3 3B
+					29 01 00 00 00 00 02 A4 03
+					29 01 00 00 00 00 02 A5 40
+					29 01 00 00 00 00 02 A6 03
+					29 01 00 00 00 00 02 A7 50
+					29 01 00 00 00 00 02 A9 03
+					29 01 00 00 00 00 02 AA 6D
+					29 01 00 00 00 00 02 AB 03
+					29 01 00 00 00 00 02 AC 80
+					29 01 00 00 00 00 02 AD 03
+					29 01 00 00 00 00 02 AE CB
+					29 01 00 00 00 00 02 AF 00
+					29 01 00 00 00 00 02 B0 19
+					29 01 00 00 00 00 02 B1 00
+					29 01 00 00 00 00 02 B2 36
+					29 01 00 00 00 00 02 B3 00
+					29 01 00 00 00 00 02 B4 55
+					29 01 00 00 00 00 02 B5 00
+					29 01 00 00 00 00 02 B6 70
+					29 01 00 00 00 00 02 B7 00
+					29 01 00 00 00 00 02 B8 83
+					29 01 00 00 00 00 02 B9 00
+					29 01 00 00 00 00 02 BA 99
+					29 01 00 00 00 00 02 BB 00
+					29 01 00 00 00 00 02 BC A8
+					29 01 00 00 00 00 02 BD 00
+					29 01 00 00 00 00 02 BE B7
+					29 01 00 00 00 00 02 BF 00
+					29 01 00 00 00 00 02 C0 C5
+					29 01 00 00 00 00 02 C1 00
+					29 01 00 00 00 00 02 C2 F7
+					29 01 00 00 00 00 02 C3 01
+					29 01 00 00 00 00 02 C4 1E
+					29 01 00 00 00 00 02 C5 01
+					29 01 00 00 00 00 02 C6 60
+					29 01 00 00 00 00 02 C7 01
+					29 01 00 00 00 00 02 C8 95
+					29 01 00 00 00 00 02 C9 01
+					29 01 00 00 00 00 02 CA E1
+					29 01 00 00 00 00 02 CB 02
+					29 01 00 00 00 00 02 CC 20
+					29 01 00 00 00 00 02 CD 02
+					29 01 00 00 00 00 02 CE 23
+					29 01 00 00 00 00 02 CF 02
+					29 01 00 00 00 00 02 D0 59
+					29 01 00 00 00 00 02 D1 02
+					29 01 00 00 00 00 02 D2 94
+					29 01 00 00 00 00 02 D3 02
+					29 01 00 00 00 00 02 D4 B4
+					29 01 00 00 00 00 02 D5 02
+					29 01 00 00 00 00 02 D6 E1
+					29 01 00 00 00 00 02 D7 03
+					29 01 00 00 00 00 02 D8 01
+					29 01 00 00 00 00 02 D9 03
+					29 01 00 00 00 00 02 DA 28
+					29 01 00 00 00 00 02 DB 03
+					29 01 00 00 00 00 02 DC 30
+					29 01 00 00 00 00 02 DD 03
+					29 01 00 00 00 00 02 DE 37
+					29 01 00 00 00 00 02 DF 03
+					29 01 00 00 00 00 02 E0 3B
+					29 01 00 00 00 00 02 E1 03
+					29 01 00 00 00 00 02 E2 40
+					29 01 00 00 00 00 02 E3 03
+					29 01 00 00 00 00 02 E4 50
+					29 01 00 00 00 00 02 E5 03
+					29 01 00 00 00 00 02 E6 6D
+					29 01 00 00 00 00 02 E7 03
+					29 01 00 00 00 00 02 E8 80
+					29 01 00 00 00 00 02 E9 03
+					29 01 00 00 00 00 02 EA CB
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 02
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 04
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 00
+					29 01 00 00 64 00 02 11 00
+					29 01 00 00 00 00 02 FF EE
+					29 01 00 00 00 00 02 12 50
+					29 01 00 00 00 00 02 13 02
+					29 01 00 00 00 00 02 6A 60
+					29 01 00 00 00 00 02 FF 00
+					29 01 00 00 78 00 02 29 00];
+
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
 		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ce050a4..b801da8 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -148,14 +148,15 @@
 						<0x0 0x40 0x6>,
 						<0x0 0x40 0x7>;
 
-				interrupt-names = "vsense_for_r",
-						  "vsense_avg",
-						  "sw_cc_thr",
-						  "ocv_thr",
-						  "charge_begin",
-						  "good_ocv",
+				interrupt-names = "cc_thr",
 						  "ocv_for_r",
-						  "cc_thr";
+						  "good_ocv",
+						  "charge_begin",
+						  "ocv_thr",
+						  "sw_cc_thr",
+						  "vsense_avg",
+						  "vsense_for_r";
+
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 703ba4b..d9bd5e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -18,7 +18,7 @@
 		reg = <0xf9089000 0x1000>;
 		qcom,core-id = <0>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -35,7 +35,7 @@
 		reg = <0xf9099000 0x1000>;
 		qcom,core-id = <1>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -52,7 +52,7 @@
 		reg = <0xf90a9000 0x1000>;
 		qcom,core-id = <2>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -69,7 +69,7 @@
 		reg = <0xf90b9000 0x1000>;
 		qcom,core-id = <3>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -367,6 +367,13 @@
 		qcom,pc-resets-timer;
 	};
 
+	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 {
 		compatible = "qcom,rpm-log";
 		reg = <0xfc19dc00 0x4000>;
@@ -384,4 +391,10 @@
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
+
+	qcom,rpm-rbcpr-stats@fc000000 {
+		compatible = "qcom,rpmrbcpr-stats";
+		reg = <0xfc000000 0x1a0000>;
+		qcom,start-offset = <0x190010>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 7018c6a..64cbb10 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -323,8 +323,9 @@
 
 &pm8226_chg {
 	status = "okay";
-	qcom,chg-vddmax-mv = <4350>;
-	qcom,chg-vddsafe-mv = <4350>;
+	qcom,vddmax-mv = <4350>;
+	qcom,vddsafe-mv = <4380>;
+	qcom,tchg-mins = <240>;
 };
 
 &pm8226_gpios {
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index db2f4e6..2148e1d 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -51,6 +51,11 @@
 	qcom,cpr-apc-volt-step = <10000>;
 };
 
+&msm_gpu {
+	/* Updated chip ID */
+	qcom,chipid = <0x03000512>;
+};
+
 &soc {
 	qcom,acpuclk@f9011050 {
 		reg =	<0xf9011050 0x8>,
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index faa7a41..c48eaf7 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -18,7 +18,7 @@
 		reg = <0xf9089000 0x1000>;
 		qcom,core-id = <0>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -35,7 +35,7 @@
 		reg = <0xf9099000 0x1000>;
 		qcom,core-id = <1>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -52,7 +52,7 @@
 		reg = <0xf90a9000 0x1000>;
 		qcom,core-id = <2>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -69,7 +69,7 @@
 		reg = <0xf90b9000 0x1000>;
 		qcom,core-id = <3>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-cfg = <0x00>;
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -369,6 +369,13 @@
 		qcom,pc-resets-timer;
 	};
 
+	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 {
 		compatible = "qcom,rpm-log";
 		reg = <0xfc19dc00 0x4000>;
@@ -386,4 +393,10 @@
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
+
+	qcom,rpm-rbcpr-stats@fc000000 {
+		compatible = "qcom,rpmrbcpr-stats";
+		reg = <0xfc000000 0x1a0000>;
+		qcom,start-offset = <0x190010>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
index e3bd631..2e18ed7 100644
--- a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
@@ -45,7 +45,42 @@
                 qcom,sensor-mode = <1>;
                 qcom,cci-master = <0>;
         };
-
-
+	qcom,camera@78 {
+		compatible = "shinetech,gc0339";
+		reg = <0x78>;
+		qcom,slave-id = <0x42 0x00 0xc8>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <180>;
+		qcom,sensor-name = "SKUAA_ST_gc0339";
+		cam_vdig-supply = <&pm8110_l14>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 14 0>,
+				<&msmgpio 15 0>,
+				<&msmgpio 8 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+				"CAM_RESET",
+				"CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0xe4>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 90225c0..7b45194 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -78,6 +78,15 @@
 		};
 	};
 
+	flashlight {
+		compatible = "qcom,leds-gpio-flash";
+		status = "okay";
+		qcom,flash-en = <&msmgpio 18 0>;
+		qcom,flash-now = <&msmgpio 19 0>;
+		linux,name = "flashlight";
+		linux,default-trigger = "flashlight-trigger";
+	};
+
 	gpio_keys {
                 compatible = "gpio-keys";
                 input-name = "gpio-keys";
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 72d9317..ad0980c 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -769,6 +769,9 @@
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
 		qcom,freq-control-mask = <0xf>;
+		qcom,core-limit-temp = <80>;
+		qcom,core-temp-hysteresis = <10>;
+		qcom,core-control-mask = <0xe>;
 	};
 
 	qcom,ipc-spinlock@fd484000 {
@@ -819,12 +822,6 @@
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
 	};
 
-	qcom,msm-contig-mem {
-		compatible = "qcom,msm-contig-mem";
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
-	};
-
 	jtag_mm0: jtagmm@fc34c000 {
 		compatible = "qcom,jtag-mm";
 		reg = <0xfc34c000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 1610f1f..9fee2e5 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -369,8 +369,9 @@
 		compatible = "qcom,coresight-hwevent";
 		reg = <0xfdf30018 0x80>,
 		      <0xf9011080 0x80>,
-		      <0xfd4ab160 0x80>;
-		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+		      <0xfd4ab160 0x80>,
+		      <0xfc401600 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
 
 		coresight-id = <29>;
 		coresight-name = "coresight-hwevent";
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index eed1aae..686cdd8 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -26,12 +26,11 @@
 		qcom,saw2-spm-dly= <0x3C102800>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
 	};
 
 	qcom,spm@f9099000 {
@@ -49,12 +48,11 @@
 		qcom,saw2-spm-dly= <0x3C102800>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
 	};
 
 	qcom,spm@f90a9000 {
@@ -72,12 +70,11 @@
 		qcom,saw2-spm-dly= <0x3C102800>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
 	};
 
 	qcom,spm@f90b9000 {
@@ -95,12 +92,11 @@
 		qcom,saw2-spm-dly= <0x3C102800>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
-				0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
-				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
 	};
 
 	qcom,spm@f9012000 {
@@ -125,7 +121,7 @@
 		qcom,pfm-port = <0x2>;
 		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
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
 	};
 
@@ -453,4 +449,10 @@
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
+
+	qcom,rpm-rbcpr-stats@fc000000 {
+		compatible = "qcom,rpmrbcpr-stats";
+		reg = <0xfc000000 0x1a0000>;
+		qcom,start-offset = <0x190010>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625-v2.1.dtsi b/arch/arm/boot/dts/msm9625-v2.1.dtsi
index 65ff96a..5720700 100644
--- a/arch/arm/boot/dts/msm9625-v2.1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.1.dtsi
@@ -34,3 +34,7 @@
 &ipa_hw {
 	qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
 };
+
+&hsusb_otg {
+	qcom,hsusb-l1-supported;
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index b078309..14105cb 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -46,3 +46,7 @@
 &ldrex_spinlock {
 	status = "ok";
 };
+
+&hsusb_otg {
+	qcom,hsusb-l1-supported;
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 636c0f8..616995f 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -148,7 +148,7 @@
 		interrupts = <0 109 0>;
 	};
 
-	usb@f9a55000 {
+	hsusb_otg: usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0 0 140 0>;
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 968daff..a9cca0b 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -96,4 +96,9 @@
 		qcom,pet-time = <10000>;
 		qcom,ipi-ping;
 	};
+
+	qcom,msm-mem-hole {
+		compatible = "qcom,msm-mem-hole";
+		qcom,memblock-remove = <0x07f00000 0x8000000>; /* Address and size of hole */
+	};
 };
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 8f27332..4a5c9a7 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -327,6 +327,18 @@
 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
@@ -408,8 +420,10 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index d3ab40b..02d4873 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -352,6 +352,18 @@
 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
@@ -444,8 +456,10 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 8a7ee57..07f7ed9 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -272,6 +272,7 @@
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
+CONFIG_s5k4e1=y
 CONFIG_HI256=y
 CONFIG_MSM_CAMERA_SENSOR=y
 # CONFIG_MSM_CPP is not set
@@ -382,3 +383,4 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_INPUT_KXTJ9=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 95c3476..34c0905 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -270,6 +270,7 @@
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
+CONFIG_s5k4e1=y
 CONFIG_HI256=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_CCI=y
@@ -352,6 +353,7 @@
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_MSM_GPIO_FLASH=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
@@ -424,3 +426,4 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_INPUT_KXTJ9=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index c1c6b46..cdf4263 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -63,6 +63,7 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
@@ -481,3 +482,4 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 5d0749b..19d428b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -62,6 +62,7 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_MSM_BUSPM_DEV=m
 CONFIG_MSM_WATCHDOG_V2=y
@@ -513,3 +514,4 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e9a236e..17db01e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -309,6 +309,7 @@
 obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
 obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
+obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index c722304..2c120da 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -44,6 +44,8 @@
 
 uint32_t acpuclk_get_switch_time(void)
 {
+	if (!acpuclk_data)
+		return 0;
 	return acpuclk_data->switch_time_us;
 }
 
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 378edc8..a32031d 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -136,8 +136,8 @@
 static struct gpiomux_setting lcd_rst_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-	.dir = GPIOMUX_OUT_LOW,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_OUT_HIGH,
 };
 
 static struct gpiomux_setting lcd_rst_sus_cfg = {
@@ -211,6 +211,18 @@
 			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
 		},
 	},
+	{					/*  NFC   */
+		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{					/*  NFC   */
+		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_synaptics_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index b40fcfa..0d06b83 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -31,19 +31,6 @@
 #include "clock.h"
 #include "devices.h"
 
-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 = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
 static struct of_dev_auxdata msmkrypton_auxdata_lookup[] __initdata = {
 	{}
 };
@@ -57,7 +44,7 @@
 void __init msmkrypton_add_drivers(void)
 {
 	msm_smd_init();
-	msm_clock_init(&msm_dummy_clock_init_data);
+	msm_clock_init(&msmkrypton_clock_init_data);
 }
 
 static void __init msmkrypton_map_io(void)
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 7f0a394..2a4617d 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2901,6 +2901,7 @@
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &xo.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &xo.c);
 
 
 #ifdef CONFIG_DEBUG_FS
@@ -3113,6 +3114,9 @@
 	CLK_LOOKUP("apc3_m_clk", apc3_m_clk, ""),
 	CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
 
+	/* LPM Resources */
+	CLK_LOOKUP("xo",          cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
+
 	/* PIL-LPASS */
 	CLK_LOOKUP("xo",          cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
 	CLK_LOOKUP("core_clk",          q6ss_xo_clk.c, "fe200000.qcom,lpass"),
@@ -3125,7 +3129,8 @@
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("iface_clk",   gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("mem_clk",    gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
-
+	/* NFC */
+	CLK_LOOKUP("ref_clk",            cxo_d1_a_pin.c, "2-000e"),
 	/* PIL-PRONTO */
 	CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
 
@@ -3250,6 +3255,9 @@
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
 
+	/* I2C Clocks nfc */
+	CLK_LOOKUP("iface_clk",          gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
 	/* lsuart-v14 Clocks */
 	CLK_LOOKUP("iface_clk",       gcc_blsp1_ahb_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
@@ -3315,7 +3323,6 @@
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 18a81d0..eb9a627 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -510,6 +510,15 @@
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
 
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpass_pil_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_mss_pil_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mba_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_acpu_clk, &gcc_xo_clk_src.c);
+
 static DEFINE_CLK_MEASURE(apc0_m_clk);
 static DEFINE_CLK_MEASURE(apc1_m_clk);
 static DEFINE_CLK_MEASURE(apc2_m_clk);
@@ -2740,17 +2749,18 @@
 };
 
 static struct clk_lookup msm_clocks_8610[] = {
-	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "msm_otg"),
-	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("xo",	cxo_otg_clk.c, "msm_otg"),
+	CLK_LOOKUP("xo",	cxo_lpass_pil_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("xo",        cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
 
-	CLK_LOOKUP("xo",		gcc_xo_clk_src.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("xo",	       cxo_mss_pil_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("bus_clk",  gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("iface_clk",    gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("mem_clk",     gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
 
-	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "pil-mba"),
-	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
-	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fb21b000.qcom,pronto"),
+	CLK_LOOKUP("xo",       cxo_pil_mba_clk.c, "pil-mba"),
+	CLK_LOOKUP("xo",	  cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("xo",    cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991f000.serial"),
@@ -3000,9 +3010,11 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006f"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007d"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
 	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
 
@@ -3072,7 +3084,7 @@
 	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
 	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "fe200000.qcom,lpass"),
 
-	CLK_LOOKUP("xo",      gcc_xo_a_clk_src.c, "f9011050.qcom,acpuclk"),
+	CLK_LOOKUP("xo",        cxo_acpu_clk.c, "f9011050.qcom,acpuclk"),
 	CLK_LOOKUP("gpll0", gpll0_ao_clk_src.c, "f9011050.qcom,acpuclk"),
 	CLK_LOOKUP("a7sspll",        a7sspll.c, "f9011050.qcom,acpuclk"),
 
@@ -3082,7 +3094,7 @@
 	CLK_LOOKUP("measure_clk", apc3_m_clk, ""),
 	CLK_LOOKUP("measure_clk",   l2_m_clk, ""),
 
-	CLK_LOOKUP("xo",   gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("xo",     cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("rf_clk",       cxo_a1.c, "fb000000.qcom,wcnss-wlan"),
 
 	CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ac34ed3..bd5a12e 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -831,6 +831,7 @@
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_ehci_host_clk, &cxo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &cxo_clk_src.c);
 
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
 	F(125000000,  gpll0,   1,   5,  24),
@@ -4855,6 +4856,7 @@
 	CLK_LOOKUP("xo", cxo_pil_pronto_clk.c,     "fb21b000.qcom,pronto"),
 	CLK_LOOKUP("xo",       cxo_dwc3_clk.c,                 "msm_dwc3"),
 	CLK_LOOKUP("xo",  cxo_ehci_host_clk.c,            "msm_ehci_host"),
+	CLK_LOOKUP("xo",        cxo_lpm_clk.c,        "fc4281d0.qcom,mpm"),
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 14648ec..3b07069 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -430,9 +430,10 @@
 
 static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, LONG_MAX);
-
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
 
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &cxo_clk_src.c);
+
 static struct clk_freq_tbl ftbl_gcc_ipa_clk[] = {
 	F( 50000000,    gpll0,   12,   0,   0),
 	F( 92310000,    gpll0,  6.5,   0,   0),
@@ -1762,6 +1763,7 @@
 
 static struct clk_lookup msm_clocks_9625[] = {
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	""),
+	CLK_LOOKUP("xo",        cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("pll0", gpll0_activeonly_clk_src.c, "f9010008.qcom,acpuclk"),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index fe43b72..8ec87d1 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -22,6 +22,8 @@
 #include <linux/list.h>
 #include <linux/clkdev.h>
 #include <linux/uaccess.h>
+#include <linux/mutex.h>
+
 #include <mach/clk-provider.h>
 
 #include "clock.h"
@@ -351,49 +353,24 @@
 	debugfs_remove_recursive(clk_dir);
 	return -ENOMEM;
 }
-
-/**
- * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
- * @table: Table of clocks to create debugfs nodes for
- * @size: Size of @table
- *
- * Use this function to register additional clocks in debugfs. The clock debugfs
- * hierarchy must have already been initialized with clock_debug_init() prior to
- * calling this function. Unlike clock_debug_init(), this may be called multiple
- * times with different clock lists and can be used after the kernel has
- * finished booting.
- */
-int clock_debug_register(struct clk_lookup *table, size_t size)
-{
-	struct clk_table *clk_table;
-	unsigned long flags;
-	int i;
-
-	clk_table = kmalloc(sizeof(*clk_table), GFP_KERNEL);
-	if (!clk_table)
-		return -ENOMEM;
-
-	clk_table->clocks = table;
-	clk_table->num_clocks = size;
-
-	spin_lock_irqsave(&clk_list_lock, flags);
-	list_add_tail(&clk_table->node, &clk_list);
-	spin_unlock_irqrestore(&clk_list_lock, flags);
-
-	for (i = 0; i < size; i++)
-		clock_debug_add(table[i].clk);
-
-	return 0;
-}
+static DEFINE_MUTEX(clk_debug_lock);
+static int clk_debug_init_once;
 
 /**
  * clock_debug_init() - Initialize clock debugfs
+ * Lock clk_debug_lock before invoking this function.
  */
-int __init clock_debug_init(void)
+static int clock_debug_init(void)
 {
+	if (clk_debug_init_once)
+		return 0;
+
+	clk_debug_init_once = 1;
+
 	debugfs_base = debugfs_create_dir("clk", NULL);
 	if (!debugfs_base)
 		return -ENOMEM;
+
 	if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
 				debugfs_base, &debug_suspend)) {
 		debugfs_remove_recursive(debugfs_base);
@@ -407,6 +384,45 @@
 	return 0;
 }
 
+/**
+ * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
+ * @table: Table of clocks to create debugfs nodes for
+ * @size: Size of @table
+ *
+ */
+int clock_debug_register(struct clk_lookup *table, size_t size)
+{
+	struct clk_table *clk_table;
+	unsigned long flags;
+	int i, ret;
+
+	mutex_lock(&clk_debug_lock);
+
+	ret = clock_debug_init();
+	if (ret)
+		goto out;
+
+	clk_table = kmalloc(sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	clk_table->clocks = table;
+	clk_table->num_clocks = size;
+
+	spin_lock_irqsave(&clk_list_lock, flags);
+	list_add_tail(&clk_table->node, &clk_list);
+	spin_unlock_irqrestore(&clk_list_lock, flags);
+
+	for (i = 0; i < size; i++)
+		clock_debug_add(table[i].clk);
+
+out:
+	mutex_unlock(&clk_debug_lock);
+	return ret;
+}
+
 static int clock_debug_print_clock(struct clk *c)
 {
 	char *start = "";
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
new file mode 100644
index 0000000..aaee003
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -0,0 +1,125 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+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),
+
+	CLK_DUMMY("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc", OFF),
+	CLK_DUMMY("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc", OFF),
+	CLK_DUMMY("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc", OFF),
+	CLK_DUMMY("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc", OFF),
+	CLK_DUMMY("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc", OFF),
+	CLK_DUMMY("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc", OFF),
+	CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
+	CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
+	CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
+
+	CLK_DUMMY("clktype", gcc_imem_axi_clk         , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk     , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_mss_cfg_ahb_clk      , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_mss_q6_bimc_axi_clk  , "drivername", OFF),
+	CLK_DUMMY("mem_clk", gcc_usb30_master_clk     , "drivername", OFF),
+	CLK_DUMMY("sleep_clk", gcc_usb30_sleep_clk    , "drivername", OFF),
+	CLK_DUMMY("utmi_clk", gcc_usb30_mock_utmi_clk , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_usb_hsic_ahb_clk   , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_usb_hsic_system_clk , "drivername", OFF),
+	CLK_DUMMY("phyclk", gcc_usb_hsic_clk         , "drivername", OFF),
+	CLK_DUMMY("cal_clk", gcc_usb_hsic_io_cal_clk  , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_usb_hs_system_clk   , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_usb_hs_ahb_clk     , "drivername", OFF),
+	CLK_DUMMY("sleep_a_clk", gcc_usb2a_phy_sleep_clk  , "drivername", OFF),
+	CLK_DUMMY("sleep_b_clk", gcc_usb2b_phy_sleep_clk  , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_sdcc2_apps_clk      , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_sdcc2_ahb_clk      , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_sdcc3_apps_clk      , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_sdcc3_ahb_clk      , "drivername", OFF),
+	CLK_DUMMY("core_clk", sdcc3_apps_clk_src      , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk      , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup1_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup1_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart1_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup2_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup2_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart2_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup3_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart3_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup4_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup4_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart4_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup5_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup5_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart5_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup6_spi_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_qup6_i2c_apps_clk, "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_blsp1_uart6_apps_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk", blsp1_uart6_apps_clk_src , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_pdm_ahb_clk        , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_pdm2_clk            , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_prng_ahb_clk        , "drivername", OFF),
+	CLK_DUMMY("dma_bam_pclk", gcc_bam_dma_ahb_clk , "drivername", OFF),
+	CLK_DUMMY("mem_clk", gcc_boot_rom_ahb_clk     , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_ce1_clk             , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_ce1_axi_clk         , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_ce1_ahb_clk         , "drivername", OFF),
+	CLK_DUMMY("core_clk_src", ce1_clk_src         , "drivername", OFF),
+	CLK_DUMMY("bus_clk", gcc_lpass_q6_axi_clk     , "drivername", OFF),
+	CLK_DUMMY("clktype", pcie_pipe_clk            , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_gp1_clk              , "drivername", OFF),
+	CLK_DUMMY("clktype", gp1_clk_src              , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_gp2_clk              , "drivername", OFF),
+	CLK_DUMMY("clktype", gp2_clk_src              , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_gp3_clk              , "drivername", OFF),
+	CLK_DUMMY("clktype", gp3_clk_src              , "drivername", OFF),
+	CLK_DUMMY("core_clk", gcc_ipa_clk             , "drivername", OFF),
+	CLK_DUMMY("iface_clk", gcc_ipa_cnoc_clk       , "drivername", OFF),
+	CLK_DUMMY("inactivity_clk", gcc_ipa_sleep_clk , "drivername", OFF),
+	CLK_DUMMY("core_clk_src", ipa_clk_src         , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_dcs_clk              , "drivername", OFF),
+	CLK_DUMMY("clktype", dcs_clk_src              , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_pcie_cfg_ahb_clk     , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_pcie_pipe_clk        , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_pcie_axi_clk         , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_pcie_sleep_clk       , "drivername", OFF),
+	CLK_DUMMY("clktype", gcc_pcie_axi_mstr_clk    , "drivername", OFF),
+	CLK_DUMMY("clktype", pcie_pipe_clk_src        , "drivername", OFF),
+	CLK_DUMMY("clktype", pcie_aux_clk_src         , "drivername", OFF),
+};
+
+struct clock_init_data msmkrypton_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 582bccf..3c43223 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -23,6 +23,7 @@
 #include <linux/clkdev.h>
 #include <linux/list.h>
 #include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
 #include <trace/events/power.h>
 #include <mach/clk-provider.h>
 #include "clock.h"
@@ -39,6 +40,8 @@
 };
 static LIST_HEAD(handoff_vdd_list);
 
+static DEFINE_MUTEX(msm_clock_init_lock);
+
 /* Find the voltage level required for a given rate. */
 int find_vdd_level(struct clk *clk, unsigned long rate)
 {
@@ -573,7 +576,7 @@
 }
 EXPORT_SYMBOL(clk_set_flags);
 
-static struct clock_init_data *clk_init_data;
+static LIST_HEAD(initdata_list);
 
 static void init_sibling_lists(struct clk_lookup *clock_tbl, size_t num_clocks)
 {
@@ -588,33 +591,6 @@
 	}
 }
 
-/**
- * msm_clock_register() - Register additional clock tables
- * @table: Table of clocks
- * @size: Size of @table
- *
- * Upon return, clock APIs may be used to control clocks registered using this
- * function. This API may only be used after msm_clock_init() has completed.
- * Unlike msm_clock_init(), this function may be called multiple times with
- * different clock lists and used after the kernel has finished booting.
- */
-int msm_clock_register(struct clk_lookup *table, size_t size)
-{
-	if (!clk_init_data)
-		return -ENODEV;
-
-	if (!table)
-		return -EINVAL;
-
-	init_sibling_lists(table, size);
-	clkdev_add_table(table, size);
-	clock_debug_register(table, size);
-
-	return 0;
-}
-EXPORT_SYMBOL(msm_clock_register);
-
-
 static void vdd_class_init(struct clk_vdd_class *vdd)
 {
 	struct handoff_vdd *v;
@@ -646,7 +622,7 @@
 	list_add_tail(&v->list, &handoff_vdd_list);
 }
 
-static int __init __handoff_clk(struct clk *clk)
+static int __handoff_clk(struct clk *clk)
 {
 	enum handoff state = HANDOFF_DISABLED_CLK;
 	struct handoff_clk *h = NULL;
@@ -726,29 +702,20 @@
 }
 
 /**
- * msm_clock_init() - Register and initialize a clock driver
- * @data: Driver-specific clock initialization data
+ * msm_clock_register() - Register additional clock tables
+ * @table: Table of clocks
+ * @size: Size of @table
  *
- * Upon return from this call, clock APIs may be used to control
- * clocks registered with this API.
+ * Upon return, clock APIs may be used to control clocks registered using this
+ * function.
  */
-int __init msm_clock_init(struct clock_init_data *data)
+int msm_clock_register(struct clk_lookup *table, size_t size)
 {
-	unsigned n;
-	struct clk_lookup *clock_tbl;
-	size_t num_clocks;
+	int n = 0;
 
-	if (!data)
-		return -EINVAL;
+	mutex_lock(&msm_clock_init_lock);
 
-	clk_init_data = data;
-	if (clk_init_data->pre_init)
-		clk_init_data->pre_init();
-
-	clock_tbl = data->table;
-	num_clocks = data->size;
-
-	init_sibling_lists(clock_tbl, num_clocks);
+	init_sibling_lists(table, size);
 
 	/*
 	 * Enable regulators and temporarily set them up at maximum voltage.
@@ -757,23 +724,50 @@
 	 * late_init, by which time we assume all the clocks would have been
 	 * handed off.
 	 */
-	for (n = 0; n < num_clocks; n++)
-		vdd_class_init(clock_tbl[n].clk->vdd_class);
+	for (n = 0; n < size; n++)
+		vdd_class_init(table[n].clk->vdd_class);
 
 	/*
 	 * Detect and preserve initial clock state until clock_late_init() or
 	 * a driver explicitly changes it, whichever is first.
 	 */
-	for (n = 0; n < num_clocks; n++)
-		__handoff_clk(clock_tbl[n].clk);
+	for (n = 0; n < size; n++)
+		__handoff_clk(table[n].clk);
 
-	clkdev_add_table(clock_tbl, num_clocks);
+	clkdev_add_table(table, size);
 
-	if (clk_init_data->post_init)
-		clk_init_data->post_init();
+	clock_debug_register(table, size);
 
-	clock_debug_init();
-	clock_debug_register(clock_tbl, num_clocks);
+	mutex_unlock(&msm_clock_init_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_clock_register);
+
+/**
+ * msm_clock_init() - Register and initialize a clock driver
+ * @data: Driver-specific clock initialization data
+ *
+ * Upon return from this call, clock APIs may be used to control
+ * clocks registered with this API.
+ */
+int __init msm_clock_init(struct clock_init_data *data)
+{
+	if (!data)
+		return -EINVAL;
+
+	if (data->pre_init)
+		data->pre_init();
+
+	mutex_lock(&msm_clock_init_lock);
+	if (data->late_init)
+		list_add(&data->list, &initdata_list);
+	mutex_unlock(&msm_clock_init_lock);
+
+	msm_clock_register(data->table, data->size);
+
+	if (data->post_init)
+		data->post_init();
 
 	return 0;
 }
@@ -782,12 +776,21 @@
 {
 	struct handoff_clk *h, *h_temp;
 	struct handoff_vdd *v, *v_temp;
+	struct clock_init_data *initdata, *initdata_temp;
 	int ret = 0;
 
-	if (clk_init_data->late_init)
-		ret = clk_init_data->late_init();
-
 	pr_info("%s: Removing enables held for handed-off clocks\n", __func__);
+
+	mutex_lock(&msm_clock_init_lock);
+
+	list_for_each_entry_safe(initdata, initdata_temp,
+					&initdata_list, list) {
+		ret = initdata->late_init();
+		if (ret)
+			pr_err("%s: %pS failed late_init.\n", __func__,
+				initdata);
+	}
+
 	list_for_each_entry_safe(h, h_temp, &handoff_list, list) {
 		clk_disable_unprepare(h->clk);
 		list_del(&h->list);
@@ -800,6 +803,11 @@
 		kfree(v);
 	}
 
+	mutex_unlock(&msm_clock_init_lock);
+
 	return ret;
 }
-late_initcall(clock_late_init);
+/* clock_late_init should run only after all deferred probing
+ * (excluding DLKM probes) has completed.
+ */
+late_initcall_sync(clock_late_init);
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 2a65d2f..e294f4c 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -26,6 +26,7 @@
  * @late_init: called during late init
  */
 struct clock_init_data {
+	struct list_head list;
 	struct clk_lookup *table;
 	size_t size;
 	void (*pre_init)(void);
@@ -55,16 +56,15 @@
 extern struct clock_init_data msm8226_rumi_clock_init_data;
 extern struct clock_init_data msm8084_clock_init_data;
 extern struct clock_init_data mpq8092_clock_init_data;
+extern struct clock_init_data msmkrypton_clock_init_data;
 
 int msm_clock_init(struct clock_init_data *data);
 int find_vdd_level(struct clk *clk, unsigned long rate);
 
 #ifdef CONFIG_DEBUG_FS
-int clock_debug_init(void);
 int clock_debug_register(struct clk_lookup *t, size_t s);
 void clock_debug_print_enabled(void);
 #else
-static inline int clock_debug_init(void) { return 0; }
 static inline int clock_debug_register(struct clk_lookup *t, size_t s)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index eeda7ce..541ca44 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -189,7 +189,8 @@
 };
 
 enum dump_reg {
-	DUMP_REG_FAR0,
+	DUMP_REG_FIRST,
+	DUMP_REG_FAR0 = DUMP_REG_FIRST,
 	DUMP_REG_FAR1,
 	DUMP_REG_PAR0,
 	DUMP_REG_PAR1,
@@ -201,10 +202,23 @@
 	DUMP_REG_SCTLR,
 	DUMP_REG_ACTLR,
 	DUMP_REG_PRRR,
+	DUMP_REG_MAIR0 = DUMP_REG_PRRR,
 	DUMP_REG_NMRR,
+	DUMP_REG_MAIR1 = DUMP_REG_NMRR,
 	MAX_DUMP_REGS,
 };
 
+struct dump_regs_tbl {
+	/*
+	 * To keep things context-bank-agnostic, we only store the CB
+	 * register offset in `key'
+	 */
+	unsigned long key;
+	const char *name;
+	int offset;
+};
+extern struct dump_regs_tbl dump_regs_tbl[MAX_DUMP_REGS];
+
 #define COMBINE_DUMP_REG(upper, lower) (((u64) upper << 32) | lower)
 
 struct msm_iommu_context_reg {
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 1c20d04..04cd441 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -19,6 +19,8 @@
 #define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
 #define GET_CTX_REG(reg, base, ctx) \
 	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+#define GET_CTX_REG_L(reg, base, ctx) \
+	(readll_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
 
 #define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
 
@@ -196,7 +198,7 @@
 #define GET_CONTEXTIDR(b, c)     GET_CTX_REG(CB_CONTEXTIDR, (b), (c))
 #define GET_PRRR(b, c)           GET_CTX_REG(CB_PRRR, (b), (c))
 #define GET_NMRR(b, c)           GET_CTX_REG(CB_NMRR, (b), (c))
-#define GET_PAR(b, c)            GET_CTX_REG(CB_PAR, (b), (c))
+#define GET_PAR(b, c)            GET_CTX_REG_L(CB_PAR, (b), (c))
 #define GET_FSR(b, c)            GET_CTX_REG(CB_FSR, (b), (c))
 #define GET_FSRRESTORE(b, c)     GET_CTX_REG(CB_FSRRESTORE, (b), (c))
 #define GET_FAR(b, c)            GET_CTX_REG(CB_FAR, (b), (c))
@@ -1307,6 +1309,7 @@
 #define CB_PAR_TF          (CB_PAR_TF_MASK     << CB_PAR_TF_SHIFT)
 #define CB_PAR_AFF         (CB_PAR_AFF_MASK    << CB_PAR_AFF_SHIFT)
 #define CB_PAR_PF          (CB_PAR_PF_MASK     << CB_PAR_PF_SHIFT)
+#define CB_PAR_EF          (CB_PAR_EF_MASK     << CB_PAR_EF_SHIFT)
 #define CB_PAR_TLBMCF      (CB_PAR_TLBMCF_MASK << CB_PAR_TLBMCF_SHIFT)
 #define CB_PAR_TLBLKF      (CB_PAR_TLBLKF_MASK << CB_PAR_TLBLKF_SHIFT)
 #define CB_PAR_ATOT        (CB_PAR_ATOT_MASK   << CB_PAR_ATOT_SHIFT)
@@ -1682,11 +1685,12 @@
 #define CB_PAR_TF_MASK          0x01
 #define CB_PAR_AFF_MASK         0x01
 #define CB_PAR_PF_MASK          0x01
+#define CB_PAR_EF_MASK          0x01
 #define CB_PAR_TLBMCF_MASK      0x01
 #define CB_PAR_TLBLKF_MASK      0x01
-#define CB_PAR_ATOT_MASK        0x01
-#define CB_PAR_PLVL_MASK        0x03
-#define CB_PAR_STAGE_MASK       0x01
+#define CB_PAR_ATOT_MASK        0x01ULL
+#define CB_PAR_PLVL_MASK        0x03ULL
+#define CB_PAR_STAGE_MASK       0x01ULL
 
 /* Primary Region Remap Register: CB_PRRR */
 #define CB_PRRR_TR0_MASK        0x03
@@ -2052,11 +2056,12 @@
 #define CB_PAR_TF_SHIFT            1
 #define CB_PAR_AFF_SHIFT           2
 #define CB_PAR_PF_SHIFT            3
+#define CB_PAR_EF_SHIFT            4
 #define CB_PAR_TLBMCF_SHIFT        5
 #define CB_PAR_TLBLKF_SHIFT        6
 #define CB_PAR_ATOT_SHIFT          31
-#define CB_PAR_PLVL_SHIFT          0
-#define CB_PAR_STAGE_SHIFT         3
+#define CB_PAR_PLVL_SHIFT          32
+#define CB_PAR_STAGE_SHIFT         35
 
 /* Primary Region Remap Register: CB_PRRR */
 #define CB_PRRR_TR0_SHIFT          0
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index a87380c..f5f1954 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -29,6 +29,7 @@
 enum msm_ipc_router_event {
 	MSM_IPC_ROUTER_READ_CB = 0,
 	MSM_IPC_ROUTER_WRITE_DONE,
+	MSM_IPC_ROUTER_RESUME_TX,
 };
 
 struct comm_mode_info {
diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
index 11867f3..1641e8c 100644
--- a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
+++ b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 #include <linux/socket.h>
 #include <linux/gfp.h>
 #include <linux/qmi_encdec.h>
+#include <linux/workqueue.h>
 
 #define QMI_COMMON_TLV_TYPE 0
 
@@ -45,6 +46,8 @@
 	void *ind_cb_priv;
 	int handle_reset;
 	wait_queue_head_t reset_waitq;
+	struct list_head pending_txn_list;
+	struct delayed_work resume_tx_work;
 };
 
 enum qmi_result_type_v01 {
@@ -153,7 +156,8 @@
 			void *resp, unsigned int resp_len,
 			void (*resp_cb)(struct qmi_handle *handle,
 					unsigned int msg_id, void *msg,
-					void *resp_cb_data),
+					void *resp_cb_data,
+					int stat),
 			void *resp_cb_data);
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 2cfb5ac..661d496 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.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
@@ -53,6 +53,12 @@
 /* Encoder/decoder configuration block */
 #define USM_PARAM_ID_ENCDEC_ENC_CFG_BLK			0x0001230D
 
+/* Max number of static located ports (bytes) */
+#define USM_MAX_PORT_NUMBER 8
+
+/* Max number of static located transparent data (bytes) */
+#define USM_MAX_CFG_DATA_SIZE 100
+
 /* Parameter structures used in  USM_STREAM_CMD_SET_ENCDEC_PARAM command */
 /* common declarations */
 struct usm_cfg_common {
@@ -60,26 +66,7 @@
 	u16 bits_per_sample;
 	u32 sample_rate;
 	u32 dev_id;
-	u32 data_map;
-} __packed;
-
-/* Max number of static located transparent data (bytes) */
-#define USM_MAX_CFG_DATA_SIZE 100
-struct usm_encode_cfg_blk {
-	u32 frames_per_buf;
-	u32 format_id;
-	/* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
-	u32 cfg_size;
-	struct usm_cfg_common cfg_common;
-	/* Transparent configuration data for specific encoder */
-	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
-} __packed;
-
-struct usm_stream_cmd_encdec_cfg_blk {
-	struct apr_hdr hdr;
-	u32 param_id;
-	u32 param_size;
-	struct usm_encode_cfg_blk enc_blk;
+	u8 data_map[USM_MAX_PORT_NUMBER];
 } __packed;
 
 struct us_encdec_cfg {
@@ -89,16 +76,6 @@
 	u8 *params;
 } __packed;
 
-struct usm_stream_media_format_update {
-	struct apr_hdr hdr;
-	u32 format_id;
-	/* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
-	u32 cfg_size;
-	struct usm_cfg_common cfg_common;
-	/* Transparent configuration data for specific encoder */
-	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
-} __packed;
-
 /* Start/stop US signal detection */
 #define USM_SESSION_CMD_SIGNAL_DETECT_MODE		0x00012719
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
index 4008698..782f3ae 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -56,4 +56,43 @@
 
 #define USM_DATA_EVENT_WRITE_DONE			0x00011274
 
+/* Max number of static located ports (bytes) */
+#define USM_MAX_PORT_NUMBER_A 4
+
+/* Parameter structures used in  USM_STREAM_CMD_SET_ENCDEC_PARAM command */
+/* common declarations */
+struct usm_cfg_common_a {
+	u16 ch_cfg;
+	u16 bits_per_sample;
+	u32 sample_rate;
+	u32 dev_id;
+	u8 data_map[USM_MAX_PORT_NUMBER_A];
+} __packed;
+
+struct usm_stream_media_format_update {
+	struct apr_hdr hdr;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common_a cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_encode_cfg_blk {
+	u32 frames_per_buf;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common_a cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+	struct apr_hdr hdr;
+	u32 param_id;
+	u32 param_size;
+	struct usm_encode_cfg_blk enc_blk;
+} __packed;
 #endif /* __APR_US_A_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
index 11de6ef..26e8369 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
@@ -67,4 +67,30 @@
 
 #define USM_DATA_EVENT_WRITE_DONE		0x00012727
 
+struct usm_stream_media_format_update {
+	struct apr_hdr hdr;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_encode_cfg_blk {
+	u32 frames_per_buf;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+	struct apr_hdr hdr;
+	u32 param_id;
+	u32 param_size;
+	struct usm_encode_cfg_blk enc_blk;
+} __packed;
 #endif /* __APR_US_B_H__ */
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index a3e993d..b2dd49c 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -198,14 +198,6 @@
 		struct usb_bam_connect_ipa_params *ipa_params);
 
 /**
- * Wait for Consumer granted from Resource Manager.
- *
- * @ipa_params - in/out parameters
- *
- */
-void usb_bam_wait_for_cons_granted(
-	struct usb_bam_connect_ipa_params *ipa_params);
-/**
  * Register a wakeup callback from peer BAM.
  *
  * @idx - Connection index.
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 9ec8395..32589f1 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -735,8 +735,14 @@
 				&rport_ptr->resume_tx_port_list, list) {
 		local_port =
 			msm_ipc_router_lookup_local_port(rtx_port->port_id);
-		if (local_port)
+		if (local_port && local_port->notify)
+			local_port->notify(MSM_IPC_ROUTER_RESUME_TX,
+						local_port->priv);
+		else if (local_port)
 			post_pkt_to_port(local_port, pkt, 1);
+		else
+			pr_err("%s: Local Port %d not Found",
+				__func__, rtx_port->port_id);
 		list_del(&rtx_port->list);
 		kfree(rtx_port);
 	}
@@ -2216,6 +2222,8 @@
 	}
 
 	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
+	if (ret == -EAGAIN)
+		return ret;
 	if (ret < 0) {
 		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
 			__func__, ret);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 7c1b8d6..b30cba4 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -131,6 +131,15 @@
 #define VREF_LDO_BIT_POS	0
 #define VREF_LDO_MASK		KRAIT_MASK(6, 0)
 
+#define PWR_GATE_SWITCH_MODE_POS	4
+#define PWR_GATE_SWITCH_MODE_MASK	KRAIT_MASK(6, 4)
+
+#define PWR_GATE_SWITCH_MODE_PC		0
+#define PWR_GATE_SWITCH_MODE_LDO	1
+#define PWR_GATE_SWITCH_MODE_BHS	2
+#define PWR_GATE_SWITCH_MODE_DT		3
+#define PWR_GATE_SWITCH_MODE_RET	4
+
 #define LDO_HDROOM_MIN		50000
 #define LDO_HDROOM_MAX		250000
 
@@ -144,6 +153,10 @@
 #define LDO_DELTA_MAX		100000
 
 #define MSM_L2_SAW_PHYS		0xf9012000
+#define MSM_MDD_BASE_PHYS	0xf908a800
+
+#define KPSS_VERSION_2P0	0x20000000
+
 /**
  * struct pmic_gang_vreg -
  * @name:			the string used to represent the gang
@@ -580,35 +593,55 @@
 	if (kvreg->mode == HS_MODE)
 		return 0;
 	/* enable bhs */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
-	/* complete the above write before the delay */
-	mb();
-	/* wait for the bhs to settle */
-	udelay(BHS_SETTLING_DELAY_US);
+	if (version > KPSS_VERSION_2P0) {
+		krait_masked_write(kvreg, APC_PWR_GATE_MODE,
+			PWR_GATE_SWITCH_MODE_MASK,
+			PWR_GATE_SWITCH_MODE_BHS << PWR_GATE_SWITCH_MODE_POS);
 
-	/* Turn on BHS segments */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+		/* complete the writes before the delay */
+		mb();
 
-	/* complete the above write before the delay */
-	mb();
+		/* wait for the bhs to settle */
+		udelay(BHS_SETTLING_DELAY_US);
+	} else {
+		/* enable bhs */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+						BHS_EN_MASK, BHS_EN_MASK);
 
-	/*
-	 * wait for the bhs to settle - note that
-	 * after the voltage has settled both BHS and LDO are supplying power
-	 * to the krait. This avoids glitches during switching
-	 */
-	udelay(BHS_SETTLING_DELAY_US);
+		/* complete the above write before the delay */
+		mb();
 
-	/*
-	 * enable ldo bypass - the krait is powered still by LDO since
-	 * LDO is enabled
-	 */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
+		/* wait for the bhs to settle */
+		udelay(BHS_SETTLING_DELAY_US);
 
-	/* disable ldo - only the BHS provides voltage to the cpu after this */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		/* Turn on BHS segments */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK,
+				BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+
+		/* complete the above write before the delay */
+		mb();
+
+		/*
+		 * wait for the bhs to settle - note that
+		 * after the voltage has settled both BHS and LDO are supplying
+		 * power to the krait. This avoids glitches during switching
+		 */
+		udelay(BHS_SETTLING_DELAY_US);
+
+		/*
+		 * enable ldo bypass - the krait is powered still by LDO since
+		 * LDO is enabled
+		 */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+				LDO_BYP_MASK, LDO_BYP_MASK);
+
+		/*
+		 * disable ldo - only the BHS provides voltage to
+		 * the cpu after this
+		 */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL,
 				LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
+	}
 
 	kvreg->mode = HS_MODE;
 	pr_debug("%s using BHS\n", kvreg->name);
@@ -629,27 +662,39 @@
 		switch_to_using_hs(kvreg);
 
 	set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
+	if (version > KPSS_VERSION_2P0) {
+		krait_masked_write(kvreg, APC_PWR_GATE_MODE,
+			PWR_GATE_SWITCH_MODE_MASK,
+			PWR_GATE_SWITCH_MODE_LDO << PWR_GATE_SWITCH_MODE_POS);
 
-	/*
-	 * enable ldo - note that both LDO and BHS are are supplying voltage to
-	 * the cpu after this. This avoids glitches during switching from BHS
-	 * to LDO.
-	 */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_PWR_DWN_MASK, 0);
+		/* complete the writes before the delay */
+		mb();
 
-	/* complete the writes before the delay */
-	mb();
+		/* wait for the ldo to settle */
+		udelay(LDO_SETTLING_DELAY_US);
+	} else {
+		/*
+		 * enable ldo - note that both LDO and BHS are are supplying
+		 * voltage to the cpu after this. This avoids glitches during
+		 * switching from BHS to LDO.
+		 */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+						LDO_PWR_DWN_MASK, 0);
 
-	/* wait for the ldo to settle */
-	udelay(LDO_SETTLING_DELAY_US);
+		/* complete the writes before the delay */
+		mb();
 
-	/*
-	 * disable BHS and disable LDO bypass seperate from enabling
-	 * the LDO above.
-	 */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		BHS_EN_MASK | LDO_BYP_MASK, 0);
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
+		/* wait for the ldo to settle */
+		udelay(LDO_SETTLING_DELAY_US);
+
+		/*
+		 * disable BHS and disable LDO bypass seperate from enabling
+		 * the LDO above.
+		 */
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+			BHS_EN_MASK | LDO_BYP_MASK, 0);
+		krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
+	}
 
 	kvreg->mode = LDO_MODE;
 	pr_debug("%s using LDO\n", kvreg->name);
@@ -993,22 +1038,34 @@
 DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
 			get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
 
+static void kvreg_ldo_voltage_init(struct krait_power_vreg *kvreg)
+{
+	set_krait_retention_uv(kvreg, kvreg->retention_uV);
+	set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
+}
+
 #define CPU_PWR_CTL_ONLINE_MASK 0x80
 static void kvreg_hw_init(struct krait_power_vreg *kvreg)
 {
-	int online;
-	/*
-	 * bhs_cnt value sets the ramp-up time from power collapse,
-	 * initialize the ramp up time
-	 */
-	set_krait_retention_uv(kvreg, kvreg->retention_uV);
-	set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
-
 	/* setup the bandgap that configures the reference to the LDO */
 	writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
 	/* Enable MDD */
 	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
+
+	if (version > KPSS_VERSION_2P0) {
+		/* Configure hardware sequencer delays. */
+		writel_relaxed(0x30430600, kvreg->reg_base + APC_PWR_GATE_DLY);
+
+		/* Enable the hardware sequencer in BHS mode. */
+		writel_relaxed(0x00000021, kvreg->reg_base + APC_PWR_GATE_MODE);
+	}
+}
+
+static void online_at_probe(struct krait_power_vreg *kvreg)
+{
+	int online;
+
 	online = CPU_PWR_CTL_ONLINE_MASK
 			& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
 	kvreg->online_at_probe
@@ -1017,11 +1074,15 @@
 
 static void glb_init(void __iomem *apcs_gcc_base)
 {
-	/* configure bi-modal switch */
-	writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
 	/* read kpss version */
 	version = readl_relaxed(apcs_gcc_base + VERSION);
 	pr_debug("version= 0x%x\n", version);
+
+	/* configure bi-modal switch */
+	if (version > KPSS_VERSION_2P0)
+		writel_relaxed(0x0308736E, apcs_gcc_base + PWR_GATE_CONFIG);
+	else
+		writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
 }
 
 static int __devinit krait_power_probe(struct platform_device *pdev)
@@ -1179,6 +1240,14 @@
 	list_add_tail(&kvreg->link, &the_gang->krait_power_vregs);
 	mutex_unlock(&the_gang->krait_power_vregs_lock);
 
+	online_at_probe(kvreg);
+	kvreg_ldo_voltage_init(kvreg);
+
+	if (kvreg->cpu_num == 0)
+		kvreg_hw_init(kvreg);
+
+	per_cpu(krait_vregs, cpu_num) = kvreg;
+
 	kvreg->rdev = regulator_register(&kvreg->desc, &pdev->dev, init_data,
 					 kvreg, pdev->dev.of_node);
 	if (IS_ERR(kvreg->rdev)) {
@@ -1187,8 +1256,6 @@
 		goto out;
 	}
 
-	kvreg_hw_init(kvreg);
-	per_cpu(krait_vregs, cpu_num) = kvreg;
 	dev_dbg(&pdev->dev, "id=%d, name=%s\n", pdev->id, kvreg->name);
 
 	return 0;
@@ -1426,10 +1493,29 @@
 }
 module_exit(krait_power_exit);
 
-void secondary_cpu_hs_init(void *base_ptr)
+#define GCC_BASE	0xF9011000
+
+/**
+ * secondary_cpu_hs_init - Initialize BHS and LDO registers
+ *				for nonboot cpu
+ *
+ * @base_ptr: address pointer to APC registers of a cpu
+ * @cpu: the cpu being brought out of reset
+ *
+ * seconday_cpu_hs_init() is called when a secondary cpu
+ * is being brought online for the first time. It is not
+ * called for boot cpu. It initializes power related
+ * registers and makes the core run from BHS.
+ * It also ends up turning on MDD which is required when the
+ * core switches to LDO mode
+ */
+void secondary_cpu_hs_init(void *base_ptr, int cpu)
 {
 	uint32_t reg_val;
 	void *l2_saw_base;
+	void *gcc_base_ptr;
+	void *mdd_base;
+	struct krait_power_vreg *kvreg;
 
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
 	reg_val =  BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1438,14 +1524,23 @@
 		| BHS_EN_MASK;
 	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 
-	/* complete the above write before the delay */
-	mb();
-	/* wait for the bhs to settle */
-	udelay(BHS_SETTLING_DELAY_US);
+	if (version == 0) {
+		gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
+		version = readl_relaxed(gcc_base_ptr + VERSION);
+		iounmap(gcc_base_ptr);
+	}
 
-	/* Turn on BHS segments */
-	reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
-	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+	/* Turn on the BHS segments only for version < 2 */
+	if (version <= KPSS_VERSION_2P0) {
+		/* complete the above write before the delay */
+		mb();
+		/* wait for the bhs to settle */
+		udelay(BHS_SETTLING_DELAY_US);
+
+		/* Turn on BHS segments */
+		reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+		writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+	}
 
 	/* complete the above write before the delay */
 	mb();
@@ -1456,23 +1551,48 @@
 	reg_val |= LDO_BYP_MASK;
 	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 
-	if (the_gang && the_gang->manage_phases)
-		return;
+	kvreg = per_cpu(krait_vregs, cpu);
+	if (kvreg != NULL) {
+		kvreg_hw_init(kvreg);
+	} else {
+		/*
+		 * This nonboot cpu has not been probed yet. This cpu was
+		 * brought out of reset as a part of maxcpus >= 2. Initialize
+		 * its MDD and APC_PWR_GATE_MODE register here
+		 */
+		mdd_base = ioremap_nocache(MSM_MDD_BASE_PHYS + cpu * 0x10000,
+				SZ_4K);
+		/* setup the bandgap that configures the reference to the LDO */
+		writel_relaxed(0x00000190, mdd_base + MDD_CONFIG_CTL);
+		/* Enable MDD */
+		writel_relaxed(0x00000002, mdd_base + MDD_MODE);
+		mb();
+		iounmap(mdd_base);
 
-	/*
-	 * If the driver has not yet started to manage phases then enable
-	 * max phases.
-	 */
-	l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
-	if (!l2_saw_base) {
-		__WARN();
-		return;
+		if (version > KPSS_VERSION_2P0) {
+			writel_relaxed(0x30430600, base_ptr + APC_PWR_GATE_DLY);
+			writel_relaxed(0x00000021,
+						base_ptr + APC_PWR_GATE_MODE);
+		}
+		mb();
 	}
-	writel_relaxed(0x10003, l2_saw_base + 0x1c);
-	mb();
-	udelay(PHASE_SETTLING_TIME_US);
 
-	iounmap(l2_saw_base);
+	if (!the_gang || !the_gang->manage_phases) {
+		/*
+		 * If the driver has not yet started to manage phases then
+		 * enable max phases.
+		 */
+		l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+		if (l2_saw_base) {
+			writel_relaxed(0x10003, l2_saw_base + 0x1c);
+			mb();
+			udelay(PHASE_SETTLING_TIME_US);
+
+			iounmap(l2_saw_base);
+		} else {
+			__WARN();
+		}
+	}
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
index 78d62ac..e03ac64 100644
--- a/arch/arm/mach-msm/msm_dcvs_scm.c
+++ b/arch/arm/mach-msm/msm_dcvs_scm.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
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/memory_alloc.h>
+#include <asm/cacheflush.h>
 #include <mach/memory.h>
 #include <mach/scm.h>
 #include <mach/msm_dcvs_scm.h>
@@ -83,6 +84,12 @@
 }
 EXPORT_SYMBOL(msm_dcvs_scm_init);
 
+static void __msm_dcvs_flush_cache(void *v, size_t size)
+{
+	__cpuc_flush_dcache_area(v, size);
+	outer_flush_range(virt_to_phys(v), virt_to_phys(v) + size);
+}
+
 int msm_dcvs_scm_register_core(uint32_t core_id,
 		struct msm_dcvs_core_param *param)
 {
@@ -99,6 +106,8 @@
 	reg_data.core_id = core_id;
 	reg_data.core_param_phy = virt_to_phys(p);
 
+	__msm_dcvs_flush_cache(p, sizeof(struct msm_dcvs_core_param));
+
 	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
 			&reg_data, sizeof(reg_data), NULL, 0);
 
@@ -125,6 +134,8 @@
 	algo.core_id = core_id;
 	algo.algo_phy = virt_to_phys(p);
 
+	__msm_dcvs_flush_cache(p, sizeof(struct msm_algo_param));
+
 	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
 			&algo, sizeof(algo), NULL, 0);
 
@@ -150,6 +161,8 @@
 	algo.core_id = 0;
 	algo.algo_phy = virt_to_phys(p);
 
+	__msm_dcvs_flush_cache(p, sizeof(struct msm_algo_param));
+
 	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
 			&algo, sizeof(algo), NULL, 0);
 
@@ -197,6 +210,12 @@
 			sizeof(struct msm_dcvs_freq_entry)*pwr_param->num_freq);
 	memcpy(coefft, coeffs, sizeof(struct msm_dcvs_energy_curve_coeffs));
 
+	__msm_dcvs_flush_cache(pwrt, sizeof(struct msm_dcvs_power_params));
+	__msm_dcvs_flush_cache(freqt,
+		sizeof(struct msm_dcvs_freq_entry) * pwr_param->num_freq);
+	__msm_dcvs_flush_cache(coefft,
+				sizeof(struct msm_dcvs_energy_curve_coeffs));
+
 	pwr.core_id = core_id;
 	pwr.pwr_param_phy = virt_to_phys(pwrt);
 	pwr.freq_phy = virt_to_phys(freqt);
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 9b3e500..8d96bd8 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -25,6 +25,8 @@
 #include <linux/socket.h>
 #include <linux/gfp.h>
 #include <linux/qmi_encdec.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 #include <mach/msm_qmi_interface.h>
 #include <mach/msm_ipc_router.h>
@@ -33,6 +35,8 @@
 
 static LIST_HEAD(svc_event_nb_list);
 static DEFINE_MUTEX(svc_event_nb_list_lock);
+static DEFINE_MUTEX(msm_qmi_init_lock);
+static struct workqueue_struct *msm_qmi_pending_workqueue;
 
 struct elem_info qmi_response_type_v01_ei[] = {
 	{
@@ -87,12 +91,98 @@
 		spin_unlock_irqrestore(&handle->notify_lock, flags);
 		break;
 
+	case MSM_IPC_ROUTER_RESUME_TX:
+		queue_delayed_work(msm_qmi_pending_workqueue,
+				   &handle->resume_tx_work,
+				   msecs_to_jiffies(0));
+		break;
 	default:
 		break;
 	}
 	mutex_unlock(&handle->handle_lock);
 }
 
+/**
+ * init_msm_qmi() - Init function for kernel space QMI
+ *
+ * This function is implemented to initialize the QMI resources that are common
+ * across kernel space QMI users. As it is not necessary for this init function
+ * to be module_init function it is called when the first handle of kernel space
+ * QMI gets created.
+ */
+static void init_msm_qmi(void)
+{
+	static bool msm_qmi_inited;
+
+	if (likely(msm_qmi_inited))
+		return;
+
+	mutex_lock(&msm_qmi_init_lock);
+	if (likely(msm_qmi_inited && msm_qmi_pending_workqueue)) {
+		mutex_unlock(&msm_qmi_init_lock);
+		return;
+	}
+	msm_qmi_inited = 1;
+	msm_qmi_pending_workqueue =
+			create_singlethread_workqueue("msm_qmi_rtx_q");
+	mutex_unlock(&msm_qmi_init_lock);
+}
+
+/**
+ * handle_resume_tx() - Handle the Resume_Tx event
+ * @work : Pointer to the work strcuture.
+ *
+ * This function handles the resume_tx event for any QMI client that
+ * exists in the kernel space. This function parses the pending_txn_list of
+ * the handle and attempts a send for each transaction in that list.
+ */
+static void handle_resume_tx(struct work_struct *work)
+{
+	struct delayed_work *rtx_work = to_delayed_work(work);
+	struct qmi_handle *handle =
+		container_of(rtx_work, struct qmi_handle, resume_tx_work);
+	struct qmi_txn *pend_txn, *temp_txn;
+	int ret;
+	uint16_t msg_id;
+
+	mutex_lock(&handle->handle_lock);
+	list_for_each_entry_safe(pend_txn, temp_txn,
+				&handle->pending_txn_list, list) {
+		ret = msm_ipc_router_send_msg(
+				(struct msm_ipc_port *)handle->src_port,
+				(struct msm_ipc_addr *)handle->dest_info,
+				pend_txn->enc_data, pend_txn->enc_data_len);
+
+		if (ret == -EAGAIN) {
+			mutex_unlock(&handle->handle_lock);
+			return;
+		}
+		msg_id = ((struct qmi_header *)pend_txn->enc_data)->msg_id;
+		kfree(pend_txn->enc_data);
+		if (ret < 0) {
+			if (pend_txn->type == QMI_ASYNC_TXN) {
+				pend_txn->resp_cb(pend_txn->handle,
+						msg_id, pend_txn->resp,
+						pend_txn->resp_cb_data,
+						ret);
+				list_del(&pend_txn->list);
+				kfree(pend_txn);
+			} else if (pend_txn->type == QMI_SYNC_TXN) {
+				pend_txn->send_stat = ret;
+				wake_up(&pend_txn->wait_q);
+			}
+			pr_err("%s: Sending transaction %d from port %d failed",
+				__func__, pend_txn->txn_id,
+				((struct msm_ipc_port *)handle->src_port)->
+							this_port.port_id);
+		} else {
+			list_del(&pend_txn->list);
+			list_add_tail(&pend_txn->list, &handle->txn_list);
+		}
+	}
+	mutex_unlock(&handle->handle_lock);
+}
+
 struct qmi_handle *qmi_handle_create(
 	void (*notify)(struct qmi_handle *handle,
 		       enum qmi_event_type event, void *notify_priv),
@@ -118,20 +208,39 @@
 	temp_handle->src_port = port_ptr;
 	temp_handle->next_txn_id = 1;
 	INIT_LIST_HEAD(&temp_handle->txn_list);
+	INIT_LIST_HEAD(&temp_handle->pending_txn_list);
 	mutex_init(&temp_handle->handle_lock);
 	spin_lock_init(&temp_handle->notify_lock);
 	temp_handle->notify = notify;
 	temp_handle->notify_priv = notify_priv;
 	temp_handle->handle_reset = 0;
 	init_waitqueue_head(&temp_handle->reset_waitq);
+	INIT_DELAYED_WORK(&temp_handle->resume_tx_work, handle_resume_tx);
+	init_msm_qmi();
 	return temp_handle;
 }
 EXPORT_SYMBOL(qmi_handle_create);
 
 static void clean_txn_info(struct qmi_handle *handle)
 {
-	struct qmi_txn *txn_handle, *temp_txn_handle;
+	struct qmi_txn *txn_handle, *temp_txn_handle, *pend_txn;
 
+	list_for_each_entry_safe(pend_txn, temp_txn_handle,
+				&handle->pending_txn_list, list) {
+		if (pend_txn->type == QMI_ASYNC_TXN) {
+			list_del(&pend_txn->list);
+			pend_txn->resp_cb(pend_txn->handle,
+					((struct qmi_header *)
+					pend_txn->enc_data)->msg_id,
+					pend_txn->resp, pend_txn->resp_cb_data,
+					-ENETRESET);
+			kfree(pend_txn->enc_data);
+			kfree(pend_txn);
+		} else if (pend_txn->type == QMI_SYNC_TXN) {
+			kfree(pend_txn->enc_data);
+			wake_up(&pend_txn->wait_q);
+		}
+	}
 	list_for_each_entry_safe(txn_handle, temp_txn_handle,
 				 &handle->txn_list, list) {
 		if (txn_handle->type == QMI_ASYNC_TXN) {
@@ -154,7 +263,7 @@
 	handle->handle_reset = 1;
 	clean_txn_info(handle);
 	mutex_unlock(&handle->handle_lock);
-
+	flush_delayed_work(&handle->resume_tx_work);
 	rc = wait_event_interruptible(handle->reset_waitq,
 				      list_empty(&handle->txn_list));
 
@@ -194,7 +303,7 @@
 	struct msg_desc *resp_desc, void *resp, unsigned int resp_len,
 	void (*resp_cb)(struct qmi_handle *handle,
 			unsigned int msg_id, void *msg,
-			void *resp_cb_data),
+			void *resp_cb_data, int stat),
 	void *resp_cb_data)
 {
 	struct qmi_txn *txn_handle;
@@ -230,6 +339,8 @@
 	txn_handle->resp_received = 0;
 	txn_handle->resp_cb = resp_cb;
 	txn_handle->resp_cb_data = resp_cb_data;
+	txn_handle->enc_data = NULL;
+	txn_handle->enc_data_len = 0;
 
 	/* Encode the request msg */
 	encoded_req_len = req_desc->max_msg_len + QMI_HEADER_SIZE;
@@ -256,12 +367,35 @@
 			  txn_handle->txn_id, req_desc->msg_id,
 			  encoded_req_len);
 	encoded_req_len += QMI_HEADER_SIZE;
-	list_add_tail(&txn_handle->list, &handle->txn_list);
 
+	/*
+	 * Check if this port has transactions queued to its pending list
+	 * and if there are any pending transactions then add the current
+	 * transaction to the pending list rather than sending it. This avoids
+	 * out-of-order message transfers.
+	 */
+	if (!list_empty(&handle->pending_txn_list)) {
+		rc = -EAGAIN;
+		goto append_pend_txn;
+	}
+
+	list_add_tail(&txn_handle->list, &handle->txn_list);
 	/* Send the request */
 	rc = msm_ipc_router_send_msg((struct msm_ipc_port *)(handle->src_port),
 		(struct msm_ipc_addr *)handle->dest_info,
 		encoded_req, encoded_req_len);
+append_pend_txn:
+	if (rc == -EAGAIN) {
+		txn_handle->enc_data = encoded_req;
+		txn_handle->enc_data_len = encoded_req_len;
+		if (list_empty(&handle->pending_txn_list))
+			list_del(&txn_handle->list);
+		list_add_tail(&txn_handle->list, &handle->pending_txn_list);
+		if (ret_txn_handle)
+			*ret_txn_handle = txn_handle;
+		mutex_unlock(&handle->handle_lock);
+		return 0;
+	}
 	if (rc < 0) {
 		pr_err("%s: send_msg failed %d\n", __func__, rc);
 		goto encode_and_send_req_err3;
@@ -306,13 +440,15 @@
 	/* Wait for the response */
 	if (!timeout_ms) {
 		rc = wait_event_interruptible(txn_handle->wait_q,
-					(txn_handle->resp_received ||
-					 handle->handle_reset));
+				(txn_handle->resp_received ||
+				 handle->handle_reset ||
+				(txn_handle->send_stat < 0)));
 	} else {
 		rc = wait_event_interruptible_timeout(txn_handle->wait_q,
-					(txn_handle->resp_received ||
-					 handle->handle_reset),
-					msecs_to_jiffies(timeout_ms));
+				(txn_handle->resp_received ||
+				handle->handle_reset ||
+				(txn_handle->send_stat < 0)),
+				msecs_to_jiffies(timeout_ms));
 		if (rc == 0)
 			rc = -ETIMEDOUT;
 	}
@@ -324,6 +460,8 @@
 			rc = -ENETRESET;
 		if (rc >= 0)
 			rc = -EFAULT;
+		if (txn_handle->send_stat < 0)
+			rc = txn_handle->send_stat;
 		goto send_req_wait_err;
 	}
 	rc = 0;
@@ -344,7 +482,7 @@
 			void *resp, unsigned int resp_len,
 			void (*resp_cb)(struct qmi_handle *handle,
 					unsigned int msg_id, void *msg,
-					void *resp_cb_data),
+					void *resp_cb_data, int stat),
 			void *resp_cb_data)
 {
 	return qmi_encode_and_send_req(NULL, handle, QMI_ASYNC_TXN,
@@ -407,7 +545,7 @@
 		if (txn_handle->resp_cb)
 			txn_handle->resp_cb(txn_handle->handle, msg_id,
 					    txn_handle->resp,
-					    txn_handle->resp_cb_data);
+					    txn_handle->resp_cb_data, 0);
 		list_del(&txn_handle->list);
 		kfree(txn_handle);
 		rc = 0;
diff --git a/arch/arm/mach-msm/msm_qmi_interface_priv.h b/arch/arm/mach-msm/msm_qmi_interface_priv.h
index 58f1ce3..8eba0db 100644
--- a/arch/arm/mach-msm/msm_qmi_interface_priv.h
+++ b/arch/arm/mach-msm/msm_qmi_interface_priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -34,12 +34,15 @@
 	uint16_t txn_id;
 	enum txn_type type;
 	struct qmi_handle *handle;
+	void *enc_data;
+	unsigned int enc_data_len;
 	struct msg_desc *resp_desc;
 	void *resp;
 	unsigned int resp_len;
 	int resp_received;
+	int send_stat;
 	void (*resp_cb)(struct qmi_handle *handle, unsigned int msg_id,
-			void *msg, void *resp_cb_data);
+			void *msg, void *resp_cb_data, int stat);
 	void *resp_cb_data;
 	wait_queue_head_t wait_q;
 };
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index f4ca4e3..796fba1 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -147,10 +147,11 @@
 						unsigned int cpu)
 {
 	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+
 	if (!base_ptr)
 		return -ENODEV;
 
-	secondary_cpu_hs_init(base_ptr);
+	secondary_cpu_hs_init(base_ptr, cpu);
 
 	writel_relaxed(0x021, base_ptr+0x04);
 	mb();
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 6799cbf..146dc0b 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -967,7 +967,7 @@
 		if (acc_sts & msm_pm_slp_sts[cpu].mask)
 			return 0;
 		udelay(100);
-		WARN(++timeout == 10, "CPU%u didn't collape within 1ms\n",
+		WARN(++timeout == 20, "CPU%u didn't collape within 2ms\n",
 					cpu);
 	}
 
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index d37a325..1ea213a 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -456,7 +456,7 @@
 		__func__, config->buf_num, config->stream_format,
 		config->port_cnt, config->params_data_size);
 
-	pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d\n",
+	pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d,\n",
 		__func__,
 		config->port_id[0],
 		config->port_id[1],
@@ -464,6 +464,11 @@
 		config->port_id[3],
 		config->port_id[4]);
 
+	pr_debug("id[5]=%d, id[6]=%d, id[7]=%d\n",
+		config->port_id[5],
+		config->port_id[6],
+		config->port_id[7]);
+
 	/* q6usm allocation & configuration */
 	usf_xx->buffer_size = config->buf_size;
 	usf_xx->buffer_count = config->buf_num;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c
index 5d30eb1..80b1aaa 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.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
@@ -652,7 +652,7 @@
 		sizeof(struct usm_stream_cmd_encdec_cfg_blk);
 	uint32_t round_params_size = 0;
 	uint8_t  is_allocated = 0;
-
+	size_t min_common_size;
 
 	if ((usc == NULL) || (us_cfg == NULL)) {
 		pr_err("%s: wrong input", __func__);
@@ -692,12 +692,13 @@
 				round_params_size;
 	enc_cfg->enc_blk.frames_per_buf = 1;
 	enc_cfg->enc_blk.format_id = int_format;
-	enc_cfg->enc_blk.cfg_size = sizeof(struct usm_cfg_common)+
+	min_common_size = min(sizeof(struct usm_cfg_common),
+			      sizeof(struct usm_cfg_common_a));
+	enc_cfg->enc_blk.cfg_size = min_common_size +
 				    USM_MAX_CFG_DATA_SIZE +
 				    round_params_size;
 	memcpy(&(enc_cfg->enc_blk.cfg_common), &(us_cfg->cfg_common),
-	       sizeof(struct usm_cfg_common));
-
+	       min_common_size);
 	/* Transparent data copy */
 	memcpy(enc_cfg->enc_blk.transp_data, us_cfg->params,
 	       us_cfg->params_size);
@@ -716,11 +717,15 @@
 		enc_cfg->enc_blk.transp_data[6],
 		enc_cfg->enc_blk.transp_data[7]
 	       );
-	pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+	pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:[0x%x,0x%x,0x%x,0x%x];\n",
 		__func__, enc_cfg->enc_blk.cfg_common.sample_rate,
 		enc_cfg->enc_blk.cfg_common.ch_cfg,
 		enc_cfg->enc_blk.cfg_common.bits_per_sample,
-		enc_cfg->enc_blk.cfg_common.data_map,
+		enc_cfg->enc_blk.cfg_common.data_map[0],
+		enc_cfg->enc_blk.cfg_common.data_map[1],
+		enc_cfg->enc_blk.cfg_common.data_map[2],
+		enc_cfg->enc_blk.cfg_common.data_map[3]);
+	pr_debug("dev_id=0x%x\n",
 		enc_cfg->enc_blk.cfg_common.dev_id);
 
 	rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
@@ -757,7 +762,7 @@
 	uint32_t total_cfg_size = sizeof(struct usm_stream_media_format_update);
 	uint32_t round_params_size = 0;
 	uint8_t  is_allocated = 0;
-
+	size_t min_common_size;
 
 	if ((usc == NULL) || (us_cfg == NULL)) {
 		pr_err("%s: wrong input", __func__);
@@ -794,11 +799,13 @@
 
 	dec_cfg->hdr.opcode = USM_DATA_CMD_MEDIA_FORMAT_UPDATE;
 	dec_cfg->format_id = int_format;
-	dec_cfg->cfg_size = sizeof(struct usm_cfg_common) +
+	min_common_size = min(sizeof(struct usm_cfg_common),
+			      sizeof(struct usm_cfg_common_a));
+	dec_cfg->cfg_size = min_common_size +
 			    USM_MAX_CFG_DATA_SIZE +
 			    round_params_size;
 	memcpy(&(dec_cfg->cfg_common), &(us_cfg->cfg_common),
-	       sizeof(struct usm_cfg_common));
+	       min_common_size);
 	/* Transparent data copy */
 	memcpy(dec_cfg->transp_data, us_cfg->params, us_cfg->params_size);
 	pr_debug("%s: cfg_size[%d], params_size[%d]; parambytes[%d,%d,%d,%d]\n",
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index a3af3e78..fe7c8c2 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -620,13 +620,13 @@
 	uint32_t int_format = INVALID_FORMAT;
 	switch (ext_format) {
 	case FORMAT_USPS_EPOS:
-		int_format = US_POINT_EPOS_FORMAT;
+		int_format = US_POINT_EPOS_FORMAT_V2;
 		break;
 	case FORMAT_USRAW:
-		int_format = US_RAW_FORMAT;
+		int_format = US_RAW_FORMAT_V2;
 		break;
 	case FORMAT_USPROX:
-		int_format = US_PROX_FORMAT;
+		int_format = US_PROX_FORMAT_V2;
 		break;
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
@@ -757,11 +757,19 @@
 		enc_cfg->enc_blk.transp_data[6],
 		enc_cfg->enc_blk.transp_data[7]
 	       );
-	pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+	pr_debug("%s: srate:%d, ch=%d, bps= %d;\n",
 		__func__, enc_cfg->enc_blk.cfg_common.sample_rate,
 		enc_cfg->enc_blk.cfg_common.ch_cfg,
-		enc_cfg->enc_blk.cfg_common.bits_per_sample,
-		enc_cfg->enc_blk.cfg_common.data_map,
+		enc_cfg->enc_blk.cfg_common.bits_per_sample);
+	pr_debug("dmap:[0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x]; dev_id=0x%x\n",
+		enc_cfg->enc_blk.cfg_common.data_map[0],
+		enc_cfg->enc_blk.cfg_common.data_map[1],
+		enc_cfg->enc_blk.cfg_common.data_map[2],
+		enc_cfg->enc_blk.cfg_common.data_map[3],
+		enc_cfg->enc_blk.cfg_common.data_map[4],
+		enc_cfg->enc_blk.cfg_common.data_map[5],
+		enc_cfg->enc_blk.cfg_common.data_map[6],
+		enc_cfg->enc_blk.cfg_common.data_map[7],
 		enc_cfg->enc_blk.cfg_common.dev_id);
 
 	rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index fda64e5..2fd8bef 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -22,6 +22,7 @@
 #include <linux/hrtimer.h>
 #include <linux/tick.h>
 #include <linux/ktime.h>
+#include <linux/kthread.h>
 #include <linux/sched.h>
 #include <linux/input.h>
 #include <linux/workqueue.h>
@@ -103,6 +104,11 @@
 	 * when user is changing the governor or limits.
 	 */
 	struct mutex timer_mutex;
+
+	struct task_struct *sync_thread;
+	wait_queue_head_t sync_wq;
+	atomic_t src_sync_cpu;
+	atomic_t sync_enabled;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
 
@@ -125,14 +131,6 @@
 
 static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work);
 
-struct dbs_sync_work_struct {
-	struct work_struct work;
-	unsigned int src_cpu;
-	unsigned int targ_cpu;
-};
-
-static DEFINE_PER_CPU(struct dbs_sync_work_struct, dbs_sync_work);
-
 static struct dbs_tuners {
 	unsigned int sampling_rate;
 	unsigned int up_threshold;
@@ -1039,12 +1037,11 @@
 static int dbs_migration_notify(struct notifier_block *nb,
 				unsigned long target_cpu, void *arg)
 {
-	struct dbs_sync_work_struct *sync_work =
-		&per_cpu(dbs_sync_work, target_cpu);
-	sync_work->src_cpu = (unsigned int)arg;
+	struct cpu_dbs_info_s *target_dbs_info =
+		&per_cpu(od_cpu_dbs_info, target_cpu);
 
-	queue_work_on(target_cpu, dbs_wq,
-		&per_cpu(dbs_sync_work, target_cpu).work);
+	atomic_set(&target_dbs_info->src_sync_cpu, (int)arg);
+	wake_up(&target_dbs_info->sync_wq);
 
 	return NOTIFY_OK;
 }
@@ -1053,73 +1050,97 @@
 	.notifier_call = dbs_migration_notify,
 };
 
-void dbs_synchronize(struct work_struct *work)
+static int sync_pending(struct cpu_dbs_info_s *this_dbs_info)
 {
-	struct cpufreq_policy *policy;
-	struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info;
-	struct dbs_sync_work_struct *dbs_work;
-	unsigned int cpu, src_cpu;
+	return atomic_read(&this_dbs_info->src_sync_cpu) >= 0;
+}
+
+static int dbs_sync_thread(void *data)
+{
+	int src_cpu, cpu = (int)data;
 	unsigned int src_freq, src_max_load;
+	struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info;
+	struct cpufreq_policy *policy;
 	int delay;
 
-	dbs_work = container_of(work, struct dbs_sync_work_struct, work);
-	cpu = dbs_work->targ_cpu;
-	src_cpu = dbs_work->src_cpu;
-
-	get_online_cpus();
-
-	/* Getting source cpu info  */
-	src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
-	if (src_dbs_info != NULL && src_dbs_info->cur_policy != NULL) {
-		src_freq = src_dbs_info->cur_policy->cur;
-		src_max_load = src_dbs_info->max_load;
-	} else {
-		src_freq = dbs_tuners_ins.sync_freq;
-		src_max_load = 0;
-	}
-
-	if (lock_policy_rwsem_write(cpu) < 0)
-		goto bail_acq_sema_failed;
-
 	this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
-	policy = this_dbs_info->cur_policy;
-	if (!policy) {
-		/* CPU not using ondemand governor */
-		goto bail_incorrect_governor;
-	}
 
-	delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+	while (1) {
+		wait_event(this_dbs_info->sync_wq,
+			   sync_pending(this_dbs_info) ||
+			   kthread_should_stop());
 
-	if (policy->cur < src_freq) {
+		if (kthread_should_stop())
+			break;
 
-		/* Cancelling the next ondemand sample */
-		cancel_delayed_work_sync(&this_dbs_info->work);
+		get_online_cpus();
 
-		/*
-		 * Arch specific cpufreq driver may fail.
-		 * Don't update governor frequency upon failure.
+		/* TODO: cur_policy is currently set for all CPUs when
+		 * a policy is started but cleared only on the current
+		 * CPU when the policy is stopped. If/when this is
+		 * resolved, sync_enabled can be removed and
+		 * cur_policy can be used instead.
 		 */
-		if (__cpufreq_driver_target(policy, src_freq,
-					CPUFREQ_RELATION_L) >= 0) {
-			policy->cur = src_freq;
-			if (src_max_load > this_dbs_info->max_load) {
-				this_dbs_info->max_load = src_max_load;
-				this_dbs_info->prev_load = src_max_load;
-			}
+		if (!atomic_read(&this_dbs_info->sync_enabled)) {
+			atomic_set(&this_dbs_info->src_sync_cpu, -1);
+			put_online_cpus();
+			continue;
 		}
 
-		/* Rescheduling the next ondemand sample */
-		mutex_lock(&this_dbs_info->timer_mutex);
-		schedule_delayed_work_on(cpu, &this_dbs_info->work,
-					delay);
-		mutex_unlock(&this_dbs_info->timer_mutex);
-	}
-bail_incorrect_governor:
-	unlock_policy_rwsem_write(cpu);
+		src_cpu = atomic_read(&this_dbs_info->src_sync_cpu);
+		src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
+		if (src_dbs_info != NULL &&
+		    src_dbs_info->cur_policy != NULL) {
+			src_freq = src_dbs_info->cur_policy->cur;
+			src_max_load = src_dbs_info->max_load;
+		} else {
+			src_freq = dbs_tuners_ins.sync_freq;
+			src_max_load = 0;
+		}
 
+		if (lock_policy_rwsem_write(cpu) < 0)
+			goto bail_acq_sema_failed;
+
+		policy = this_dbs_info->cur_policy;
+		if (!policy) {
+			/* CPU not using ondemand governor */
+			goto bail_incorrect_governor;
+		}
+		delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+
+		if (policy->cur < src_freq) {
+			/* cancel the next ondemand sample */
+			cancel_delayed_work_sync(&this_dbs_info->work);
+
+			/*
+			 * Arch specific cpufreq driver may fail.
+			 * Don't update governor frequency upon failure.
+			 */
+			if (__cpufreq_driver_target(policy, src_freq,
+						    CPUFREQ_RELATION_L) >= 0) {
+				policy->cur = src_freq;
+				if (src_max_load > this_dbs_info->max_load) {
+					this_dbs_info->max_load = src_max_load;
+					this_dbs_info->prev_load = src_max_load;
+				}
+			}
+
+			/* reschedule the next ondemand sample */
+			mutex_lock(&this_dbs_info->timer_mutex);
+			queue_delayed_work_on(cpu, dbs_wq,
+					      &this_dbs_info->work, delay);
+			mutex_unlock(&this_dbs_info->timer_mutex);
+		}
+
+bail_incorrect_governor:
+		unlock_policy_rwsem_write(cpu);
 bail_acq_sema_failed:
-	put_online_cpus();
-	return;
+		put_online_cpus();
+		atomic_set(&this_dbs_info->src_sync_cpu, -1);
+	}
+
+	return 0;
 }
 
 static void dbs_input_event(struct input_handle *handle, unsigned int type,
@@ -1215,6 +1236,9 @@
 			if (dbs_tuners_ins.ignore_nice)
 				j_dbs_info->prev_cpu_nice =
 						kcpustat_cpu(j).cpustat[CPUTIME_NICE];
+			set_cpus_allowed(j_dbs_info->sync_thread,
+					 *cpumask_of(j));
+			atomic_set(&j_dbs_info->sync_enabled, 1);
 		}
 		this_dbs_info->cpu = cpu;
 		this_dbs_info->rate_mult = 1;
@@ -1271,6 +1295,13 @@
 
 		mutex_lock(&dbs_mutex);
 		dbs_enable--;
+
+		for_each_cpu(j, policy->cpus) {
+			struct cpu_dbs_info_s *j_dbs_info;
+			j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+			atomic_set(&j_dbs_info->sync_enabled, 0);
+		}
+
 		/* If device is being removed, policy is no longer
 		 * valid. */
 		this_dbs_info->cur_policy = NULL;
@@ -1342,17 +1373,17 @@
 			&per_cpu(od_cpu_dbs_info, i);
 		struct dbs_work_struct *dbs_work =
 			&per_cpu(dbs_refresh_work, i);
-		struct dbs_sync_work_struct *dbs_sync =
-			&per_cpu(dbs_sync_work, i);
 
 		mutex_init(&this_dbs_info->timer_mutex);
 		INIT_WORK(&dbs_work->work, dbs_refresh_callback);
 		dbs_work->cpu = i;
 
-		INIT_WORK(&dbs_sync->work, dbs_synchronize);
-		dbs_sync->src_cpu = 0;
-		dbs_sync->targ_cpu = i;
+		atomic_set(&this_dbs_info->src_sync_cpu, -1);
+		init_waitqueue_head(&this_dbs_info->sync_wq);
 
+		this_dbs_info->sync_thread = kthread_run(dbs_sync_thread,
+							 (void *)i,
+							 "dbs_sync/%d", i);
 	}
 
 	return cpufreq_register_governor(&cpufreq_gov_ondemand);
@@ -1367,6 +1398,7 @@
 		struct cpu_dbs_info_s *this_dbs_info =
 			&per_cpu(od_cpu_dbs_info, i);
 		mutex_destroy(&this_dbs_info->timer_mutex);
+		kthread_stop(this_dbs_info->sync_thread);
 	}
 	destroy_workqueue(dbs_wq);
 }
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index f8185df..dadf87c 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -69,6 +69,29 @@
 }
 
 /**
+ * devfreq_set_freq_limits() - Set min and max frequency from freq_table
+ * @devfreq:	the devfreq instance
+ */
+static void devfreq_set_freq_limits(struct devfreq *devfreq)
+{
+	int idx;
+	unsigned long min = ~0, max = 0;
+
+	if (!devfreq->profile->freq_table)
+		return;
+
+	for (idx = 0; idx < devfreq->profile->max_state; idx++) {
+		if (min > devfreq->profile->freq_table[idx])
+			min = devfreq->profile->freq_table[idx];
+		if (max < devfreq->profile->freq_table[idx])
+			max = devfreq->profile->freq_table[idx];
+	}
+
+	devfreq->min_freq = min;
+	devfreq->max_freq = max;
+}
+
+/**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:	the devfreq instance
  * @freq:	the target frequency
@@ -506,6 +529,7 @@
 						devfreq->profile->max_state,
 						GFP_KERNEL);
 	devfreq->last_stat_updated = jiffies;
+	devfreq_set_freq_limits(devfreq);
 
 	dev_set_name(&devfreq->dev, dev_name(dev));
 	err = device_register(&devfreq->dev);
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index c72f942..bc7da1e 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -32,7 +32,7 @@
 {
 	int ret = 0;
 
-	if (event == DEVFREQ_GOV_START) {
+	if (event == DEVFREQ_GOV_START || event == DEVFREQ_GOV_RESUME) {
 		mutex_lock(&devfreq->lock);
 		ret = update_devfreq(devfreq);
 		mutex_unlock(&devfreq->lock);
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 0c6bed5..6d43685 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -29,7 +29,7 @@
 {
 	int ret = 0;
 
-	if (event == DEVFREQ_GOV_START) {
+	if (event == DEVFREQ_GOV_START || event == DEVFREQ_GOV_RESUME) {
 		mutex_lock(&devfreq->lock);
 		ret = update_devfreq(devfreq);
 		mutex_unlock(&devfreq->lock);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4a45313..4e3af1c 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -365,6 +365,9 @@
 	if (!ION_IS_CACHED(flags))
 		return 0;
 
+	if (flags & ION_FLAG_SECURE)
+		return 0;
+
 	table = ion_sg_table(client, handle);
 
 	if (IS_ERR_OR_NULL(table))
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ecd3c0d..44c9c29 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -214,6 +214,11 @@
 		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
 		0x201, 0x200 },
+	/* 8226v2 */
+	{ ADRENO_REV_A305B, 3, 0, 5, 0x12,
+		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
+		512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
+		0x201, 0x200 },
 	{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index daeefd0..1fc7467 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -722,7 +722,7 @@
 		ret = -EINVAL;
 	else if (TYPE_IS_PMEM(priv->type) || TYPE_IS_MEM(priv->type)) {
 		if (priv->ion_handle) {
-			args->ion_fd = ion_share_dma_buf(
+			args->ion_fd = ion_share_dma_buf_fd(
 				kgsl_drm_ion_client, priv->ion_handle);
 			if (args->ion_fd < 0) {
 				DRM_ERROR(
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 0bacc5e..9113605 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -287,7 +287,7 @@
 				addr < (p->gpuaddr + p->size)) {
 
 				kgsl_get_memory_usage(name, sizeof(name) - 1,
-					p->flags),
+					p->flags);
 				KGSL_LOG_DUMP(iommu_dev->kgsldev,
 					"---- premature free ----\n");
 				KGSL_LOG_DUMP(iommu_dev->kgsldev,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index de7b0e9..9570327 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -389,8 +389,13 @@
 
 	rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
 						&iadc->iadc_comp.sys_gain);
-	if (rc < 0)
+	if (rc < 0) {
 		pr_err("full scale read failed with %d\n", rc);
+		return rc;
+	}
+
+	if (iadc->external_rsense)
+		iadc->iadc_comp.ext_rsense = true;
 
 	pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
 			iadc->iadc_comp.id,
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index a400b58..175328e 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -39,6 +39,7 @@
 #define MSM_IOMMU_PGSIZES	(SZ_4K | SZ_64K | SZ_1M | SZ_16M)
 
 static DEFINE_MUTEX(msm_iommu_lock);
+struct dump_regs_tbl dump_regs_tbl[MAX_DUMP_REGS];
 
 static int __enable_regulators(struct msm_iommu_drvdata *drvdata)
 {
@@ -769,7 +770,7 @@
 	struct msm_iommu_priv *priv;
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
-	unsigned int par;
+	u64 par;
 	void __iomem *base;
 	phys_addr_t ret = 0;
 	int ctx;
@@ -802,6 +803,23 @@
 	__disable_clocks(iommu_drvdata);
 
 	if (par & CB_PAR_F) {
+		unsigned int level = (par & CB_PAR_PLVL) >> CB_PAR_PLVL_SHIFT;
+		pr_err("IOMMU translation fault!\n");
+		pr_err("name = %s\n", iommu_drvdata->name);
+		pr_err("context = %s (%d)\n", ctx_drvdata->name,
+						ctx_drvdata->num);
+		pr_err("Interesting registers:\n");
+		pr_err("PAR = %16llx [%s%s%s%s%s%s%s%sPLVL%u %s]\n", par,
+			(par & CB_PAR_F) ? "F " : "",
+			(par & CB_PAR_TF) ? "TF " : "",
+			(par & CB_PAR_AFF) ? "AFF " : "",
+			(par & CB_PAR_PF) ? "PF " : "",
+			(par & CB_PAR_EF) ? "EF " : "",
+			(par & CB_PAR_TLBMCF) ? "TLBMCF " : "",
+			(par & CB_PAR_TLBLKF) ? "TLBLKF " : "",
+			(par & CB_PAR_ATOT) ? "ATOT " : "",
+			level,
+			(par & CB_PAR_STAGE) ? "S2 " : "S1 ");
 		ret = 0;
 	} else {
 		/* We are dealing with a supersection */
@@ -857,49 +875,13 @@
 
 static void __print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
 {
-	struct msm_iommu_context_reg regs[MAX_DUMP_REGS] = {
-		[DUMP_REG_FAR0] = {
-			.val = GET_FAR(base, ctx)
-		},
-		[DUMP_REG_FAR1] = {
-			/* TODO: make GET_FAR 64-bit and take this from that */
-			.val = 0
-		},
-		[DUMP_REG_PAR0] = {
-			.val = GET_PAR(base, ctx)
-		},
-		[DUMP_REG_PAR1] = {
-			/* TODO: make GET_PAR 64-bit and take this from that */
-			.val = 0
-		},
-		[DUMP_REG_FSR] = {
-			.val = fsr
-		},
-		[DUMP_REG_FSYNR0] = {
-			.val = GET_FSYNR0(base, ctx)
-		},
-		[DUMP_REG_FSYNR1] = {
-			.val = GET_FSYNR1(base, ctx)
-		},
-		[DUMP_REG_TTBR0] = {
-			.val = GET_TTBR0(base, ctx)
-		},
-		[DUMP_REG_TTBR1] = {
-			.val = GET_TTBR1(base, ctx)
-		},
-		[DUMP_REG_SCTLR] = {
-			.val = GET_SCTLR(base, ctx)
-		},
-		[DUMP_REG_ACTLR] = {
-			.val = GET_ACTLR(base, ctx)
-		},
-		[DUMP_REG_PRRR] = {
-			.val = GET_PRRR(base, ctx)
-		},
-		[DUMP_REG_NMRR] = {
-			.val = GET_NMRR(base, ctx)
-		},
-	};
+	struct msm_iommu_context_reg regs[MAX_DUMP_REGS];
+	unsigned int i;
+
+	for (i = DUMP_REG_FIRST; i < MAX_DUMP_REGS; ++i) {
+		regs[i].val = GET_CTX_REG(dump_regs_tbl[i].key, base, ctx);
+		regs[i].valid = 1;
+	}
 	print_ctx_regs(regs);
 }
 
@@ -976,6 +958,29 @@
 	return __pa(priv->pt.fl_table);
 }
 
+#define DUMP_REG_INIT(dump_reg, cb_reg)				\
+	do {							\
+		dump_regs_tbl[dump_reg].key = cb_reg;		\
+		dump_regs_tbl[dump_reg].name = #cb_reg;		\
+	} while (0)
+
+static void msm_iommu_build_dump_regs_table(void)
+{
+	DUMP_REG_INIT(DUMP_REG_FAR0,	CB_FAR);
+	DUMP_REG_INIT(DUMP_REG_FAR1,	CB_FAR + 4);
+	DUMP_REG_INIT(DUMP_REG_PAR0,	CB_PAR);
+	DUMP_REG_INIT(DUMP_REG_PAR1,	CB_PAR + 4);
+	DUMP_REG_INIT(DUMP_REG_FSR,	CB_FSR);
+	DUMP_REG_INIT(DUMP_REG_FSYNR0,	CB_FSYNR0);
+	DUMP_REG_INIT(DUMP_REG_FSYNR1,	CB_FSYNR1);
+	DUMP_REG_INIT(DUMP_REG_TTBR0,	CB_TTBR0);
+	DUMP_REG_INIT(DUMP_REG_TTBR1,	CB_TTBR1);
+	DUMP_REG_INIT(DUMP_REG_SCTLR,	CB_SCTLR);
+	DUMP_REG_INIT(DUMP_REG_ACTLR,	CB_ACTLR);
+	DUMP_REG_INIT(DUMP_REG_PRRR,	CB_PRRR);
+	DUMP_REG_INIT(DUMP_REG_NMRR,	CB_NMRR);
+}
+
 static struct iommu_ops msm_iommu_ops = {
 	.domain_init = msm_iommu_domain_init,
 	.domain_destroy = msm_iommu_domain_destroy,
@@ -995,6 +1000,8 @@
 {
 	msm_iommu_pagetable_init();
 	bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
+	msm_iommu_build_dump_regs_table();
+
 	return 0;
 }
 
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 50f6df4..8d2cc8f 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -124,41 +124,8 @@
 	return ret;
 }
 
-static struct dump_regs_tbl {
-	/*
-	 * To keep things context-bank-agnostic, we only store the CB
-	 * register offset in `key'
-	 */
-	unsigned long key;
-	const char *name;
-	int offset;
-} dump_regs_tbl[MAX_DUMP_REGS];
-
 #define EXTRACT_DUMP_REG_KEY(addr, ctx) (addr & ((1 << CTX_SHIFT) - 1))
 
-#define DUMP_REG_INIT(dump_reg, cb_reg)				\
-	do {							\
-		dump_regs_tbl[dump_reg].key = cb_reg;		\
-		dump_regs_tbl[dump_reg].name = #cb_reg;		\
-	} while (0)
-
-static void msm_iommu_sec_build_dump_regs_table(void)
-{
-	DUMP_REG_INIT(DUMP_REG_FAR0,	CB_FAR);
-	DUMP_REG_INIT(DUMP_REG_FAR1,	CB_FAR + 4);
-	DUMP_REG_INIT(DUMP_REG_PAR0,	CB_PAR);
-	DUMP_REG_INIT(DUMP_REG_PAR1,	CB_PAR + 4);
-	DUMP_REG_INIT(DUMP_REG_FSR,	CB_FSR);
-	DUMP_REG_INIT(DUMP_REG_FSYNR0,	CB_FSYNR0);
-	DUMP_REG_INIT(DUMP_REG_FSYNR1,	CB_FSYNR1);
-	DUMP_REG_INIT(DUMP_REG_TTBR0,	CB_TTBR0);
-	DUMP_REG_INIT(DUMP_REG_TTBR1,	CB_TTBR1);
-	DUMP_REG_INIT(DUMP_REG_SCTLR,	CB_SCTLR);
-	DUMP_REG_INIT(DUMP_REG_ACTLR,	CB_ACTLR);
-	DUMP_REG_INIT(DUMP_REG_PRRR,	CB_PRRR);
-	DUMP_REG_INIT(DUMP_REG_NMRR,	CB_NMRR);
-}
-
 static int msm_iommu_reg_dump_to_regs(
 	struct msm_iommu_context_reg ctx_regs[],
 	struct msm_scm_fault_regs_dump *dump, int cb_num)
@@ -799,9 +766,6 @@
 
 	bus_set_iommu(&msm_iommu_sec_bus_type, &msm_iommu_ops);
 	ret = msm_iommu_sec_ptbl_init();
-	if (ret)
-		goto fail;
-	msm_iommu_sec_build_dump_regs_table();
 fail:
 	return ret;
 }
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bac8678..fbcc243 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -97,6 +97,7 @@
 #define FLASH_FAULT_DETECT(base)	(base + 0x51)
 
 #define FLASH_MAX_LEVEL			0x4F
+#define TORCH_MAX_LEVEL			0x0F
 #define	FLASH_NO_MASK			0x00
 
 #define FLASH_MASK_1			0x20
@@ -159,6 +160,7 @@
 #define QPNP_LED_PWM_FLAGS	(PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
 #define QPNP_LUT_RAMP_STEP_DEFAULT	255
 #define	PWM_LUT_MAX_SIZE		63
+#define	PWM_GPLED_LUT_MAX_SIZE		31
 #define RGB_LED_DISABLE			0x00
 
 #define MPP_MAX_LEVEL			LED_FULL
@@ -299,6 +301,10 @@
  *  @pwm_channel - pwm channel to be configured for led
  *  @pwm_period_us - period for pwm, in us
  *  @mode - mode the led operates in
+ *  @old_duty_pcts - storage for duty pcts that may need to be reused
+ *  @default_mode - default mode of LED as set in device tree
+ *  @use_blink - use blink sysfs entry
+ *  @blinking - device is currently blinking w/LPG mode
  */
 struct pwm_config_data {
 	struct lut_params	lut_params;
@@ -306,9 +312,11 @@
 	int			pwm_channel;
 	u32			pwm_period_us;
 	struct pwm_duty_cycles	*duty_cycles;
+	int	*old_duty_pcts;
 	u8	mode;
-	u8	enable;
+	u8	default_mode;
 	bool use_blink;
+	bool blinking;
 };
 
 /**
@@ -414,6 +422,7 @@
  * struct qpnp_led_data - internal led data structure
  * @led_classdev - led class device
  * @delayed_work - delayed work for turning off the LED
+ * @work - workqueue for led
  * @id - led index
  * @base_reg - base register given in device tree
  * @lock - to protect the transactions
@@ -427,11 +436,12 @@
 	struct led_classdev	cdev;
 	struct spmi_device	*spmi_dev;
 	struct delayed_work	dwork;
+	struct work_struct	work;
 	int			id;
 	u16			base;
 	u8			reg;
 	u8			num_leds;
-	spinlock_t		lock;
+	struct mutex		lock;
 	struct wled_config_data *wled_cfg;
 	struct flash_config_data	*flash_cfg;
 	struct kpdbl_config_data	*kpdbl_cfg;
@@ -566,6 +576,14 @@
 	int duty_us;
 
 	if (led->cdev.brightness) {
+		if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+			if (!led->mpp_cfg->pwm_cfg->blinking) {
+				led->mpp_cfg->pwm_cfg->mode =
+					led->mpp_cfg->pwm_cfg->default_mode;
+				led->mpp_cfg->pwm_mode =
+					led->mpp_cfg->pwm_cfg->default_mode;
+			}
+		}
 		if (led->mpp_cfg->pwm_mode == PWM_MODE) {
 			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
 			duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
@@ -606,8 +624,13 @@
 			return rc;
 		}
 	} else {
-		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+		if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+			led->mpp_cfg->pwm_cfg->mode =
+				led->mpp_cfg->pwm_cfg->default_mode;
+			led->mpp_cfg->pwm_mode =
+				led->mpp_cfg->pwm_cfg->default_mode;
 			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
+		}
 		rc = qpnp_led_masked_write(led,
 					LED_MPP_MODE_CTRL(led->base),
 					LED_MPP_MODE_MASK,
@@ -629,6 +652,8 @@
 		}
 	}
 
+	if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+		led->mpp_cfg->pwm_cfg->blinking = false;
 	qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
 
 	return 0;
@@ -639,8 +664,12 @@
 	int rc;
 	int val = led->cdev.brightness;
 
-	led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
-						led->max_current);
+	if (led->flash_cfg->torch_enable)
+		led->flash_cfg->current_prgm =
+			(val * TORCH_MAX_LEVEL / led->max_current);
+	else
+		led->flash_cfg->current_prgm =
+			(val * FLASH_MAX_LEVEL / led->max_current);
 
 	led->flash_cfg->current_prgm =
 		led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
@@ -691,7 +720,7 @@
 
 			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
 				FLASH_CURRENT_MASK,
-				led->max_current);
+				TORCH_MAX_LEVEL);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
@@ -861,6 +890,9 @@
 	int rc;
 
 	if (led->cdev.brightness) {
+		if (!led->kpdbl_cfg->pwm_cfg->blinking)
+			led->kpdbl_cfg->pwm_cfg->mode =
+				led->kpdbl_cfg->pwm_cfg->default_mode;
 		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
 				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
 		duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
@@ -877,6 +909,8 @@
 			return rc;
 		}
 	} else {
+		led->kpdbl_cfg->pwm_cfg->mode =
+			led->kpdbl_cfg->pwm_cfg->default_mode;
 		pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
 				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
@@ -887,6 +921,7 @@
 		}
 	}
 
+	led->kpdbl_cfg->pwm_cfg->blinking = false;
 	qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
 
 	return 0;
@@ -898,6 +933,9 @@
 	int rc;
 
 	if (led->cdev.brightness) {
+		if (!led->rgb_cfg->pwm_cfg->blinking)
+			led->rgb_cfg->pwm_cfg->mode =
+				led->rgb_cfg->pwm_cfg->default_mode;
 		if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
 			duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
 				led->cdev.brightness) / LED_FULL;
@@ -924,6 +962,8 @@
 			return rc;
 		}
 	} else {
+		led->rgb_cfg->pwm_cfg->mode =
+			led->rgb_cfg->pwm_cfg->default_mode;
 		pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led,
 			RGB_LED_EN_CTL(led->base),
@@ -935,6 +975,7 @@
 		}
 	}
 
+	led->rgb_cfg->pwm_cfg->blinking = false;
 	qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
 
 	return 0;
@@ -943,9 +984,7 @@
 static void qpnp_led_set(struct led_classdev *led_cdev,
 				enum led_brightness value)
 {
-	int rc, i;
 	struct qpnp_led_data *led;
-	struct qpnp_led_data *led_array;
 
 	led = container_of(led_cdev, struct qpnp_led_data, cdev);
 	if (value < LED_OFF || value > led->cdev.max_brightness) {
@@ -953,6 +992,16 @@
 		return;
 	}
 
+	led->cdev.brightness = value;
+	schedule_work(&led->work);
+}
+
+static void __qpnp_led_work(struct qpnp_led_data *led,
+				enum led_brightness value)
+{
+	int rc, i;
+	struct qpnp_led_data *led_array;
+
 	if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
 		if (!led->flash_cfg->flash_on && value > 0) {
 			led_array = dev_get_drvdata(&led->spmi_dev->dev);
@@ -980,8 +1029,7 @@
 		}
 	}
 
-	spin_lock(&led->lock);
-	led->cdev.brightness = value;
+	mutex_lock(&led->lock);
 
 	switch (led->id) {
 	case QPNP_ID_WLED:
@@ -1021,7 +1069,7 @@
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		break;
 	}
-	spin_unlock(&led->lock);
+	mutex_unlock(&led->lock);
 
 	if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
 		if (led->flash_cfg->flash_on && !value) {
@@ -1050,6 +1098,16 @@
 	}
 }
 
+static void qpnp_led_work(struct work_struct *work)
+{
+	struct qpnp_led_data *led = container_of(work,
+					struct qpnp_led_data, work);
+
+	__qpnp_led_work(led, led->cdev.brightness);
+
+	return;
+}
+
 static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
 {
 	switch (led->id) {
@@ -1341,28 +1399,424 @@
 	return 0;
 }
 
+static ssize_t pwm_us_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 pwm_us;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_pwm_us;
+	struct pwm_config_data *pwm_cfg;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	ret = kstrtou32(buf, 10, &pwm_us);
+	if (ret)
+		return ret;
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for pwm_us\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_pwm_us = pwm_cfg->pwm_period_us;
+
+	pwm_cfg->pwm_period_us = pwm_us;
+	pwm_free(pwm_cfg->pwm_dev);
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->pwm_period_us = previous_pwm_us;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new pwm_us value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t pause_lo_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 pause_lo;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_pause_lo;
+	struct pwm_config_data *pwm_cfg;
+
+	ret = kstrtou32(buf, 10, &pause_lo);
+	if (ret)
+		return ret;
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for pause lo\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_pause_lo = pwm_cfg->lut_params.lut_pause_lo;
+
+	pwm_free(pwm_cfg->pwm_dev);
+	pwm_cfg->lut_params.lut_pause_lo = pause_lo;
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->lut_params.lut_pause_lo = previous_pause_lo;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new pause lo value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t pause_hi_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 pause_hi;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_pause_hi;
+	struct pwm_config_data *pwm_cfg;
+
+	ret = kstrtou32(buf, 10, &pause_hi);
+	if (ret)
+		return ret;
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for pause hi\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_pause_hi = pwm_cfg->lut_params.lut_pause_hi;
+
+	pwm_free(pwm_cfg->pwm_dev);
+	pwm_cfg->lut_params.lut_pause_hi = pause_hi;
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->lut_params.lut_pause_hi = previous_pause_hi;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new pause hi value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t start_idx_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 start_idx;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_start_idx;
+	struct pwm_config_data *pwm_cfg;
+
+	ret = kstrtou32(buf, 10, &start_idx);
+	if (ret)
+		return ret;
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for start idx\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_start_idx = pwm_cfg->duty_cycles->start_idx;
+	pwm_cfg->duty_cycles->start_idx = start_idx;
+	pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
+	pwm_free(pwm_cfg->pwm_dev);
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->duty_cycles->start_idx = previous_start_idx;
+		pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new start idx value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t ramp_step_ms_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 ramp_step_ms;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_ramp_step_ms;
+	struct pwm_config_data *pwm_cfg;
+
+	ret = kstrtou32(buf, 10, &ramp_step_ms);
+	if (ret)
+		return ret;
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for ramp step\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_ramp_step_ms = pwm_cfg->lut_params.ramp_step_ms;
+
+	pwm_free(pwm_cfg->pwm_dev);
+	pwm_cfg->lut_params.ramp_step_ms = ramp_step_ms;
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->lut_params.ramp_step_ms = previous_ramp_step_ms;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new ramp step value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t lut_flags_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	u32 lut_flags;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret;
+	u32 previous_lut_flags;
+	struct pwm_config_data *pwm_cfg;
+
+	ret = kstrtou32(buf, 10, &lut_flags);
+	if (ret)
+		return ret;
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for lut flags\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	previous_lut_flags = pwm_cfg->lut_params.flags;
+
+	pwm_free(pwm_cfg->pwm_dev);
+	pwm_cfg->lut_params.flags = lut_flags;
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret) {
+		pwm_cfg->lut_params.flags = previous_lut_flags;
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
+		dev_err(&led->spmi_dev->dev,
+			"Failed to initialize pwm with new lut flags value\n");
+		return ret;
+	}
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+}
+
+static ssize_t duty_pcts_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	int num_duty_pcts = 0;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	char *buffer;
+	ssize_t ret;
+	int i = 0;
+	int max_duty_pcts;
+	struct pwm_config_data *pwm_cfg;
+	u32 previous_num_duty_pcts;
+	int value;
+	int *previous_duty_pcts;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	switch (led->id) {
+	case QPNP_ID_LED_MPP:
+		pwm_cfg = led->mpp_cfg->pwm_cfg;
+		max_duty_pcts = PWM_LUT_MAX_SIZE;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		pwm_cfg = led->rgb_cfg->pwm_cfg;
+		max_duty_pcts = PWM_LUT_MAX_SIZE;
+		break;
+	default:
+		dev_err(&led->spmi_dev->dev,
+			"Invalid LED id type for duty pcts\n");
+		return -EINVAL;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE)
+		pwm_cfg->blinking = true;
+
+	buffer = (char *)buf;
+
+	for (i = 0; i < max_duty_pcts; i++) {
+		if (buffer == NULL)
+			break;
+		ret = sscanf((const char *)buffer, "%u,%s", &value, buffer);
+		pwm_cfg->old_duty_pcts[i] = value;
+		num_duty_pcts++;
+		if (ret <= 1)
+			break;
+	}
+
+	if (num_duty_pcts >= max_duty_pcts) {
+		dev_err(&led->spmi_dev->dev,
+			"Number of duty pcts given exceeds max (%d)\n",
+			max_duty_pcts);
+		return -EINVAL;
+	}
+
+	previous_num_duty_pcts = pwm_cfg->duty_cycles->num_duty_pcts;
+	previous_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
+
+	pwm_cfg->duty_cycles->num_duty_pcts = num_duty_pcts;
+	pwm_cfg->duty_cycles->duty_pcts = pwm_cfg->old_duty_pcts;
+	pwm_cfg->old_duty_pcts = previous_duty_pcts;
+	pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
+
+	pwm_free(pwm_cfg->pwm_dev);
+	ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	if (ret)
+		goto restore;
+
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return count;
+
+restore:
+	dev_err(&led->spmi_dev->dev,
+		"Failed to initialize pwm with new duty pcts value\n");
+	pwm_cfg->duty_cycles->num_duty_pcts = previous_num_duty_pcts;
+	pwm_cfg->old_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
+	pwm_cfg->duty_cycles->duty_pcts = previous_duty_pcts;
+	pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
+	pwm_free(pwm_cfg->pwm_dev);
+	qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+	return ret;
+}
+
 static void led_blink(struct qpnp_led_data *led,
 			struct pwm_config_data *pwm_cfg)
 {
-	u8 previous_mode;
-
-	previous_mode = pwm_cfg->mode;
 	if (pwm_cfg->use_blink) {
 		if (led->cdev.brightness) {
+			pwm_cfg->blinking = true;
 			if (led->id == QPNP_ID_LED_MPP)
 				led->mpp_cfg->pwm_mode = LPG_MODE;
 			pwm_cfg->mode = LPG_MODE;
-			pwm_free(pwm_cfg->pwm_dev);
-			qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
-			qpnp_led_set(&led->cdev, led->cdev.brightness);
-			if (led->id == QPNP_ID_LED_MPP)
-				led->mpp_cfg->pwm_mode = previous_mode;
-			pwm_cfg->mode = previous_mode;
 		} else {
-			pwm_free(pwm_cfg->pwm_dev);
-			qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
-			qpnp_led_set(&led->cdev, led->cdev.brightness);
+			pwm_cfg->blinking = false;
+			pwm_cfg->mode = pwm_cfg->default_mode;
+			if (led->id == QPNP_ID_LED_MPP)
+				led->mpp_cfg->pwm_mode = pwm_cfg->default_mode;
 		}
+		pwm_free(pwm_cfg->pwm_dev);
+		qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+		qpnp_led_set(&led->cdev, led->cdev.brightness);
 	}
 }
 
@@ -1399,6 +1853,13 @@
 
 static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
 static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+static DEVICE_ATTR(pwm_us, 0664, NULL, pwm_us_store);
+static DEVICE_ATTR(pause_lo, 0664, NULL, pause_lo_store);
+static DEVICE_ATTR(pause_hi, 0664, NULL, pause_hi_store);
+static DEVICE_ATTR(start_idx, 0664, NULL, start_idx_store);
+static DEVICE_ATTR(ramp_step_ms, 0664, NULL, ramp_step_ms_store);
+static DEVICE_ATTR(lut_flags, 0664, NULL, lut_flags_store);
+static DEVICE_ATTR(duty_pcts, 0664, NULL, duty_pcts_store);
 static DEVICE_ATTR(blink, 0664, NULL, blink_store);
 
 static struct attribute *led_attrs[] = {
@@ -1411,11 +1872,34 @@
 	.attrs = led_attrs,
 };
 
+static struct attribute *pwm_attrs[] = {
+	&dev_attr_pwm_us.attr,
+	NULL
+};
+
+static struct attribute *lpg_attrs[] = {
+	&dev_attr_pause_lo.attr,
+	&dev_attr_pause_hi.attr,
+	&dev_attr_start_idx.attr,
+	&dev_attr_ramp_step_ms.attr,
+	&dev_attr_lut_flags.attr,
+	&dev_attr_duty_pcts.attr,
+	NULL
+};
+
 static struct attribute *blink_attrs[] = {
 	&dev_attr_blink.attr,
 	NULL
 };
 
+static const struct attribute_group pwm_attr_group = {
+	.attrs = pwm_attrs,
+};
+
+static const struct attribute_group lpg_attr_group = {
+	.attrs = lpg_attrs,
+};
+
 static const struct attribute_group blink_attr_group = {
 	.attrs = blink_attrs,
 };
@@ -1840,11 +2324,18 @@
 		return -EINVAL;
 	}
 
+	led->flash_cfg->torch_enable =
+		of_property_read_bool(node, "qcom,torch-enable");
+
 	rc = of_property_read_u32(node, "qcom,current", &val);
-	if (!rc)
-		led->flash_cfg->current_prgm = (val *
+	if (!rc) {
+		if (led->flash_cfg->torch_enable)
+			led->flash_cfg->current_prgm = (val *
+				TORCH_MAX_LEVEL / led->max_current);
+		else
+			led->flash_cfg->current_prgm = (val *
 				FLASH_MAX_LEVEL / led->max_current);
-	else
+	} else
 		return -EINVAL;
 
 	rc = of_property_read_u32(node, "qcom,headroom", &val);
@@ -1883,9 +2374,6 @@
 	led->flash_cfg->safety_timer =
 		of_property_read_bool(node, "qcom,safety-timer");
 
-	led->flash_cfg->torch_enable =
-		of_property_read_bool(node, "qcom,torch-enable");
-
 	return 0;
 }
 
@@ -1942,12 +2430,23 @@
 
 		pwm_cfg->duty_cycles->duty_pcts =
 			devm_kzalloc(&spmi_dev->dev,
-			sizeof(int) * pwm_cfg->duty_cycles->num_duty_pcts,
+			sizeof(int) * PWM_LUT_MAX_SIZE,
 			GFP_KERNEL);
 		if (!pwm_cfg->duty_cycles->duty_pcts) {
 			dev_err(&spmi_dev->dev,
 				"Unable to allocate memory\n");
-			rc =  -ENOMEM;
+			rc = -ENOMEM;
+			goto bad_lpg_params;
+		}
+
+		pwm_cfg->old_duty_pcts =
+			devm_kzalloc(&spmi_dev->dev,
+			sizeof(int) * PWM_LUT_MAX_SIZE,
+			GFP_KERNEL);
+		if (!pwm_cfg->old_duty_pcts) {
+			dev_err(&spmi_dev->dev,
+				"Unable to allocate memory\n");
+			rc = -ENOMEM;
 			goto bad_lpg_params;
 		}
 
@@ -2062,6 +2561,7 @@
 			return -ENOMEM;
 		}
 		led->kpdbl_cfg->pwm_cfg->mode = led_mode;
+		led->kpdbl_cfg->pwm_cfg->default_mode = led_mode;
 	} else
 		return rc;
 
@@ -2130,6 +2630,7 @@
 			return -ENOMEM;
 		}
 		led->rgb_cfg->pwm_cfg->mode = led_mode;
+		led->rgb_cfg->pwm_cfg->default_mode = led_mode;
 	} else
 		return rc;
 
@@ -2196,6 +2697,7 @@
 			return -ENOMEM;
 		}
 		led->mpp_cfg->pwm_cfg->mode = led_mode;
+		led->mpp_cfg->pwm_cfg->default_mode = led_mode;
 	} else
 		return rc;
 
@@ -2331,7 +2833,8 @@
 			goto fail_id_check;
 		}
 
-		spin_lock_init(&led->lock);
+		mutex_init(&led->lock);
+		INIT_WORK(&led->work, qpnp_led_work);
 
 		rc =  qpnp_led_initialize(led);
 		if (rc < 0)
@@ -2360,27 +2863,60 @@
 		if (led->id == QPNP_ID_LED_MPP) {
 			if (!led->mpp_cfg->pwm_cfg)
 				break;
+			if (led->mpp_cfg->pwm_cfg->mode == PWM_MODE) {
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&pwm_attr_group);
+				if (rc)
+					goto fail_id_check;
+			}
 			if (led->mpp_cfg->pwm_cfg->use_blink) {
 				rc = sysfs_create_group(&led->cdev.dev->kobj,
 					&blink_attr_group);
 				if (rc)
 					goto fail_id_check;
+
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&lpg_attr_group);
+				if (rc)
+					goto fail_id_check;
+			} else if (led->mpp_cfg->pwm_cfg->mode == LPG_MODE) {
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&lpg_attr_group);
+				if (rc)
+					goto fail_id_check;
 			}
 		} else if ((led->id == QPNP_ID_RGB_RED) ||
 			(led->id == QPNP_ID_RGB_GREEN) ||
 			(led->id == QPNP_ID_RGB_BLUE)) {
+			if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&pwm_attr_group);
+				if (rc)
+					goto fail_id_check;
+			}
 			if (led->rgb_cfg->pwm_cfg->use_blink) {
 				rc = sysfs_create_group(&led->cdev.dev->kobj,
 					&blink_attr_group);
 				if (rc)
 					goto fail_id_check;
+
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&lpg_attr_group);
+				if (rc)
+					goto fail_id_check;
+			} else if (led->rgb_cfg->pwm_cfg->mode == LPG_MODE) {
+				rc = sysfs_create_group(&led->cdev.dev->kobj,
+					&lpg_attr_group);
+				if (rc)
+					goto fail_id_check;
 			}
 		}
 
 		/* configure default state */
 		if (led->default_on) {
 			led->cdev.brightness = led->cdev.max_brightness;
-			qpnp_led_set(&led->cdev, led->cdev.brightness);
+			__qpnp_led_work(led, led->cdev.brightness);
+			schedule_work(&led->work);
 			if (led->turn_off_delay_ms > 0)
 				qpnp_led_turn_off(led);
 		} else
@@ -2392,8 +2928,11 @@
 	return 0;
 
 fail_id_check:
-	for (i = 0; i < parsed_leds; i++)
+	for (i = 0; i < parsed_leds; i++) {
+		mutex_destroy(&led_array[i].lock);
 		led_classdev_unregister(&led_array[i].cdev);
+	}
+
 	return rc;
 }
 
@@ -2403,6 +2942,8 @@
 	int i, parsed_leds = led_array->num_leds;
 
 	for (i = 0; i < parsed_leds; i++) {
+		cancel_work_sync(&led_array[i].work);
+		mutex_destroy(&led_array[i].lock);
 		led_classdev_unregister(&led_array[i].cdev);
 		switch (led_array[i].id) {
 		case QPNP_ID_WLED:
@@ -2418,6 +2959,35 @@
 		case QPNP_ID_RGB_RED:
 		case QPNP_ID_RGB_GREEN:
 		case QPNP_ID_RGB_BLUE:
+			if (led_array[i].rgb_cfg->pwm_cfg->mode == PWM_MODE)
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &pwm_attr_group);
+			if (led_array[i].rgb_cfg->pwm_cfg->use_blink) {
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &blink_attr_group);
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &lpg_attr_group);
+			} else if (led_array[i].rgb_cfg->pwm_cfg->mode\
+					== LPG_MODE)
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &lpg_attr_group);
+			break;
+		case QPNP_ID_LED_MPP:
+			if (!led_array[i].mpp_cfg->pwm_cfg)
+				break;
+			if (led_array[i].mpp_cfg->pwm_cfg->mode == PWM_MODE)
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &pwm_attr_group);
+			if (led_array[i].mpp_cfg->pwm_cfg->use_blink) {
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &blink_attr_group);
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &lpg_attr_group);
+			} else if (led_array[i].mpp_cfg->pwm_cfg->mode\
+					== LPG_MODE)
+				sysfs_remove_group(&led_array[i].cdev.dev->\
+					kobj, &lpg_attr_group);
+			break;
 		default:
 			dev_err(&led_array[i].spmi_dev->dev,
 					"Invalid LED(%d)\n",
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 3a30970..ec2e381 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -164,6 +164,15 @@
 		1280 * 270. It does not support auto focus. It supports
 		few special effects like mono.
 
+config GC0339
+	bool "Sensor GC0339 (BAYER .3M)"
+	depends on MSMB_CAMERA
+	---help---
+		gc0339 is a Galaxycore .3 MP Bayer Sensor.
+		It supports 1 or 2 mipi lanes.
+		Preview and snapshot resolution shall be 640*480 at 30 fps,
+		It does not support auto focus.
+
 config OV8825
 	bool "OmniVision OV8825 (BAYER 8MP)"
 	depends on MSMB_CAMERA
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 df72328..d238649 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
@@ -24,6 +24,9 @@
 #include <linux/proc_fs.h>
 #include <linux/msm_ion.h>
 #include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
 #include <mach/iommu_domains.h>
 #include <mach/iommu.h>
 #include <mach/vreg.h>
@@ -36,6 +39,7 @@
 #include "msm_cpp.h"
 #include "msm_isp_util.h"
 #include "msm_camera_io_util.h"
+#include <linux/debugfs.h>
 
 #define MSM_CPP_DRV_NAME "msm_cpp"
 
@@ -43,6 +47,23 @@
 
 #define CONFIG_MSM_CPP_DBG 0
 
+#define CPP_CMD_TIMEOUT_MS 300
+
+struct msm_cpp_timer_data_t {
+	struct cpp_device *cpp_dev;
+	struct msm_cpp_frame_info_t *processed_frame;
+};
+
+struct msm_cpp_timer_t {
+	uint8_t used;
+	struct msm_cpp_timer_data_t data;
+	struct timer_list cpp_timer;
+};
+
+struct msm_cpp_timer_t cpp_timers[2];
+static int del_timer_idx;
+static int set_timer_idx;
+
 /* dump the frame command before writing to the hardware */
 #define  MSM_CPP_DUMP_FRM_CMD 0
 
@@ -109,6 +130,11 @@
 	{"micro_iface_clk", -1},
 };
 static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
+static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
+static void cpp_timer_callback(unsigned long data);
+
+uint8_t induce_error;
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
 
 static void msm_cpp_write(u32 data, void __iomem *cpp_base)
 {
@@ -472,7 +498,6 @@
 			tx_fifo[i] = msm_camera_io_r(cpp_dev->base +
 				MSM_CPP_MICRO_FIFO_TX_DATA);
 		}
-
 		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
 		queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx];
 		if (queue_cmd->cmd_used) {
@@ -494,6 +519,36 @@
 		spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
 
 		tasklet_schedule(&cpp_dev->cpp_tasklet);
+	} else if (irq_status & 0x7C0) {
+		pr_err("%s: fatal error: 0x%x\n", __func__, irq_status);
+		pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
+		pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
+		pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
+		pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
+		pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
+		pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
+		pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
+		pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
+		pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
+		pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
+		pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
+		pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
+		pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
+		pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
 	}
 	msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
 	return IRQ_HANDLED;
@@ -509,6 +564,7 @@
 	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
 	struct cpp_device *cpp_dev = (struct cpp_device *) data;
 	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+	struct msm_cpp_timer_t *timer = NULL;
 
 	while (atomic_read(&cpp_dev->irq_cnt)) {
 		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
@@ -535,6 +591,25 @@
 				msg_id = tx_fifo[i+2];
 				if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
 					CPP_DBG("Frame done!!\n");
+					/* delete CPP timer */
+					CPP_DBG("delete timer %d.\n",
+						del_timer_idx);
+					timer = &cpp_timers[del_timer_idx];
+					del_timer(&timer->cpp_timer);
+					timer->used = 0;
+					timer->data.processed_frame = NULL;
+					del_timer_idx = 1 - del_timer_idx;
+					msm_cpp_notify_frame_done(cpp_dev);
+				} else if (msg_id ==
+					MSM_CPP_MSG_ID_FRAME_NACK) {
+					pr_err("NACK error from hw!!\n");
+					CPP_DBG("delete timer %d.\n",
+						del_timer_idx);
+					timer = &cpp_timers[del_timer_idx];
+					del_timer(&timer->cpp_timer);
+					timer->used = 0;
+					timer->data.processed_frame = NULL;
+					del_timer_idx = 1 - del_timer_idx;
 					msm_cpp_notify_frame_done(cpp_dev);
 				}
 				i += cmd_len + 2;
@@ -543,48 +618,6 @@
 	}
 }
 
-static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
-{
-	disable_irq(cpp_dev->irq->start);
-
-	msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
-	msm_camera_io_w(0x1, cpp_dev->base +
-				 MSM_CPP_MICRO_BOOT_START);
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
-
-	/*Trigger MC to jump to start address*/
-	msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
-
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
-	msm_cpp_poll(cpp_dev->base, 0x1);
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
-
-	/*Get Bootloader Version*/
-	msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
-	pr_info("MC Bootloader Version: 0x%x\n",
-		   msm_cpp_read(cpp_dev->base));
-
-	/*Get Firmware Version*/
-	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
-	msm_cpp_write(0x1, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
-
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
-	msm_cpp_poll(cpp_dev->base, 0x2);
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
-	pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
-	enable_irq(cpp_dev->irq->start);
-	msm_camera_io_w_mb(0x8, cpp_dev->base +
-		MSM_CPP_MICRO_IRQGEN_MASK);
-	msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
-		MSM_CPP_MICRO_IRQGEN_CLR);
-}
-
 static int cpp_init_hardware(struct cpp_device *cpp_dev)
 {
 	int rc = 0;
@@ -663,8 +696,15 @@
 	cpp_dev->taskletq_idx = 0;
 	atomic_set(&cpp_dev->irq_cnt, 0);
 	msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
-	if (cpp_dev->is_firmware_loaded == 1)
-		msm_cpp_boot_hw(cpp_dev);
+	if (cpp_dev->is_firmware_loaded == 1) {
+		disable_irq(cpp_dev->irq->start);
+		cpp_load_fw(cpp_dev, NULL);
+		enable_irq(cpp_dev->irq->start);
+		msm_camera_io_w_mb(0x7C8, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_MASK);
+		msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_CLR);
+	}
 	return rc;
 req_irq_fail:
 	iounmap(cpp_dev->cpp_hw_base);
@@ -713,47 +753,44 @@
 	const struct firmware *fw = NULL;
 	struct device *dev = &cpp_dev->pdev->dev;
 
-	pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
-	rc = request_firmware(&fw, fw_name_bin, dev);
-	if (rc) {
-		dev_err(dev, "Failed to locate blob %s from device %p, Error: %d\n",
-				fw_name_bin, dev, rc);
-	}
-
-	CPP_DBG("HW Ver:0x%x\n",
-		msm_camera_io_r(cpp_dev->base +
-		MSM_CPP_MICRO_HW_VERSION));
-
+	msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
 	msm_camera_io_w(0x1, cpp_dev->base +
-					   MSM_CPP_MICRO_BOOT_START);
-	/*Enable MC clock*/
-	msm_camera_io_w(0x1, cpp_dev->base +
-					   MSM_CPP_MICRO_CLKEN_CTL);
-
+				 MSM_CPP_MICRO_BOOT_START);
 	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
 
-	/*Start firmware loading*/
-	msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
-	msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
-	if (NULL != fw)
-		ptr_bin = (uint32_t *)fw->data;
+	if (fw_name_bin) {
+		pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
+		rc = request_firmware(&fw, fw_name_bin, dev);
+		if (rc) {
+			dev_err(dev,
+				"Fail to loc blob %s from dev %p, Error: %d\n",
+				fw_name_bin, dev, rc);
+		}
+		if (NULL != fw)
+			ptr_bin = (uint32_t *)fw->data;
 
-	if (ptr_bin == NULL) {
-		pr_err("ptr_bin is NULL\n");
-	} else {
-		for (i = 0; i < fw->size/4; i++) {
-			if (ptr_bin) {
+		msm_camera_io_w(0x1, cpp_dev->base +
+					 MSM_CPP_MICRO_BOOT_START);
+		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+		msm_camera_io_w(0xFFFFFFFF, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_CLR);
+
+		/*Start firmware loading*/
+		msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
+		msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
+		msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
+
+		if (ptr_bin) {
+			for (i = 0; i < fw->size/4; i++) {
 				msm_cpp_write(*ptr_bin, cpp_dev->base);
 				ptr_bin++;
 			}
 		}
+		if (fw)
+			release_firmware(fw);
+		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
+		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
 	}
-	if (fw)
-		release_firmware(fw);
-
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
-	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
 
 	/*Trigger MC to jump to start address*/
 	msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
@@ -817,7 +854,6 @@
 	cpp_dev->cpp_open_cnt++;
 	if (cpp_dev->cpp_open_cnt == 1) {
 		cpp_init_hardware(cpp_dev);
-		iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_init_mem(cpp_dev);
 		cpp_dev->state = CPP_STATE_IDLE;
 	}
@@ -852,9 +888,38 @@
 
 	cpp_dev->cpp_open_cnt--;
 	if (cpp_dev->cpp_open_cnt == 0) {
+		pr_err("%s: irq_status: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
+		pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
+		pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
+		pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
+		pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
+		pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
+		pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
+		pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
+		pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
+		pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
+		pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
+		pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
+		pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
+		pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
+		pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
 		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
 		cpp_deinit_mem(cpp_dev);
-		iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_release_hardware(cpp_dev);
 		cpp_dev->state = CPP_STATE_OFF;
 	}
@@ -969,23 +1034,140 @@
 }
 #endif
 
+void msm_cpp_do_timeout_work(struct work_struct *work)
+{
+	int ret;
+	uint32_t i = 0;
+	struct msm_cpp_frame_info_t *this_frame =
+		cpp_timers[del_timer_idx].data.processed_frame;
+	struct msm_cpp_frame_info_t *second_frame = NULL;
+
+	pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
+		del_timer_idx, jiffies);
+	pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
+		this_frame->identity, this_frame->frame_id);
+	cpp_timers[del_timer_idx].used = 0;
+	cpp_timers[del_timer_idx].data.processed_frame = NULL;
+	del_timer_idx = 1 - del_timer_idx;
+
+	if (cpp_timers[del_timer_idx].used == 1) {
+		pr_err("deleting cpp_timer %d.\n", del_timer_idx);
+		del_timer(&cpp_timers[del_timer_idx].cpp_timer);
+		cpp_timers[del_timer_idx].used = 0;
+		second_frame = cpp_timers[del_timer_idx].data.processed_frame;
+		cpp_timers[del_timer_idx].data.processed_frame = NULL;
+		del_timer_idx = 1 - del_timer_idx;
+	}
+
+	disable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+	pr_err("Reloading firmware\n");
+	cpp_load_fw(cpp_timers[del_timer_idx].data.cpp_dev, NULL);
+	pr_err("Firmware loading done\n");
+	enable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+	msm_camera_io_w_mb(0x8, cpp_timers[del_timer_idx].data.cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_MASK);
+	msm_camera_io_w_mb(0xFFFF,
+		cpp_timers[del_timer_idx].data.cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_CLR);
+
+	cpp_timers[set_timer_idx].data.processed_frame = this_frame;
+	cpp_timers[set_timer_idx].used = 1;
+	pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
+	setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
+		(unsigned long)&cpp_timers[0]);
+	pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+		CPP_CMD_TIMEOUT_MS, jiffies);
+	ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+		jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+	if (ret)
+		pr_err("error in mod_timer\n");
+
+	set_timer_idx = 1 - set_timer_idx;
+	pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+		this_frame->identity, this_frame->frame_id);
+	msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
+	msm_cpp_dump_frame_cmd(this_frame->cpp_cmd_msg,
+		this_frame->msg_len);
+	for (i = 0; i < this_frame->msg_len; i++)
+		msm_cpp_write(this_frame->cpp_cmd_msg[i],
+			cpp_timers[set_timer_idx].data.cpp_dev->base);
+
+
+	if (second_frame != NULL) {
+		cpp_timers[set_timer_idx].data.processed_frame = second_frame;
+		cpp_timers[set_timer_idx].used = 1;
+		pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
+		setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
+			cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+		pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+			CPP_CMD_TIMEOUT_MS, jiffies);
+		ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+			jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+		if (ret)
+			pr_err("error in mod_timer\n");
+
+		set_timer_idx = 1 - set_timer_idx;
+		pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+			second_frame->identity, second_frame->frame_id);
+		msm_cpp_write(0x6,
+			cpp_timers[set_timer_idx].data.cpp_dev->base);
+		msm_cpp_dump_frame_cmd(second_frame->cpp_cmd_msg,
+			second_frame->msg_len);
+		for (i = 0; i < second_frame->msg_len; i++)
+			msm_cpp_write(second_frame->cpp_cmd_msg[i],
+				cpp_timers[set_timer_idx].data.cpp_dev->base);
+	}
+}
+
+void cpp_timer_callback(unsigned long data)
+{
+	struct msm_cpp_work_t *work =
+		cpp_timers[set_timer_idx].data.cpp_dev->work;
+	queue_work(cpp_timers[set_timer_idx].data.cpp_dev->timer_wq,
+		(struct work_struct *)work);
+}
+
 static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
 	struct msm_queue_cmd *frame_qcmd)
 {
 	uint32_t i;
 	int32_t rc = -EAGAIN;
+	int ret;
 	struct msm_cpp_frame_info_t *process_frame;
 
 	if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
 		process_frame = frame_qcmd->command;
 		msm_enqueue(&cpp_dev->processing_q,
 					&frame_qcmd->list_frame);
+
+		cpp_timers[set_timer_idx].data.processed_frame = process_frame;
+		cpp_timers[set_timer_idx].used = 1;
+		/* install timer for cpp timeout */
+		CPP_DBG("Installing cpp_timer %d\n", set_timer_idx);
+		setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
+			cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+		CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+			CPP_CMD_TIMEOUT_MS, jiffies);
+		ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+			jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+		if (ret)
+			pr_err("error in mod_timer\n");
+
+		set_timer_idx = 1 - set_timer_idx;
+
 		msm_cpp_write(0x6, cpp_dev->base);
 		msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
 				process_frame->msg_len);
-		for (i = 0; i < process_frame->msg_len; i++)
-			msm_cpp_write(process_frame->cpp_cmd_msg[i],
-				cpp_dev->base);
+		for (i = 0; i < process_frame->msg_len; i++) {
+			if ((induce_error) && (i == 1)) {
+				pr_err("Induce error\n");
+				msm_cpp_write(process_frame->cpp_cmd_msg[i]-1,
+					cpp_dev->base);
+				induce_error--;
+			} else
+				msm_cpp_write(process_frame->cpp_cmd_msg[i],
+					cpp_dev->base);
+		}
 		do_gettimeofday(&(process_frame->in_time));
 		rc = 0;
 	}
@@ -1097,7 +1279,7 @@
 			&buff_mgr_info);
 		if (rc < 0) {
 			rc = -EAGAIN;
-			pr_err("error getting buffer rc:%d\n", rc);
+			pr_debug("error getting buffer rc:%d\n", rc);
 			goto ERROR2;
 		}
 		new_frame->output_buffer_info[1].index = buff_mgr_info.index;
@@ -1184,7 +1366,6 @@
 	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
 	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
 	int rc = 0;
-	char *fw_name_bin;
 
 	if (ioctl_ptr == NULL) {
 		pr_err("ioctl_ptr is null\n");
@@ -1206,8 +1387,11 @@
 
 	case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
 		if (cpp_dev->is_firmware_loaded == 0) {
-			fw_name_bin = kzalloc(ioctl_ptr->len+1, GFP_KERNEL);
-			if (!fw_name_bin) {
+			kfree(cpp_dev->fw_name_bin);
+			cpp_dev->fw_name_bin = NULL;
+			cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1,
+				GFP_KERNEL);
+			if (!cpp_dev->fw_name_bin) {
 				pr_err("%s:%d: malloc error\n", __func__,
 					__LINE__);
 				mutex_unlock(&cpp_dev->mutex);
@@ -1222,24 +1406,24 @@
 				pr_err("ioctl_ptr->len is 0\n");
 				return -EINVAL;
 			}
-			rc = (copy_from_user(fw_name_bin,
+			rc = (copy_from_user(cpp_dev->fw_name_bin,
 				(void __user *)ioctl_ptr->ioctl_ptr,
 				ioctl_ptr->len) ? -EFAULT : 0);
 			if (rc) {
 				ERR_COPY_FROM_USER();
-				kfree(fw_name_bin);
+				kfree(cpp_dev->fw_name_bin);
+				cpp_dev->fw_name_bin = NULL;
 				mutex_unlock(&cpp_dev->mutex);
 				return -EINVAL;
 			}
-			*(fw_name_bin+ioctl_ptr->len) = '\0';
+			*(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0';
 			if (cpp_dev == NULL) {
 				pr_err("cpp_dev is null\n");
 				return -EINVAL;
 			}
 
 			disable_irq(cpp_dev->irq->start);
-			cpp_load_fw(cpp_dev, fw_name_bin);
-			kfree(fw_name_bin);
+			cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
 			enable_irq(cpp_dev->irq->start);
 			cpp_dev->is_firmware_loaded = 1;
 		}
@@ -1467,7 +1651,6 @@
 	return msm_register_domain(&cpp_fw_layout);
 }
 
-
 static int __devinit cpp_probe(struct platform_device *pdev)
 {
 	struct cpp_device *cpp_dev;
@@ -1582,23 +1765,35 @@
 	cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num;
 	cpp_dev->state = CPP_STATE_BOOT;
 	cpp_init_hardware(cpp_dev);
+	iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 
 	msm_camera_io_w(0x0, cpp_dev->base +
 					   MSM_CPP_MICRO_IRQGEN_MASK);
 	msm_camera_io_w(0xFFFF, cpp_dev->base +
 					   MSM_CPP_MICRO_IRQGEN_CLR);
-
+	msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0);
 	cpp_release_hardware(cpp_dev);
 	cpp_dev->state = CPP_STATE_OFF;
+	msm_cpp_enable_debugfs(cpp_dev);
 
 	msm_queue_init(&cpp_dev->eventData_q, "eventdata");
 	msm_queue_init(&cpp_dev->processing_q, "frame");
 	INIT_LIST_HEAD(&cpp_dev->tasklet_q);
 	tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet,
 		(unsigned long)cpp_dev);
+	cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
+	cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
+		GFP_KERNEL);
+	INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
 	cpp_dev->cpp_open_cnt = 0;
 	cpp_dev->is_firmware_loaded = 0;
+	cpp_timers[0].data.cpp_dev = cpp_dev;
+	cpp_timers[1].data.cpp_dev = cpp_dev;
+	cpp_timers[0].used = 0;
+	cpp_timers[1].used = 0;
+	cpp_dev->fw_name_bin = NULL;
 	return rc;
+
 ERROR3:
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 ERROR2:
@@ -1628,6 +1823,7 @@
 		return 0;
 	}
 
+	iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 	msm_sd_unregister(&cpp_dev->msm_sd);
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 	release_mem_region(cpp_dev->vbif_mem->start,
@@ -1635,6 +1831,8 @@
 	release_mem_region(cpp_dev->cpp_hw_mem->start,
 		resource_size(cpp_dev->cpp_hw_mem));
 	mutex_destroy(&cpp_dev->mutex);
+	kfree(cpp_dev->work);
+	destroy_workqueue(cpp_dev->timer_wq);
 	kfree(cpp_dev->cpp_clk);
 	kfree(cpp_dev);
 	return 0;
@@ -1660,6 +1858,30 @@
 	platform_driver_unregister(&cpp_driver);
 }
 
+static int msm_cpp_debugfs_error_s(void *data, u64 val)
+{
+	pr_err("setting error inducement");
+	induce_error = val;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL,
+	msm_cpp_debugfs_error_s, "%llu\n");
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
+{
+	struct dentry *debugfs_base;
+	debugfs_base = debugfs_create_dir("msm_cpp", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("error", S_IRUGO | S_IWUSR, debugfs_base,
+		(void *)cpp_dev, &cpp_debugfs_error))
+		return -ENOMEM;
+
+	return 0;
+}
+
 module_init(msm_cpp_init_module);
 module_exit(msm_cpp_exit_module);
 MODULE_DESCRIPTION("MSM CPP driver");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 36a5fa5..0a70d37 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -147,6 +147,11 @@
 	struct list_head native_buff_head;
 };
 
+struct msm_cpp_work_t {
+	struct work_struct my_work;
+	struct cpp_device *cpp_dev;
+};
+
 struct cpp_device {
 	struct platform_device *pdev;
 	struct msm_sd_subdev msm_sd;
@@ -165,6 +170,9 @@
 	struct mutex mutex;
 	enum cpp_state state;
 	uint8_t is_firmware_loaded;
+	char *fw_name_bin;
+	struct workqueue_struct *timer_wq;
+	struct msm_cpp_work_t *work;
 
 	int domain_num;
 	struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index b315959..40931ef 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -10,5 +10,7 @@
 obj-$(CONFIG_OV8825) += ov8825.o
 obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_OV9724) += ov9724.o
+obj-$(CONFIG_HI256) += hi256.o
 obj-$(CONFIG_MT9M114) += mt9m114.o
 obj-$(CONFIG_SP1628) += sp1628.o
+obj-$(CONFIG_GC0339) += gc0339.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 676862f..a6c5639 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -111,9 +111,30 @@
 	msm_camera_io_w(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR);
 	rc = wait_for_completion_interruptible_timeout(
 		&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
-	if (rc <= 0)
-		pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
-			__func__, __LINE__);
+	if (rc < 0) {
+		pr_err("%s:%d wait failed\n", __func__, __LINE__);
+	} else if (rc == 0) {
+		pr_err("%s:%d wait timeout\n", __func__, __LINE__);
+
+		/* Set reset pending flag to TRUE */
+		cci_dev->cci_master_info[master].reset_pending = TRUE;
+
+		/* Set proper mask to RESET CMD address based on MASTER */
+		if (master == MASTER_0)
+			msm_camera_io_w(CCI_M0_RESET_RMSK,
+				cci_dev->base + CCI_RESET_CMD_ADDR);
+		else
+			msm_camera_io_w(CCI_M1_RESET_RMSK,
+				cci_dev->base + CCI_RESET_CMD_ADDR);
+
+		/* wait for reset done irq */
+		rc = wait_for_completion_interruptible_timeout(
+			&cci_dev->cci_master_info[master].reset_complete,
+			CCI_TIMEOUT);
+		if (rc <= 0)
+			pr_err("%s:%d wait failed %d\n", __func__, __LINE__,
+				rc);
+	}
 	return;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 3dd3a4e..e096e96 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -130,12 +130,6 @@
 		pr_err("%s failed e_ctrl is NULL\n", __func__);
 		return -EINVAL;
 	}
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
-		&e_ctrl->i2c_client, MSM_CCI_INIT);
-		if (rc < 0)
-			pr_err("%s cci_init failed\n", __func__);
-	}
 	CDBG("%s X\n", __func__);
 	return rc;
 }
@@ -149,12 +143,6 @@
 		pr_err("%s failed e_ctrl is NULL\n", __func__);
 		return -EINVAL;
 	}
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
-			&e_ctrl->i2c_client, MSM_CCI_RELEASE);
-		if (rc < 0)
-			pr_err("%s cci_init failed\n", __func__);
-	}
 	CDBG("%s X\n", __func__);
 	return rc;
 }
@@ -445,14 +433,18 @@
 	struct msm_eeprom_board_info *eb_info;
 	struct msm_camera_power_ctrl_t *power_info =
 		&e_ctrl->eboard_info->power_info;
-	struct spi_device *spi = e_ctrl->i2c_client.spi_client->spi_master;
-	struct device_node *of_node = spi->dev.of_node;
+	struct device_node *of_node = NULL;
 	struct msm_camera_gpio_conf *gconf = NULL;
 	uint16_t gpio_array_size = 0;
 	uint16_t *gpio_array = NULL;
 
 	eb_info = e_ctrl->eboard_info;
-	rc = msm_camera_get_dt_power_setting_data(spi->dev.of_node,
+	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+		of_node = e_ctrl->i2c_client.
+			spi_client->spi_master->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		of_node = e_ctrl->pdev->dev.of_node;
+	rc = msm_camera_get_dt_power_setting_data(of_node,
 		  &power_info->power_setting, &power_info->power_setting_size);
 	if (rc)
 		return rc;
@@ -787,26 +779,35 @@
 		goto board_free;
 	}
 
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
-		&e_ctrl->i2c_client, MSM_CCI_INIT);
-		if (rc < 0)
-			pr_err("%s cci_init failed\n", __func__);
-	}
+	rc = msm_eeprom_get_dt_data(e_ctrl);
+	if (rc)
+		goto board_free;
 
 	rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
 	if (rc)
 		goto board_free;
 
+	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("failed rc %d\n", rc);
+		goto memdata_free;
+	}
 	rc = read_eeprom_memory(e_ctrl);
 	if (rc < 0) {
 		pr_err("%s read_eeprom_memory failed\n", __func__);
-		goto memdata_free;
+		goto power_down;
 	}
 		pr_err("%s line %d\n", __func__, __LINE__);
 	for (j = 0; j < e_ctrl->num_bytes; j++)
 		CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
 
+	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("failed rc %d\n", rc);
+		goto memdata_free;
+	}
 	v4l2_subdev_init(&e_ctrl->msm_sd.sd,
 		e_ctrl->eeprom_v4l2_subdev_ops);
 	v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl);
@@ -821,16 +822,13 @@
 	msm_sd_register(&e_ctrl->msm_sd);
 
 
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
-			&e_ctrl->i2c_client, MSM_CCI_RELEASE);
-		if (rc < 0)
-			pr_err("%s cci_init failed\n", __func__);
-	}
 	e_ctrl->is_supported = 1;
 	CDBG("%s X\n", __func__);
 	return rc;
 
+power_down:
+	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
 memdata_free:
 	kfree(e_ctrl->memory_data);
 	kfree(eb_info->eeprom_map);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
new file mode 100644
index 0000000..8cba04c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -0,0 +1,676 @@
+/* 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 <mach/gpiomux.h>
+#include "msm_sensor.h"
+#include "msm_cci.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_i2c_mux.h"
+
+
+#define GC0339_SENSOR_NAME "gc0339"
+DEFINE_MSM_MUTEX(gc0339_mut);
+
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+
+static struct msm_sensor_ctrl_t gc0339_s_ctrl;
+
+static struct msm_sensor_power_setting gc0339_power_setting[] = {
+
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 1,
+	},
+};
+
+static struct v4l2_subdev_info gc0339_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static int32_t msm_gc0339_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &gc0339_s_ctrl);
+}
+
+static const struct i2c_device_id gc0339_i2c_id[] = {
+	{GC0339_SENSOR_NAME, (kernel_ulong_t)&gc0339_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver gc0339_i2c_driver = {
+	.id_table = gc0339_i2c_id,
+	.probe  = msm_gc0339_i2c_probe,
+	.driver = {
+		.name = GC0339_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client gc0339_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+int32_t gc0339_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0, index = 0;
+	struct msm_sensor_power_setting_array *power_setting_array = NULL;
+	struct msm_sensor_power_setting *power_setting = NULL;
+	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	power_setting_array = &s_ctrl->power_setting_array;
+
+	if (data->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+		pr_err("%s:%d mux install\n", __func__, __LINE__);
+		msm_gpiomux_install(
+			(struct msm_gpiomux_config *)
+			data->gpio_conf->cam_gpiomux_conf_tbl,
+			data->gpio_conf->cam_gpiomux_conf_tbl_size);
+	}
+
+	rc = msm_camera_request_gpio_table(
+		data->gpio_conf->cam_gpio_req_tbl,
+		data->gpio_conf->cam_gpio_req_tbl_size, 1);
+	if (rc < 0) {
+		pr_err("%s: request gpio failed\n", __func__);
+		return rc;
+	}
+	for (index = 0; index < power_setting_array->size; index++) {
+		CDBG("%s index %d\n", __func__, index);
+		power_setting = &power_setting_array->power_setting[index];
+		CDBG("%s type %d\n", __func__, power_setting->seq_type);
+		switch (power_setting->seq_type) {
+		case SENSOR_CLK:
+			if (power_setting->seq_val >= s_ctrl->clk_info_size) {
+				pr_err("%s clk index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					s_ctrl->clk_info_size);
+				goto power_up_failed;
+			}
+			if (power_setting->config_val)
+				s_ctrl->clk_info[power_setting->seq_val].
+					clk_rate = power_setting->config_val;
+
+			rc = msm_cam_clk_enable(s_ctrl->dev,
+				&s_ctrl->clk_info[0],
+				(struct clk **)&power_setting->data[0],
+				s_ctrl->clk_info_size,
+				1);
+			if (rc < 0) {
+				pr_err("%s: clk enable failed\n",
+					__func__);
+				goto power_up_failed;
+			}
+			break;
+		case SENSOR_GPIO:
+			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
+				!data->gpio_conf->gpio_num_info) {
+				pr_err("%s gpio index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				goto power_up_failed;
+			}
+			pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
+				data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val]);
+			if (data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val])
+				gpio_set_value_cansleep(
+					data->gpio_conf->gpio_num_info->gpio_num
+					[power_setting->seq_val],
+					power_setting->config_val);
+			break;
+		case SENSOR_VREG:
+			if (power_setting->seq_val >= CAM_VREG_MAX) {
+				pr_err("%s vreg index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				goto power_up_failed;
+			}
+			msm_camera_config_single_vreg(s_ctrl->dev,
+				&data->cam_vreg[power_setting->seq_val],
+				(struct regulator **)&power_setting->data[0],
+				1);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				power_setting->seq_type);
+			break;
+		}
+		if (power_setting->delay > 20) {
+			msleep(power_setting->delay);
+		} else if (power_setting->delay) {
+			usleep_range(power_setting->delay * 1000,
+				(power_setting->delay * 1000) + 1000);
+		}
+	}
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+			s_ctrl->sensor_i2c_client, MSM_CCI_INIT);
+		if (rc < 0) {
+			pr_err("%s cci_init failed\n", __func__);
+			goto power_up_failed;
+		}
+	}
+	if (s_ctrl->func_tbl->sensor_match_id)
+		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+	else
+		rc = msm_sensor_match_id(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc);
+		goto power_up_failed;
+	}
+
+	CDBG("%s exit\n", __func__);
+	return 0;
+power_up_failed:
+	pr_err("%s:%d failed\n", __func__, __LINE__);
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+	}
+
+	for (index--; index >= 0; index--) {
+		CDBG("%s index %d\n", __func__, index);
+		power_setting = &power_setting_array->power_setting[index];
+		CDBG("%s type %d\n", __func__, power_setting->seq_type);
+		switch (power_setting->seq_type) {
+		case SENSOR_CLK:
+			msm_cam_clk_enable(s_ctrl->dev,
+				&s_ctrl->clk_info[0],
+				(struct clk **)&power_setting->data[0],
+				s_ctrl->clk_info_size,
+				0);
+			break;
+		case SENSOR_GPIO:
+			gpio_set_value_cansleep(
+				data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			break;
+		case SENSOR_VREG:
+			msm_camera_config_single_vreg(s_ctrl->dev,
+				&data->cam_vreg[power_setting->seq_val],
+				(struct regulator **)&power_setting->data[0],
+				0);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				power_setting->seq_type);
+			break;
+		}
+		if (power_setting->delay > 20) {
+			msleep(power_setting->delay);
+		} else if (power_setting->delay) {
+			usleep_range(power_setting->delay * 1000,
+				(power_setting->delay * 1000) + 1000);
+		}
+	}
+	msm_camera_request_gpio_table(
+		data->gpio_conf->cam_gpio_req_tbl,
+		data->gpio_conf->cam_gpio_req_tbl_size, 0);
+	return rc;
+}
+
+int32_t gc0339_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t index = 0;
+	struct msm_sensor_power_setting_array *power_setting_array = NULL;
+	struct msm_sensor_power_setting *power_setting = NULL;
+	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	power_setting_array = &s_ctrl->power_setting_array;
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+	}
+
+	for (index = (power_setting_array->size - 1); index >= 0; index--) {
+		CDBG("%s index %d\n", __func__, index);
+		power_setting = &power_setting_array->power_setting[index];
+		CDBG("%s type %d\n", __func__, power_setting->seq_type);
+		switch (power_setting->seq_type) {
+		case SENSOR_CLK:
+			msm_cam_clk_enable(s_ctrl->dev,
+				&s_ctrl->clk_info[0],
+				(struct clk **)&power_setting->data[0],
+				s_ctrl->clk_info_size,
+				0);
+			break;
+		case SENSOR_GPIO:
+			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
+				!data->gpio_conf->gpio_num_info) {
+				pr_err("%s gpio index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				continue;
+			}
+			gpio_set_value_cansleep(
+				data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			break;
+		case SENSOR_VREG:
+			if (power_setting->seq_val >= CAM_VREG_MAX) {
+				pr_err("%s vreg index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				continue;
+			}
+			msm_camera_config_single_vreg(s_ctrl->dev,
+				&data->cam_vreg[power_setting->seq_val],
+				(struct regulator **)&power_setting->data[0],
+				0);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				power_setting->seq_type);
+			break;
+		}
+		if (power_setting->delay > 20) {
+			msleep(power_setting->delay);
+		} else if (power_setting->delay) {
+			usleep_range(power_setting->delay * 1000,
+				(power_setting->delay * 1000) + 1000);
+		}
+	}
+	msm_camera_request_gpio_table(
+		data->gpio_conf->cam_gpio_req_tbl,
+		data->gpio_conf->cam_gpio_req_tbl_size, 0);
+	CDBG("%s exit\n", __func__);
+	return 0;
+}
+
+int32_t gc0339_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+				s_ctrl->sensor_i2c_client,
+				0xfc,
+				0x10, MSM_CAMERA_I2C_BYTE_DATA);
+	rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
+			&chipid, MSM_CAMERA_I2C_BYTE_DATA);
+	if (rc < 0) {
+		pr_err("%s: %s: read id failed\n", __func__,
+			s_ctrl->sensordata->sensor_name);
+		return rc;
+	}
+
+	if (chipid != s_ctrl->sensordata->slave_info->sensor_id) {
+		pr_err("msm_sensor_match_id chip id doesnot match\n");
+		return -ENODEV;
+	}
+	return rc;
+}
+
+int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl,
+	void __user *argp)
+{
+	struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
+	long rc = 0;
+	int32_t i = 0;
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	switch (cdata->cfgtype) {
+	case CFG_GET_SENSOR_INFO:
+		memcpy(cdata->cfg.sensor_info.sensor_name,
+			s_ctrl->sensordata->sensor_name,
+			sizeof(cdata->cfg.sensor_info.sensor_name));
+		cdata->cfg.sensor_info.session_id =
+			s_ctrl->sensordata->sensor_info->session_id;
+		for (i = 0; i < SUB_MODULE_MAX; i++)
+			cdata->cfg.sensor_info.subdev_id[i] =
+				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.sensor_name);
+		CDBG("%s:%d session id %d\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.session_id);
+		for (i = 0; i < SUB_MODULE_MAX; i++)
+			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
+				cdata->cfg.sensor_info.subdev_id[i]);
+
+		break;
+	case CFG_GET_SENSOR_INIT_PARAMS:
+		cdata->cfg.sensor_init_params =
+			*s_ctrl->sensordata->sensor_init_params;
+		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
+			__LINE__,
+			cdata->cfg.sensor_init_params.modes_supported,
+			cdata->cfg.sensor_init_params.position,
+			cdata->cfg.sensor_init_params.sensor_mount_angle);
+		break;
+	case CFG_SET_SLAVE_INFO: {
+		struct msm_camera_sensor_slave_info sensor_slave_info;
+		struct msm_sensor_power_setting_array *power_setting_array;
+		int slave_index = 0;
+		if (copy_from_user(&sensor_slave_info,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_sensor_slave_info))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		/* Update sensor slave address */
+		if (sensor_slave_info.slave_addr) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				sensor_slave_info.slave_addr >> 1;
+		}
+
+		/* Update sensor address type */
+		s_ctrl->sensor_i2c_client->addr_type =
+			sensor_slave_info.addr_type;
+
+		/* Update power up / down sequence */
+		s_ctrl->power_setting_array =
+			sensor_slave_info.power_setting_array;
+		power_setting_array = &s_ctrl->power_setting_array;
+		power_setting_array->power_setting = kzalloc(
+			power_setting_array->size *
+			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
+		if (!power_setting_array->power_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(power_setting_array->power_setting,
+			(void *)
+			sensor_slave_info.power_setting_array.power_setting,
+			power_setting_array->size *
+			sizeof(struct msm_sensor_power_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		s_ctrl->free_power_setting = true;
+		CDBG("%s sensor id %x\n", __func__,
+			sensor_slave_info.slave_addr);
+		CDBG("%s sensor addr type %d\n", __func__,
+			sensor_slave_info.addr_type);
+		CDBG("%s sensor reg %x\n", __func__,
+			sensor_slave_info.sensor_id_info.sensor_id_reg_addr);
+		CDBG("%s sensor id %x\n", __func__,
+			sensor_slave_info.sensor_id_info.sensor_id);
+		for (slave_index = 0; slave_index <
+			power_setting_array->size; slave_index++) {
+			CDBG("%s i %d power setting %d %d %ld %d\n", __func__,
+				slave_index,
+				power_setting_array->power_setting[slave_index].
+				seq_type,
+				power_setting_array->power_setting[slave_index].
+				seq_val,
+				power_setting_array->power_setting[slave_index].
+				config_val,
+				power_setting_array->power_setting[slave_index].
+				delay);
+		}
+		break;
+	}
+	case CFG_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+		if (copy_from_user(&conf_array,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting, (void *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &conf_array);
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_WRITE_I2C_SEQ_ARRAY: {
+		struct msm_camera_i2c_seq_reg_setting conf_array;
+		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+
+		if (copy_from_user(&conf_array,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_seq_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_seq_reg_array)),
+			GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting, (void *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_seq_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write_seq_table(s_ctrl->sensor_i2c_client,
+			&conf_array);
+		kfree(reg_setting);
+		break;
+	}
+
+	case CFG_POWER_UP:
+		if (s_ctrl->func_tbl->sensor_power_up)
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_POWER_DOWN:
+		if (s_ctrl->func_tbl->sensor_power_down)
+			rc = s_ctrl->func_tbl->sensor_power_down(
+				s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_STOP_STREAM_SETTING: {
+		struct msm_camera_i2c_reg_setting *stop_setting =
+			&s_ctrl->stop_setting;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+		if (copy_from_user(stop_setting,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = stop_setting->reg_setting;
+		stop_setting->reg_setting = kzalloc(stop_setting->size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!stop_setting->reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(stop_setting->reg_setting,
+			(void *)reg_setting,
+			stop_setting->size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(stop_setting->reg_setting);
+			stop_setting->reg_setting = NULL;
+			stop_setting->size = 0;
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+	return rc;
+}
+
+static struct msm_sensor_fn_t gc0339_sensor_fn_t = {
+	.sensor_power_up = gc0339_power_up,
+	.sensor_power_down = gc0339_power_down,
+	.sensor_match_id = gc0339_match_id,
+	.sensor_config = gc0339_config,
+};
+
+
+static struct msm_sensor_ctrl_t gc0339_s_ctrl = {
+	.sensor_i2c_client = &gc0339_sensor_i2c_client,
+	.power_setting_array.power_setting = gc0339_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(gc0339_power_setting),
+	.msm_sensor_mutex = &gc0339_mut,
+	.sensor_v4l2_subdev_info = gc0339_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(gc0339_subdev_info),
+	.func_tbl = &gc0339_sensor_fn_t,
+};
+
+static const struct of_device_id gc0339_dt_match[] = {
+	{.compatible = "shinetech,gc0339", .data = &gc0339_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, gc0339_dt_match);
+
+static struct platform_driver gc0339_platform_driver = {
+	.driver = {
+		.name = "shinetech,gc0339",
+		.owner = THIS_MODULE,
+		.of_match_table = gc0339_dt_match,
+	},
+};
+
+static int32_t gc0339_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+
+	match = of_match_device(gc0339_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init gc0339_init_module(void)
+{
+	int32_t rc = 0;
+
+	rc = platform_driver_probe(&gc0339_platform_driver,
+		gc0339_platform_probe);
+	if (!rc)
+		return rc;
+	return i2c_add_driver(&gc0339_i2c_driver);
+}
+
+static void __exit gc0339_exit_module(void)
+{
+	if (gc0339_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&gc0339_s_ctrl);
+		platform_driver_unregister(&gc0339_platform_driver);
+	} else
+		i2c_del_driver(&gc0339_i2c_driver);
+	return;
+}
+
+module_init(gc0339_init_module);
+module_exit(gc0339_exit_module);
+MODULE_DESCRIPTION("gc0339");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
new file mode 100644
index 0000000..f1df703
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -0,0 +1,1413 @@
+/* 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 "msm_sensor.h"
+#include "msm_cci.h"
+#include "msm_camera_io_util.h"
+#define HI256_SENSOR_NAME "hi256"
+#define PLATFORM_DRIVER_NAME "msm_camera_hi256"
+
+#define CONFIG_MSMB_CAMERA_DEBUG
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+
+DEFINE_MSM_MUTEX(hi256_mut);
+static struct msm_sensor_ctrl_t hi256_s_ctrl;
+
+static struct msm_sensor_power_setting hi256_power_setting[] = {
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 20,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 20,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct msm_camera_i2c_reg_conf hi256_uxga_settings[] = {
+	{0x03, 0x00},
+	{0x01, 0xf1},
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x03, 0x22},
+	{0x10, 0x69},
+	{0x03, 0x00},
+	{0x12, 0x00},
+	{0x20, 0x00},
+	{0x21, 0x0a},
+	{0x22, 0x00},
+	{0x23, 0x0a},
+	{0x40, 0x01},
+	{0x41, 0x68},
+	{0x42, 0x00},
+	{0x43, 0x12},
+	{0x03, 0x10},
+	{0x3f, 0x00},
+	{0x03, 0x12},
+	{0x20, 0x0f},
+	{0x21, 0x0f},
+	{0x90, 0x5d},
+	{0x03, 0x13},
+	{0x80, 0xfd},
+	{0x03, 0x00},
+	{0x10, 0x00},
+	{0x03, 0x48},
+	{0x72, 0x81},
+	{0x30, 0x0c},
+	{0x31, 0x80},
+	{0x03, 0x00},
+	{0x01, 0xf0},
+};
+
+static struct msm_camera_i2c_reg_conf hi256_start_settings[] = {
+	{0x03, 0x00},
+	{0x01, 0xf0},
+};
+
+static struct msm_camera_i2c_reg_conf hi256_stop_settings[] = {
+	{0x03, 0x00},
+	{0x01, 0xf1},
+};
+
+static struct msm_camera_i2c_reg_conf hi256_recommend_settings[] = {
+	{0x01, 0xf1},
+	{0x01, 0xf3},
+	{0x01, 0xf1},
+
+	{0x08, 0x0f},
+	{0x0a, 0x00},
+
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x03, 0x22},
+	{0x10, 0x69},
+
+	{0x03, 0x00},
+	{0x10, 0x13},
+	{0x11, 0x93},
+	{0x12, 0x00},
+	{0x0b, 0xaa},
+	{0x0c, 0xaa},
+	{0x0d, 0xaa},
+	{0x20, 0x00},
+	{0x21, 0x06},
+	{0x22, 0x00},
+	{0x23, 0x05},
+	{0x24, 0x04},
+	{0x25, 0xb0},
+	{0x26, 0x06},
+	{0x27, 0x40},
+	{0x40, 0x01},
+	{0x41, 0x78},
+	{0x42, 0x00},
+	{0x43, 0x14},
+	{0x45, 0x04},
+	{0x46, 0x18},
+	{0x47, 0xd8},
+	{0x80, 0x2e},
+	{0x81, 0x7e},
+	{0x82, 0x90},
+	{0x83, 0x00},
+	{0x84, 0x0c},
+	{0x85, 0x00},
+	{0x90, 0x0c},
+	{0x91, 0x0c},
+	{0x92, 0x78},
+	{0x93, 0x70},
+	{0x94, 0xff},
+	{0x95, 0xff},
+	{0x96, 0xdc},
+	{0x97, 0xfe},
+	{0x98, 0x38},
+	{0xa0, 0x45},
+	{0xa2, 0x45},
+	{0xa4, 0x45},
+	{0xa6, 0x45},
+	{0xa8, 0x45},
+	{0xaa, 0x45},
+	{0xac, 0x45},
+	{0xae, 0x45},
+	{0x99, 0x43},
+	{0x9a, 0x43},
+	{0x9b, 0x43},
+	{0x9c, 0x43},
+	{0x03, 0x02},
+	{0x12, 0x03},
+	{0x13, 0x03},
+	{0x15, 0x00},
+	{0x16, 0x00},
+	{0x17, 0x8C},
+	{0x18, 0x4c},
+	{0x19, 0x00},
+	{0x1a, 0x39},
+	{0x1c, 0x09},
+	{0x1d, 0x40},
+	{0x1e, 0x30},
+	{0x1f, 0x10},
+	{0x20, 0x77},
+	{0x21, 0x6d},
+	{0x22, 0x77},
+	{0x23, 0x30},
+	{0x24, 0x77},
+	{0x27, 0x3c},
+	{0x2b, 0x80},
+	{0x2e, 0x00},
+	{0x2f, 0x00},
+	{0x30, 0x05},
+	{0x50, 0x20},
+	{0x52, 0x01},
+	{0x53, 0xc1},
+	{0x55, 0x1c},
+	{0x56, 0x11},
+	{0x58, 0x22},
+	{0x59, 0x20},
+	{0x5d, 0xa2},
+	{0x5e, 0x5a},
+	{0x60, 0x87},
+	{0x61, 0x99},
+	{0x62, 0x88},
+	{0x63, 0x97},
+	{0x64, 0x88},
+	{0x65, 0x97},
+	{0x67, 0x0c},
+	{0x68, 0x0c},
+	{0x69, 0x0c},
+	{0x72, 0x89},
+	{0x73, 0x96},
+	{0x74, 0x89},
+	{0x75, 0x96},
+	{0x76, 0x89},
+	{0x77, 0x96},
+	{0x7c, 0x85},
+	{0x7d, 0xaf},
+	{0x80, 0x01},
+	{0x81, 0x7f},
+	{0x82, 0x13},
+	{0x83, 0x24},
+	{0x84, 0x7d},
+	{0x85, 0x81},
+	{0x86, 0x7d},
+	{0x87, 0x81},
+	{0x92, 0x48},
+	{0x93, 0x54},
+	{0x94, 0x7d},
+	{0x95, 0x81},
+	{0x96, 0x7d},
+	{0x97, 0x81},
+	{0xa0, 0x02},
+	{0xa1, 0x7b},
+	{0xa2, 0x02},
+	{0xa3, 0x7b},
+	{0xa4, 0x7b},
+	{0xa5, 0x02},
+	{0xa6, 0x7b},
+	{0xa7, 0x02},
+	{0xa8, 0x85},
+	{0xa9, 0x8c},
+	{0xaa, 0x85},
+	{0xab, 0x8c},
+	{0xac, 0x10},
+	{0xad, 0x16},
+	{0xae, 0x10},
+	{0xaf, 0x16},
+	{0xb0, 0x99},
+	{0xb1, 0xa3},
+	{0xb2, 0xa4},
+	{0xb3, 0xae},
+	{0xb4, 0x9b},
+	{0xb5, 0xa2},
+	{0xb6, 0xa6},
+	{0xb7, 0xac},
+	{0xb8, 0x9b},
+	{0xb9, 0x9f},
+	{0xba, 0xa6},
+	{0xbb, 0xaa},
+	{0xbc, 0x9b},
+	{0xbd, 0x9f},
+	{0xbe, 0xa6},
+	{0xbf, 0xaa},
+	{0xc4, 0x2c},
+	{0xc5, 0x43},
+	{0xc6, 0x63},
+	{0xc7, 0x79},
+	{0xc8, 0x2d},
+	{0xc9, 0x42},
+	{0xca, 0x2d},
+	{0xcb, 0x42},
+	{0xcc, 0x64},
+	{0xcd, 0x78},
+	{0xce, 0x64},
+	{0xcf, 0x78},
+	{0xd0, 0x0a},
+	{0xd1, 0x09},
+	{0xd4, 0x0c},
+	{0xd5, 0x0c},
+	{0xd6, 0x78},
+	{0xd7, 0x70},
+	{0xe0, 0xc4},
+	{0xe1, 0xc4},
+	{0xe2, 0xc4},
+	{0xe3, 0xc4},
+	{0xe4, 0x00},
+	{0xe8, 0x80},
+	{0xe9, 0x40},
+	{0xea, 0x7f},
+	{0xf0, 0xc1},
+	{0xf1, 0xc1},
+	{0xf2, 0xc1},
+	{0xf3, 0xc1},
+	{0xf4, 0xc1},
+	{0x03, 0x03},
+	{0x10, 0x10},
+	{0x03, 0x10},
+	{0x10, 0x03},
+	{0x12, 0x30},
+	{0x13, 0x02},
+	{0x20, 0x00},
+	{0x30, 0x00},
+	{0x31, 0x00},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x30},
+	{0x35, 0x00},
+	{0x36, 0x00},
+	{0x38, 0x00},
+	{0x3e, 0x58},
+	{0x3f, 0x00},
+	{0x40, 0x80},
+	{0x41, 0x00},
+	{0x48, 0x95},
+	{0x60, 0x67},
+	{0x61, 0x88},
+	{0x62, 0x90},
+	{0x63, 0x50},
+	{0x64, 0x41},
+	{0x66, 0x42},
+	{0x67, 0x20},
+	{0x6a, 0x71},
+	{0x6b, 0x84},
+	{0x6c, 0x72},
+	{0x6d, 0x83},
+	{0x03, 0x11},
+	{0x10, 0x7f},
+	{0x11, 0x40},
+	{0x12, 0x0a},
+	{0x13, 0xbb},
+	{0x26, 0x31},
+	{0x27, 0x34},
+	{0x28, 0x0f},
+	{0x29, 0x10},
+	{0x2b, 0x30},
+	{0x2c, 0x32},
+	{0x30, 0x70},
+	{0x31, 0x10},
+	{0x32, 0x58},
+	{0x33, 0x09},
+	{0x34, 0x06},
+	{0x35, 0x03},
+	{0x36, 0x70},
+	{0x37, 0x18},
+	{0x38, 0x58},
+	{0x39, 0x09},
+	{0x3a, 0x06},
+	{0x3b, 0x03},
+	{0x3c, 0x80},
+	{0x3d, 0x18},
+	{0x3e, 0x80},
+	{0x3f, 0x0c},
+	{0x40, 0x05},
+	{0x41, 0x06},
+	{0x42, 0x80},
+	{0x43, 0x18},
+	{0x44, 0x80},
+	{0x45, 0x0c},
+	{0x46, 0x05},
+	{0x47, 0x06},
+	{0x48, 0x90},
+	{0x49, 0x40},
+	{0x4a, 0x80},
+	{0x4b, 0x13},
+	{0x4c, 0x10},
+	{0x4d, 0x11},
+	{0x4e, 0x80},
+	{0x4f, 0x30},
+	{0x50, 0x80},
+	{0x51, 0x13},
+	{0x52, 0x10},
+	{0x53, 0x13},
+	{0x54, 0x11},
+	{0x55, 0x17},
+	{0x56, 0x20},
+	{0x57, 0x01},
+	{0x58, 0x00},
+	{0x59, 0x00},
+	{0x5a, 0x18},
+	{0x5b, 0x00},
+	{0x5c, 0x00},
+	{0x60, 0x3f},
+	{0x62, 0x60},
+	{0x70, 0x06},
+	{0x03, 0x12},
+	{0x20, 0x00},
+	{0x21, 0x00},
+	{0x25, 0x00},
+	{0x28, 0x00},
+	{0x29, 0x00},
+	{0x2a, 0x00},
+	{0x30, 0x50},
+	{0x31, 0x18},
+	{0x32, 0x32},
+	{0x33, 0x40},
+	{0x34, 0x50},
+	{0x35, 0x70},
+	{0x36, 0xa0},
+	{0x40, 0xa0},
+	{0x41, 0x40},
+	{0x42, 0xa0},
+	{0x43, 0x90},
+	{0x44, 0x90},
+	{0x45, 0x80},
+	{0x46, 0xb0},
+	{0x47, 0x55},
+	{0x48, 0xa0},
+	{0x49, 0x90},
+	{0x4a, 0x90},
+	{0x4b, 0x80},
+	{0x4c, 0xb0},
+	{0x4d, 0x40},
+	{0x4e, 0x90},
+	{0x4f, 0x60},
+	{0x50, 0xa0},
+	{0x51, 0x80},
+	{0x52, 0xb0},
+	{0x53, 0x40},
+	{0x54, 0x90},
+	{0x55, 0x60},
+	{0x56, 0xa0},
+	{0x57, 0x80},
+	{0x58, 0x90},
+	{0x59, 0x40},
+	{0x5a, 0xd0},
+	{0x5b, 0xd0},
+	{0x5c, 0xe0},
+	{0x5d, 0x80},
+	{0x5e, 0x88},
+	{0x5f, 0x40},
+	{0x60, 0xe0},
+	{0x61, 0xe0},
+	{0x62, 0xe0},
+	{0x63, 0x80},
+	{0x70, 0x15},
+	{0x71, 0x01},
+	{0x72, 0x18},
+	{0x73, 0x01},
+	{0x74, 0x25},
+	{0x75, 0x15},
+	{0x80, 0x20},
+	{0x81, 0x40},
+	{0x82, 0x65},
+	{0x85, 0x1a},
+	{0x88, 0x00},
+	{0x89, 0x00},
+	{0x90, 0x5d},
+	{0xD0, 0x0c},
+	{0xD1, 0x80},
+	{0xD2, 0x17},
+	{0xD3, 0x00},
+	{0xD4, 0x00},
+	{0xD5, 0x0f},
+	{0xD6, 0xff},
+	{0xD7, 0xff},
+	{0x3b, 0x06},
+	{0x3c, 0x06},
+	{0xc5, 0x00},
+	{0xc6, 0x00},
+	{0x03, 0x13},
+	{0x10, 0xcb},
+	{0x11, 0x7b},
+	{0x12, 0x07},
+	{0x14, 0x00},
+	{0x20, 0x15},
+	{0x21, 0x13},
+	{0x22, 0x33},
+	{0x23, 0x05},
+	{0x24, 0x09},
+	{0x25, 0x0a},
+	{0x26, 0x18},
+	{0x27, 0x30},
+	{0x29, 0x12},
+	{0x2a, 0x50},
+	{0x2b, 0x02},
+	{0x2c, 0x02},
+	{0x25, 0x06},
+	{0x2d, 0x0c},
+	{0x2e, 0x12},
+	{0x2f, 0x12},
+	{0x50, 0x10},
+	{0x51, 0x14},
+	{0x52, 0x12},
+	{0x53, 0x0c},
+	{0x54, 0x0f},
+	{0x55, 0x0c},
+	{0x56, 0x10},
+	{0x57, 0x13},
+	{0x58, 0x12},
+	{0x59, 0x0c},
+	{0x5a, 0x0f},
+	{0x5b, 0x0c},
+	{0x5c, 0x25},
+	{0x5d, 0x25},
+	{0x5e, 0x25},
+	{0x5f, 0x25},
+	{0x60, 0x25},
+	{0x61, 0x25},
+	{0x62, 0x25},
+	{0x63, 0x25},
+	{0x64, 0x25},
+	{0x65, 0x25},
+	{0x66, 0x25},
+	{0x67, 0x25},
+	{0x68, 0x07},
+	{0x69, 0x07},
+	{0x6a, 0x07},
+	{0x6b, 0x05},
+	{0x6c, 0x05},
+	{0x6d, 0x05},
+	{0x6e, 0x07},
+	{0x6f, 0x07},
+	{0x70, 0x07},
+	{0x71, 0x05},
+	{0x72, 0x05},
+	{0x73, 0x05},
+	{0x80, 0x01},
+	{0x81, 0x1f},
+	{0x82, 0x05},
+	{0x83, 0x31},
+	{0x90, 0x05},
+	{0x91, 0x05},
+	{0x92, 0x33},
+	{0x93, 0x30},
+	{0x94, 0x03},
+	{0x95, 0x14},
+	{0x97, 0x20},
+	{0x99, 0x20},
+	{0xa0, 0x01},
+	{0xa1, 0x02},
+	{0xa2, 0x01},
+	{0xa3, 0x02},
+	{0xa4, 0x05},
+	{0xa5, 0x05},
+	{0xa6, 0x07},
+	{0xa7, 0x08},
+	{0xa8, 0x07},
+	{0xa9, 0x08},
+	{0xaa, 0x07},
+	{0xab, 0x08},
+	{0xb0, 0x22},
+	{0xb1, 0x2a},
+	{0xb2, 0x28},
+	{0xb3, 0x22},
+	{0xb4, 0x2a},
+	{0xb5, 0x28},
+	{0xb6, 0x22},
+	{0xb7, 0x2a},
+	{0xb8, 0x28},
+	{0xb9, 0x22},
+	{0xba, 0x2a},
+	{0xbb, 0x28},
+	{0xbc, 0x25},
+	{0xbd, 0x2a},
+	{0xbe, 0x27},
+	{0xbf, 0x25},
+	{0xc0, 0x2a},
+	{0xc1, 0x27},
+	{0xc2, 0x1e},
+	{0xc3, 0x24},
+	{0xc4, 0x20},
+	{0xc5, 0x1e},
+	{0xc6, 0x24},
+	{0xc7, 0x20},
+	{0xc8, 0x18},
+	{0xc9, 0x20},
+	{0xca, 0x1e},
+	{0xcb, 0x18},
+	{0xcc, 0x20},
+	{0xcd, 0x1e},
+	{0xce, 0x18},
+	{0xcf, 0x20},
+	{0xd0, 0x1e},
+	{0xd1, 0x18},
+	{0xd2, 0x20},
+	{0xd3, 0x1e},
+	{0x03, 0x14},
+	{0x10, 0x11},
+	{0x14, 0x80},
+	{0x15, 0x80},
+	{0x16, 0x80},
+	{0x17, 0x80},
+	{0x18, 0x80},
+	{0x19, 0x80},
+	{0x20, 0x80},
+	{0x21, 0x80},
+	{0x22, 0x80},
+	{0x23, 0x80},
+	{0x24, 0x80},
+	{0x30, 0xc8},
+	{0x31, 0x2b},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x90},
+	{0x40, 0x32},
+	{0x50, 0x21},
+	{0x60, 0x19},
+	{0x70, 0x21},
+	{0x03, 0x15},
+	{0x10, 0x0f},
+	{0x14, 0x46},
+	{0x15, 0x36},
+	{0x16, 0x26},
+	{0x17, 0x2f},
+	{0x30, 0x8f},
+	{0x31, 0x59},
+	{0x32, 0x0a},
+	{0x33, 0x15},
+	{0x34, 0x5b},
+	{0x35, 0x06},
+	{0x36, 0x07},
+	{0x37, 0x40},
+	{0x38, 0x87},
+	{0x40, 0x94},
+	{0x41, 0x20},
+	{0x42, 0x89},
+	{0x43, 0x84},
+	{0x44, 0x03},
+	{0x45, 0x01},
+	{0x46, 0x88},
+	{0x47, 0x9c},
+	{0x48, 0x28},
+	{0x50, 0x02},
+	{0x51, 0x82},
+	{0x52, 0x00},
+	{0x53, 0x07},
+	{0x54, 0x11},
+	{0x55, 0x98},
+	{0x56, 0x00},
+	{0x57, 0x0b},
+	{0x58, 0x8b},
+	{0x80, 0x03},
+	{0x85, 0x40},
+	{0x87, 0x02},
+	{0x88, 0x00},
+	{0x89, 0x00},
+	{0x8a, 0x00},
+	{0x03, 0x16},
+	{0x10, 0x31},
+	{0x18, 0x5e},
+	{0x19, 0x5d},
+	{0x1a, 0x0e},
+	{0x1b, 0x01},
+	{0x1c, 0xdc},
+	{0x1d, 0xfe},
+	{0x30, 0x00},
+	{0x31, 0x0a},
+	{0x32, 0x1f},
+	{0x33, 0x33},
+	{0x34, 0x53},
+	{0x35, 0x6c},
+	{0x36, 0x81},
+	{0x37, 0x94},
+	{0x38, 0xa4},
+	{0x39, 0xb3},
+	{0x3a, 0xc0},
+	{0x3b, 0xcb},
+	{0x3c, 0xd5},
+	{0x3d, 0xde},
+	{0x3e, 0xe6},
+	{0x3f, 0xee},
+	{0x40, 0xf5},
+	{0x41, 0xfc},
+	{0x42, 0xff},
+	{0x50, 0x00},
+	{0x51, 0x08},
+	{0x52, 0x1e},
+	{0x53, 0x36},
+	{0x54, 0x5a},
+	{0x55, 0x75},
+	{0x56, 0x8d},
+	{0x57, 0xa1},
+	{0x58, 0xb2},
+	{0x59, 0xbe},
+	{0x5a, 0xc9},
+	{0x5b, 0xd2},
+	{0x5c, 0xdb},
+	{0x5d, 0xe3},
+	{0x5e, 0xeb},
+	{0x5f, 0xf0},
+	{0x60, 0xf5},
+	{0x61, 0xf7},
+	{0x62, 0xf8},
+	{0x70, 0x00},
+	{0x71, 0x08},
+	{0x72, 0x17},
+	{0x73, 0x2f},
+	{0x74, 0x53},
+	{0x75, 0x6c},
+	{0x76, 0x81},
+	{0x77, 0x94},
+	{0x78, 0xa4},
+	{0x79, 0xb3},
+	{0x7a, 0xc0},
+	{0x7b, 0xcb},
+	{0x7c, 0xd5},
+	{0x7d, 0xde},
+	{0x7e, 0xe6},
+	{0x7f, 0xee},
+	{0x80, 0xf4},
+	{0x81, 0xfa},
+	{0x82, 0xff},
+	{0x03, 0x17},
+	{0x10, 0xf7},
+	{0xC4, 0x66},
+	{0xC5, 0x55},
+	{0x03, 0x20},
+	{0x11, 0x1c},
+	{0x18, 0x30},
+	{0x1a, 0x08},
+	{0x20, 0x05},
+	{0x21, 0x30},
+	{0x22, 0x10},
+	{0x23, 0x00},
+	{0x24, 0x00},
+	{0x28, 0xe7},
+	{0x29, 0x0d},
+	{0x2a, 0xf0},
+	{0x2b, 0x34},
+	{0x30, 0x78},
+	{0x2c, 0xc2},
+	{0x2d, 0xff},
+	{0x2e, 0x33},
+	{0x30, 0x78},
+	{0x32, 0x03},
+	{0x33, 0x2e},
+	{0x34, 0x30},
+	{0x35, 0xd4},
+	{0x36, 0xfe},
+	{0x37, 0x32},
+	{0x38, 0x04},
+	{0x39, 0x22},
+	{0x3a, 0xde},
+	{0x3b, 0x22},
+	{0x3c, 0xde},
+	{0x50, 0x45},
+	{0x51, 0x88},
+	{0x56, 0x03},
+	{0x57, 0xf7},
+	{0x58, 0x14},
+	{0x59, 0x88},
+	{0x5a, 0x04},
+	{0x60, 0xaa},
+	{0x61, 0xaa},
+	{0x62, 0xaa},
+	{0x63, 0xaa},
+	{0x64, 0xaa},
+	{0x65, 0xaa},
+	{0x66, 0xab},
+	{0x67, 0xEa},
+	{0x68, 0xab},
+	{0x69, 0xEa},
+	{0x6a, 0xaa},
+	{0x6b, 0xaa},
+	{0x6c, 0xaa},
+	{0x6d, 0xaa},
+	{0x6e, 0xaa},
+	{0x6f, 0xaa},
+	{0x70, 0x76},
+	{0x71, 0x80},
+	{0x76, 0x43},
+	{0x77, 0x04},
+	{0x78, 0x23},
+	{0x79, 0x46},
+	{0x7a, 0x23},
+	{0x7b, 0x22},
+	{0x7d, 0x23},
+	{0x83, 0x01},
+	{0x84, 0x5f},
+	{0x85, 0x90},
+	{0x86, 0x01},
+	{0x87, 0x2c},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x8B, 0x75},
+	{0x8C, 0x30},
+	{0x8D, 0x61},
+	{0x8E, 0x44},
+	{0x9c, 0x08},
+	{0x9d, 0x34},
+	{0x9e, 0x01},
+	{0x9f, 0x2c},
+	{0xb0, 0x18},
+	{0xb1, 0x14},
+	{0xb2, 0x80},
+	{0xb3, 0x18},
+	{0xb4, 0x1a},
+	{0xb5, 0x44},
+	{0xb6, 0x2f},
+	{0xb7, 0x28},
+	{0xb8, 0x25},
+	{0xb9, 0x22},
+	{0xba, 0x21},
+	{0xbb, 0x20},
+	{0xbc, 0x32},
+	{0xbd, 0x30},
+	{0xc0, 0x10},
+	{0xc1, 0x2b},
+	{0xc2, 0x2b},
+	{0xc3, 0x2b},
+	{0xc4, 0x08},
+	{0xc8, 0x40},
+	{0xc9, 0x40},
+	{0x03, 0x22},
+	{0x10, 0xfd},
+	{0x11, 0x2e},
+	{0x19, 0x01},
+	{0x20, 0x10},
+	{0x21, 0x80},
+	{0x24, 0x01},
+	{0x30, 0x80},
+	{0x31, 0x80},
+	{0x38, 0x11},
+	{0x39, 0x34},
+	{0x40, 0xfa},
+	{0x41, 0x44},
+	{0x42, 0x43},
+	{0x43, 0xf6},
+	{0x44, 0x44},
+	{0x45, 0x33},
+	{0x46, 0x00},
+	{0x50, 0xb2},
+	{0x51, 0x81},
+	{0x52, 0x98},
+	{0x80, 0x38},
+	{0x81, 0x20},
+	{0x82, 0x38},
+	{0x83, 0x5e},
+	{0x84, 0x18},
+	{0x85, 0x58},
+	{0x86, 0x20},
+	{0x87, 0x49},
+	{0x88, 0x33},
+	{0x89, 0x37},
+	{0x8a, 0x2a},
+	{0x8b, 0x41},
+	{0x8c, 0x39},
+	{0x8d, 0x34},
+	{0x8e, 0x29},
+	{0x8f, 0x53},
+	{0x90, 0x52},
+	{0x91, 0x51},
+	{0x92, 0x4e},
+	{0x93, 0x46},
+	{0x94, 0x3d},
+	{0x95, 0x34},
+	{0x96, 0x2e},
+	{0x97, 0x29},
+	{0x98, 0x22},
+	{0x99, 0x1c},
+	{0x9a, 0x18},
+	{0x9b, 0x77},
+	{0x9c, 0x77},
+	{0x9d, 0x48},
+	{0x9e, 0x38},
+	{0x9f, 0x30},
+	{0xa0, 0x60},
+	{0xa1, 0x34},
+	{0xa2, 0x6f},
+	{0xa3, 0xff},
+	{0xa4, 0x14},
+	{0xa5, 0x2c},
+	{0xa6, 0xcf},
+	{0xad, 0x40},
+	{0xae, 0x4a},
+	{0xaf, 0x28},
+	{0xb0, 0x26},
+	{0xb1, 0x00},
+	{0xb4, 0xea},
+	{0xb8, 0xa0},
+	{0xb9, 0x00},
+	{0x03, 0x48},
+	{0x70, 0x03},
+	{0x71, 0x30},
+	{0x72, 0x81},
+	{0x73, 0x10},
+	{0x70, 0x85},
+	{0x03, 0x48},
+	{0x03, 0x48},
+	{0x03, 0x48},
+	{0x03, 0x48},
+	{0x70, 0x95},
+	{0x10, 0x1c},
+	{0x11, 0x10},
+	{0x12, 0x00},
+	{0x14, 0x00},
+	{0x16, 0x04},
+	{0x18, 0x80},
+	{0x19, 0x00},
+	{0x1a, 0xa0},
+	{0x1b, 0x0d},
+	{0x1c, 0x01},
+	{0x1d, 0x0a},
+	{0x1e, 0x07},
+	{0x1f, 0x0b},
+	{0x23, 0x01},
+	{0x24, 0x1e},
+	{0x25, 0x00},
+	{0x26, 0x00},
+	{0x27, 0x08},
+	{0x28, 0x00},
+	{0x30, 0x06},
+	{0x31, 0x40},
+	{0x32, 0x13},
+	{0x33, 0x0c},
+	{0x34, 0x04},
+	{0x35, 0x06},
+	{0x36, 0x01},
+	{0x37, 0x06},
+	{0x39, 0x4f},
+	{0x03, 0x20},
+	{0x10, 0x9c},
+	{0x03, 0x22},
+	{0x10, 0xe9},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x03, 0x00},
+	{0x0e, 0x03},
+	{0x0e, 0x73},
+	{0x03, 0x00},
+	{0x01, 0xf0},
+};
+
+static struct v4l2_subdev_info hi256_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt	= 1,
+		.order	= 0,
+	},
+};
+
+static struct msm_camera_i2c_reg_conf hi256_svga_settings[] = {
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x03, 0x22},
+	{0x10, 0x69},
+	{0x03, 0x00},
+	{0x10, 0x13},
+	{0x12, 0x00},
+	{0x20, 0x00},
+	{0x21, 0x04},
+	{0x22, 0x00},
+	{0x23, 0x07},
+	{0x40, 0x01},
+	{0x41, 0x78},
+	{0x42, 0x00},
+	{0x43, 0x14},
+	{0x03, 0x10},
+	{0x3f, 0x02},
+	{0x03, 0x12},
+	{0x20, 0x0f},
+	{0x21, 0x0f},
+	{0x90, 0x5d},
+	{0x03, 0x13},
+	{0x80, 0x00},
+	{0x03, 0x48},
+	{0x72, 0x81},
+	{0x30, 0x06},
+	{0x31, 0x40},
+	{0x03, 0x20},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x03, 0x20},
+	{0x10, 0x9c},
+	{0x03, 0x22},
+	{0x10, 0xe9},
+};
+
+
+static const struct i2c_device_id hi256_i2c_id[] = {
+	{HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl},
+	{ }
+};
+
+static int32_t msm_hi256_i2c_probe(struct i2c_client *client,
+	   const struct i2c_device_id *id)
+{
+	   return msm_sensor_i2c_probe(client, id, &hi256_s_ctrl);
+}
+
+static struct i2c_driver hi256_i2c_driver = {
+	.id_table = hi256_i2c_id,
+	.probe  = msm_hi256_i2c_probe,
+	.driver = {
+		.name = HI256_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client hi256_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static const struct of_device_id hi256_dt_match[] = {
+	{.compatible = "shinetech,hi256", .data = &hi256_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, hi256_dt_match);
+
+static struct platform_driver hi256_platform_driver = {
+	.driver = {
+		.name = "shinetech,hi256",
+		.owner = THIS_MODULE,
+		.of_match_table = hi256_dt_match,
+	},
+};
+
+static void hi256_i2c_write_table(struct msm_sensor_ctrl_t *s_ctrl,
+		struct msm_camera_i2c_reg_conf *table,
+		int num)
+{
+	int i = 0;
+	int rc = 0;
+	for (i = 0; i < num; ++i) {
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write(
+			s_ctrl->sensor_i2c_client, table->reg_addr,
+			table->reg_data,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		if (rc < 0) {
+			msleep(100);
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write(
+				s_ctrl->sensor_i2c_client, table->reg_addr,
+				table->reg_data,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		table++;
+	}
+
+}
+
+static int32_t hi256_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc;
+	const struct of_device_id *match;
+	match = of_match_device(hi256_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init hi256_init_module(void)
+{
+	int32_t rc;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&hi256_platform_driver,
+		hi256_platform_probe);
+	if (!rc)
+		return rc;
+	return i2c_add_driver(&hi256_i2c_driver);
+}
+
+static void __exit hi256_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (hi256_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&hi256_s_ctrl);
+		platform_driver_unregister(&hi256_platform_driver);
+	} else
+		i2c_del_driver(&hi256_i2c_driver);
+	return;
+}
+
+static int32_t hi256_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+		s_ctrl->sensor_i2c_client,
+		s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
+		&chipid, MSM_CAMERA_I2C_BYTE_DATA);
+	if (rc < 0) {
+		pr_err("%s: %s: hi256 read id failed\n", __func__,
+			s_ctrl->sensordata->sensor_name);
+		return rc;
+	}
+
+	CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
+		s_ctrl->sensordata->slave_info->sensor_id);
+	if (chipid != s_ctrl->sensordata->slave_info->sensor_id) {
+		pr_err("msm_sensor_match_id chip id doesnot match\n");
+		return -ENODEV;
+	}
+	return rc;
+}
+
+int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
+	void __user *argp)
+{
+	struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
+	long rc = 0;
+	int32_t i = 0;
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+		s_ctrl->sensordata->sensor_name, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CFG_GET_SENSOR_INFO:
+		memcpy(cdata->cfg.sensor_info.sensor_name,
+			s_ctrl->sensordata->sensor_name,
+			sizeof(cdata->cfg.sensor_info.sensor_name));
+		cdata->cfg.sensor_info.session_id =
+			s_ctrl->sensordata->sensor_info->session_id;
+		for (i = 0; i < SUB_MODULE_MAX; i++)
+			cdata->cfg.sensor_info.subdev_id[i] =
+				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.sensor_name);
+		CDBG("%s:%d session id %d\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.session_id);
+		for (i = 0; i < SUB_MODULE_MAX; i++)
+			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
+				cdata->cfg.sensor_info.subdev_id[i]);
+		break;
+	case CFG_SET_INIT_SETTING:
+		CDBG("init setting");
+		hi256_i2c_write_table(s_ctrl,
+				&hi256_recommend_settings[0],
+				ARRAY_SIZE(hi256_recommend_settings));
+		CDBG("init setting X");
+		break;
+	case CFG_SET_RESOLUTION: {
+		int val = 0;
+		if (copy_from_user(&val,
+			(void *)cdata->cfg.setting, sizeof(int))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		if (val == 0)
+			hi256_i2c_write_table(s_ctrl, &hi256_uxga_settings[0],
+				ARRAY_SIZE(hi256_uxga_settings));
+		else if (val == 1)
+			hi256_i2c_write_table(s_ctrl, &hi256_svga_settings[0],
+				ARRAY_SIZE(hi256_svga_settings));
+		break;
+	}
+	case CFG_SET_STOP_STREAM:
+		hi256_i2c_write_table(s_ctrl,
+			&hi256_stop_settings[0],
+			ARRAY_SIZE(hi256_stop_settings));
+		break;
+	case CFG_SET_START_STREAM:
+		hi256_i2c_write_table(s_ctrl,
+			&hi256_start_settings[0],
+			ARRAY_SIZE(hi256_start_settings));
+		break;
+	case CFG_GET_SENSOR_INIT_PARAMS:
+		cdata->cfg.sensor_init_params =
+			*s_ctrl->sensordata->sensor_init_params;
+		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
+			__LINE__,
+			cdata->cfg.sensor_init_params.modes_supported,
+			cdata->cfg.sensor_init_params.position,
+			cdata->cfg.sensor_init_params.sensor_mount_angle);
+		break;
+	case CFG_SET_SLAVE_INFO: {
+		struct msm_camera_sensor_slave_info sensor_slave_info;
+		struct msm_sensor_power_setting_array *power_setting_array;
+		int slave_index = 0;
+		if (copy_from_user(&sensor_slave_info,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_sensor_slave_info))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		/* Update sensor slave address */
+		if (sensor_slave_info.slave_addr) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				sensor_slave_info.slave_addr >> 1;
+		}
+
+		/* Update sensor address type */
+		s_ctrl->sensor_i2c_client->addr_type =
+			sensor_slave_info.addr_type;
+
+		/* Update power up / down sequence */
+		s_ctrl->power_setting_array =
+			sensor_slave_info.power_setting_array;
+		power_setting_array = &s_ctrl->power_setting_array;
+		power_setting_array->power_setting = kzalloc(
+			power_setting_array->size *
+			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
+		if (!power_setting_array->power_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(power_setting_array->power_setting,
+			(void *)
+			sensor_slave_info.power_setting_array.power_setting,
+			power_setting_array->size *
+			sizeof(struct msm_sensor_power_setting))) {
+			kfree(power_setting_array->power_setting);
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		s_ctrl->free_power_setting = true;
+		CDBG("%s sensor id %x\n", __func__,
+			sensor_slave_info.slave_addr);
+		CDBG("%s sensor addr type %d\n", __func__,
+			sensor_slave_info.addr_type);
+		CDBG("%s sensor reg %x\n", __func__,
+			sensor_slave_info.sensor_id_info.sensor_id_reg_addr);
+		CDBG("%s sensor id %x\n", __func__,
+			sensor_slave_info.sensor_id_info.sensor_id);
+		for (slave_index = 0; slave_index <
+			power_setting_array->size; slave_index++) {
+			CDBG("%s i %d power setting %d %d %ld %d\n", __func__,
+			slave_index,
+			power_setting_array->power_setting[slave_index].
+			seq_type,
+			power_setting_array->power_setting[slave_index].
+			seq_val,
+			power_setting_array->power_setting[slave_index].
+			config_val,
+			power_setting_array->power_setting[slave_index].
+			delay);
+		}
+		kfree(power_setting_array->power_setting);
+		break;
+	}
+	case CFG_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+		if (copy_from_user(&conf_array,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting, (void *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &conf_array);
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_WRITE_I2C_SEQ_ARRAY: {
+		struct msm_camera_i2c_seq_reg_setting conf_array;
+		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+
+		if (copy_from_user(&conf_array,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_seq_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_seq_reg_array)),
+			GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting, (void *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_seq_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write_seq_table(s_ctrl->sensor_i2c_client,
+			&conf_array);
+		kfree(reg_setting);
+		break;
+	}
+
+	case CFG_POWER_UP:
+		if (s_ctrl->func_tbl->sensor_power_up)
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_POWER_DOWN:
+		if (s_ctrl->func_tbl->sensor_power_down)
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_STOP_STREAM_SETTING: {
+		struct msm_camera_i2c_reg_setting *stop_setting =
+			&s_ctrl->stop_setting;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+		if (copy_from_user(stop_setting, (void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = stop_setting->reg_setting;
+		stop_setting->reg_setting = kzalloc(stop_setting->size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!stop_setting->reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(stop_setting->reg_setting,
+			(void *)reg_setting, stop_setting->size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(stop_setting->reg_setting);
+			stop_setting->reg_setting = NULL;
+			stop_setting->size = 0;
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+	return rc;
+}
+
+static struct msm_sensor_fn_t hi256_sensor_func_tbl = {
+	.sensor_config = hi256_sensor_config,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+	.sensor_match_id = hi256_sensor_match_id,
+};
+
+static struct msm_sensor_ctrl_t hi256_s_ctrl = {
+	.sensor_i2c_client = &hi256_sensor_i2c_client,
+	.power_setting_array.power_setting = hi256_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(hi256_power_setting),
+	.msm_sensor_mutex = &hi256_mut,
+	.sensor_v4l2_subdev_info = hi256_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(hi256_subdev_info),
+	.func_tbl = &hi256_sensor_func_tbl,
+};
+
+module_init(hi256_init_module);
+module_exit(hi256_exit_module);
+MODULE_DESCRIPTION("Hi256 2MP YUV sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 0678fc2..bc3b93d 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -400,9 +400,11 @@
 static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
 {
 	struct q6_hfi_device *device = priv;
+	struct hfi_msg_event_notify_packet pkt = {0};
+	void *payload = NULL;
 	int rc = 0;
 
-	if (!data || !device || !data->payload_size) {
+	if (!data || !device) {
 		dprintk(VIDC_ERR, "%s - Invalid arguments", __func__);
 		return -EINVAL;
 	}
@@ -410,7 +412,23 @@
 	dprintk(VIDC_DBG, "%s opcode = %u payload size = %u", __func__,
 				data->opcode, data->payload_size);
 
-	rc = q6_hfi_iface_eventq_write(device, data->payload);
+	if (data->opcode == RESET_EVENTS) {
+		dprintk(VIDC_ERR, "%s Received subsystem reset event: %d",
+				__func__, data->reset_event);
+		pkt.packet_type = HFI_MSG_EVENT_NOTIFY;
+		pkt.size = sizeof(pkt);
+		pkt.event_id = HFI_EVENT_SYS_ERROR;
+		pkt.event_data1 = data->opcode;
+		pkt.event_data2 = data->reset_event;
+		payload = &pkt;
+	} else if (data->payload_size > 0) {
+		payload = data->payload;
+	} else {
+		dprintk(VIDC_ERR, "%s - Invalid payload size", __func__);
+		return -EINVAL;
+	}
+
+	rc = q6_hfi_iface_eventq_write(device, payload);
 	if (rc) {
 		dprintk(VIDC_ERR, "%s failed to write to event queue",
 				__func__);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c60537a..6ea2346 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -41,6 +41,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/socinfo.h>
 #include <mach/qseecomi.h>
+#include <asm/cacheflush.h>
 #include "qseecom_legacy.h"
 #include "qseecom_kernel.h"
 
@@ -515,7 +516,10 @@
 		qseecom.send_resp_flag = 0;
 		send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
 		send_data_rsp.listener_id  = lstnr ;
-
+		if (ptr_svc)
+			msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
+					ptr_svc->sb_virt, ptr_svc->sb_length,
+						ION_IOC_CLEAN_INV_CACHES);
 		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
 					(const void *)&send_data_rsp,
 					sizeof(send_data_rsp), resp,
@@ -641,6 +645,8 @@
 		load_req.mdt_len = load_img_req.mdt_len;
 		load_req.img_len = load_img_req.img_len;
 		load_req.phy_addr = pa;
+		msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+					ION_IOC_CLEAN_INV_CACHES);
 
 		/*  SCM_CALL  to load the app and get the app_id back */
 		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
@@ -880,10 +886,15 @@
 		pr_err("Unsupported cmd_id %d\n", req.cmd_id);
 		return -EINVAL;
 	}
-
+	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+				data->client.sb_virt, data->client.sb_length,
+				ION_IOC_CLEAN_INV_CACHES);
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
 					sizeof(send_svc_ireq),
 					&resp, sizeof(resp));
+	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+				data->client.sb_virt, data->client.sb_length,
+				ION_IOC_INV_CACHES);
 	if (ret) {
 		pr_err("qseecom_scm_call failed with err: %d\n", ret);
 		return ret;
@@ -952,6 +963,11 @@
 					(uint32_t)req->resp_buf));
 	send_data_req.rsp_len = req->resp_len;
 
+	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+					data->client.sb_virt,
+					(req->cmd_req_len + req->resp_len),
+					ION_IOC_CLEAN_INV_CACHES);
+
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
 					sizeof(send_data_req),
 					&resp, sizeof(resp));
@@ -974,6 +990,9 @@
 			ret = -EINVAL;
 		}
 	}
+	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+				data->client.sb_virt, data->client.sb_length,
+				ION_IOC_INV_CACHES);
 	return ret;
 }
 
@@ -1005,6 +1024,8 @@
 	char *field;
 	int ret = 0;
 	int i = 0;
+	uint32_t len = 0;
+	struct scatterlist *sg;
 
 	for (i = 0; i < MAX_ION_FD; i++) {
 		struct sg_table *sg_ptr = NULL;
@@ -1035,6 +1056,7 @@
 					sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
 				goto err;
 			}
+			sg = sg_ptr->sgl;
 			if (sg_ptr->nents == 1) {
 				uint32_t *update;
 				update = (uint32_t *) field;
@@ -1043,12 +1065,11 @@
 				else
 					*update = (uint32_t)sg_dma_address(
 								sg_ptr->sgl);
+				len += (uint32_t)sg->length;
 			} else {
 				struct qseecom_sg_entry *update;
-				struct scatterlist *sg;
 				int j = 0;
 				update = (struct qseecom_sg_entry *) field;
-				sg = sg_ptr->sgl;
 				for (j = 0; j < sg_ptr->nents; j++) {
 					if (cleanup) {
 						update->phys_addr = 0;
@@ -1058,10 +1079,19 @@
 							sg_dma_address(sg);
 						update->len = sg->length;
 					}
+					len += sg->length;
 					update++;
 					sg = sg_next(sg);
 				}
 			}
+			if (cleanup)
+				msm_ion_do_cache_op(qseecom.ion_clnt,
+						ihandle, NULL, len,
+						ION_IOC_INV_CACHES);
+			else
+				msm_ion_do_cache_op(qseecom.ion_clnt,
+						ihandle, NULL, len,
+						ION_IOC_CLEAN_INV_CACHES);
 			/* Deallocate the handle */
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
@@ -1288,6 +1318,7 @@
 		return -EIO;
 	}
 
+	__cpuc_flush_dcache_area((void *)img_data, fw_size);
 	/* SCM_CALL to load the image */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,	&load_req,
 			sizeof(struct qseecom_load_app_ireq),
@@ -1354,6 +1385,7 @@
 		return -EIO;
 	}
 
+	__cpuc_flush_dcache_area((void *)img_data, fw_size);
 	/* SCM_CALL to load the image */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
 				sizeof(struct qseecom_load_lib_image_ireq),
@@ -1985,7 +2017,8 @@
 		ret = -EIO;
 		goto qseecom_load_external_elf_set_cpu_err;
 	}
-
+	msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+				ION_IOC_CLEAN_INV_CACHES);
 	/*  SCM_CALL to load the external elf */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
 			sizeof(struct qseecom_load_app_ireq),
@@ -2498,7 +2531,7 @@
 	ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
 		       (void *) &req, sizeof(req), NULL, 0);
 	if (ret) {
-		pr_err("scm_call failed");
+		pr_err("qseecom_scm_call failed");
 		return ret;
 	}
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index f01ddab..d975543 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3130,11 +3130,11 @@
 
 	/* Silent the block layer */
 	if (md) {
-		rc = mmc_queue_suspend(&md->queue);
+		rc = mmc_queue_suspend(&md->queue, 1);
 		if (rc)
 			goto suspend_error;
 		list_for_each_entry(part_md, &md->part, part) {
-			rc = mmc_queue_suspend(&part_md->queue);
+			rc = mmc_queue_suspend(&part_md->queue, 1);
 			if (rc)
 				goto suspend_error;
 		}
@@ -3161,11 +3161,11 @@
 	int rc = 0;
 
 	if (md) {
-		rc = mmc_queue_suspend(&md->queue);
+		rc = mmc_queue_suspend(&md->queue, 0);
 		if (rc)
 			goto out;
 		list_for_each_entry(part_md, &md->part, part) {
-			rc = mmc_queue_suspend(&part_md->queue);
+			rc = mmc_queue_suspend(&part_md->queue, 0);
 			if (rc)
 				goto out_resume;
 		}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 0e024dd..507cd5b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -438,12 +438,13 @@
 /**
  * mmc_queue_suspend - suspend a MMC request queue
  * @mq: MMC queue to suspend
+ * @wait: Wait till MMC request queue is empty
  *
  * Stop the block request queue, and wait for our thread to
  * complete any outstanding requests.  This ensures that we
  * won't suspend while a request is being processed.
  */
-int mmc_queue_suspend(struct mmc_queue *mq)
+int mmc_queue_suspend(struct mmc_queue *mq, int wait)
 {
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
@@ -457,7 +458,7 @@
 		spin_unlock_irqrestore(q->queue_lock, flags);
 
 		rc = down_trylock(&mq->thread_sem);
-		if (rc) {
+		if (rc && !wait) {
 			/*
 			 * Failed to take the lock so better to abort the
 			 * suspend because mmcqd thread is processing requests.
@@ -467,6 +468,9 @@
 			blk_start_queue(q);
 			spin_unlock_irqrestore(q->queue_lock, flags);
 			rc = -EBUSY;
+		} else if (rc && wait) {
+			down(&mq->thread_sem);
+			rc = 0;
 		}
 	}
 	return rc;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 9280d1b..d1fe01c 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -60,7 +60,7 @@
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
 			  const char *);
 extern void mmc_cleanup_queue(struct mmc_queue *);
-extern int mmc_queue_suspend(struct mmc_queue *);
+extern int mmc_queue_suspend(struct mmc_queue *, int);
 extern void mmc_queue_resume(struct mmc_queue *);
 
 extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 5af95927..3039b0d 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -39,3 +39,12 @@
 	  into the kernel or say M to compile it as module.
 
 endmenu
+
+config NFC_QNCI
+	bool "Qualcomm NCI based NFC Controller Driver for qca199x"
+	depends on I2C
+	select CRC_CCITT
+	help
+	  This enables the NFC driver for QCA199x based devices.
+	  This is for i2c connected version. NCI protocol logic
+	  resides in the usermode and it has no other NFC dependencies.
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index ab99e85..35a71e8 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -5,5 +5,6 @@
 obj-$(CONFIG_PN544_NFC)		+= pn544.o
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
+obj-$(CONFIG_NFC_QNCI)		+= nfc-nci.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
new file mode 100644
index 0000000..9e9a4ea
--- /dev/null
+++ b/drivers/nfc/nfc-nci.c
@@ -0,0 +1,764 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include "nfc-nci.h"
+
+
+struct qca199x_platform_data {
+	unsigned int irq_gpio;
+	unsigned int dis_gpio;
+	unsigned int ven_gpio;
+	unsigned int reg;
+};
+
+static struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,nfc-nci"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_match_table);
+
+#define MAX_BUFFER_SIZE		(780)
+/* Read data */
+#define PACKET_HEADER_SIZE_NCI	(4)
+#define PACKET_TYPE_NCI		(16)
+#define MAX_PACKET_SIZE		(PACKET_HEADER_SIZE_NCI + 255)
+#define MAX_QCA_REG		(116)
+
+static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+
+struct qca199x_dev {
+	wait_queue_head_t read_wq;
+	struct mutex read_mutex;
+	struct i2c_client *client;
+	struct miscdevice qca199x_device;
+	unsigned int irq_gpio;
+	unsigned int dis_gpio;
+	unsigned int ven_gpio;
+	bool irq_enabled;
+	spinlock_t irq_enabled_lock;
+	unsigned int count_irq;
+};
+
+/*
+ * To allow filtering of nfc logging from user. This is set via
+ * IOCTL NFC_KERNEL_LOGGING_MODE.
+ */
+static int logging_level;
+
+static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
+{
+	qca199x_dev->count_irq = 0;
+}
+
+static void qca199x_disable_irq(struct qca199x_dev *qca199x_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+	if (qca199x_dev->irq_enabled) {
+		disable_irq_nosync(qca199x_dev->client->irq);
+		qca199x_dev->irq_enabled = false;
+	}
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+}
+
+static void qca199x_enable_irq(struct qca199x_dev *qca199x_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+	if (!qca199x_dev->irq_enabled) {
+		qca199x_dev->irq_enabled = true;
+		enable_irq(qca199x_dev->client->irq);
+	}
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+}
+
+static irqreturn_t qca199x_dev_irq_handler(int irq, void *dev_id)
+{
+	struct qca199x_dev *qca199x_dev = dev_id;
+	unsigned long flags;
+
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+	qca199x_dev->count_irq++;
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+	wake_up(&qca199x_dev->read_wq);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int nfc_poll(struct file *filp, poll_table *wait)
+{
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+
+	poll_wait(filp, &qca199x_dev->read_wq, wait);
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+	if (qca199x_dev->count_irq > 0) {
+		qca199x_dev->count_irq--;
+		mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+
+
+	return mask;
+}
+
+static ssize_t nfc_read(struct file *filp, char __user *buf,
+					size_t count, loff_t *offset)
+{
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	unsigned char tmp[MAX_BUFFER_SIZE];
+	unsigned char len[PAYLOAD_HEADER_LENGTH];
+	int total, length, ret;
+
+	total = 0;
+	length = 0;
+	if (count > MAX_BUFFER_SIZE)
+		count = MAX_BUFFER_SIZE;
+
+	mutex_lock(&qca199x_dev->read_mutex);
+	/* Read the header */
+	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
+	if (ret != PAYLOAD_HEADER_LENGTH)
+		goto err;
+	length = len[PAYLOAD_HEADER_LENGTH - 1];
+
+	/** make sure full packet fits in the buffer **/
+	if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
+		/* Read the packet */
+		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
+			PAYLOAD_HEADER_LENGTH));
+		if (ret < 0)
+			goto err;
+		total = (length + PAYLOAD_HEADER_LENGTH);
+	}
+	mutex_unlock(&qca199x_dev->read_mutex);
+	if (total > 0) {
+		if ((total > count) || copy_to_user(buf, tmp, total)) {
+			dev_err(&qca199x_dev->client->dev,
+				"failed to copy to user space, total = %d\n",
+					total);
+			total = -EFAULT;
+		}
+	}
+err:
+	if (ret < 0)
+		mutex_unlock(&qca199x_dev->read_mutex);
+
+	return total;
+}
+
+static ssize_t nfc_write(struct file *filp, const char __user *buf,
+				size_t count, loff_t *offset)
+{
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	char tmp[MAX_BUFFER_SIZE];
+	int ret;
+
+	if (count > MAX_BUFFER_SIZE) {
+		dev_err(&qca199x_dev->client->dev, "out of memory\n");
+		return -ENOMEM;
+	}
+	if (copy_from_user(tmp, buf, count)) {
+		dev_err(&qca199x_dev->client->dev,
+			"nfc-nci write: failed to copy from user space\n");
+		return -EFAULT;
+	}
+	mutex_lock(&qca199x_dev->read_mutex);
+	ret = i2c_master_send(qca199x_dev->client, tmp, count);
+	if (ret != count) {
+		dev_err(&qca199x_dev->client->dev,
+			"NFC: failed to write %d\n", ret);
+		ret = -EIO;
+	}
+	mutex_unlock(&qca199x_dev->read_mutex);
+
+	return ret;
+}
+
+static int nfc_open(struct inode *inode, struct file *filp)
+{
+	int ret = 0;
+
+	struct qca199x_dev *qca199x_dev = container_of(filp->private_data,
+							struct qca199x_dev,
+							qca199x_device);
+
+	filp->private_data = qca199x_dev;
+	qca199x_init_stat(qca199x_dev);
+	qca199x_enable_irq(qca199x_dev);
+	dev_dbg(&qca199x_dev->client->dev,
+			"%d,%d\n", imajor(inode), iminor(inode));
+	return ret;
+}
+
+/*
+ * Wake/Sleep Mode
+ */
+int nfcc_wake(int level, struct nfc_info *info)
+{
+	int r = 0;
+	unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
+	/* Change slave address to 0xE */
+	unsigned char raw_nci_wake[]  = {0x10, 0x0F};
+	unsigned short	slave_addr	=	0xE;
+	unsigned short	curr_addr;
+
+	struct i2c_client *client = info->i2c_dev;
+
+	dev_dbg(&client->dev, "nfcc_wake: %s: info: %p\n", __func__, info);
+
+	if (level == NFCC_SLEEP) {
+		r = nfc_i2c_write(client, &raw_nci_sleep[0],
+						sizeof(raw_nci_sleep));
+
+		if (r != sizeof(raw_nci_sleep))
+			return -EMSGSIZE;
+		info->state = NFCC_STATE_NORMAL_SLEEP;
+	} else {
+		curr_addr = client->addr;
+		client->addr = slave_addr;
+		r = nfc_i2c_write(client, &raw_nci_wake[0],
+						sizeof(raw_nci_wake));
+		/* Restore original NFCC slave I2C address */
+		client->addr = curr_addr;
+
+		if (r != sizeof(raw_nci_sleep))
+			return -EMSGSIZE;
+
+		info->state = NFCC_STATE_NORMAL_WAKE;
+	}
+	msleep(20);
+	return r;
+}
+
+/*
+ * Inside nfc_ioctl_power_states
+ *
+ * @brief   ioctl functions
+ *
+ *
+ * Device control
+ * remove control via ioctl
+ * (arg = 0): NFC_DISABLE   GPIO = 0
+ * (arg = 1): NFC_DISABLE   GPIO = 1
+ *  NOT USED   (arg = 2): FW_DL GPIO = 0
+ *  NOT USED   (arg = 3): FW_DL GPIO = 1
+ * (arg = 4): NFCC_WAKE  = 1
+ * (arg = 5): NFCC_WAKE  = 0
+ *
+ *
+ */
+int nfc_ioctl_power_states(struct file *filp, unsigned int cmd,
+							unsigned long arg)
+{
+	int r = 0;
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	struct nfc_info *info = container_of(filp->private_data,
+					       struct nfc_info, miscdev);
+
+	struct i2c_client *client = info->i2c_dev;
+
+	r = gpio_request(qca199x_dev->dis_gpio, "nfc_reset_gpio");
+	if (r) {
+		dev_err(&client->dev, "unable to request gpio [%d]\n",
+				qca199x_dev->dis_gpio);
+			goto err_req;
+	}
+	gpio_set_value(qca199x_dev->dis_gpio, 0);
+	r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+	if (r) {
+		dev_err(&client->dev, "unable to set direction for gpio [%d]\n",
+				qca199x_dev->irq_gpio);
+			goto err_req;
+	}
+
+	if (arg == 0) {
+		gpio_set_value(qca199x_dev->dis_gpio, 0);
+		msleep(20);
+	} else if (arg == 1) {
+		gpio_set_value(qca199x_dev->dis_gpio, 1);
+		msleep(20);
+	} else if (arg == 2) {
+		msleep(20);
+	} else if (arg == 3) {
+		msleep(20);
+	} else if (arg == 4) {
+		nfcc_wake(NFCC_WAKE, info);
+		msleep(20);
+	} else if (arg == 5) {
+		nfcc_wake(NFCC_SLEEP, info);
+		msleep(20);
+	} else {
+		r = -ENOIOCTLCMD;
+	}
+
+err_req:
+	return r;
+}
+
+/*
+ * Inside nfc_ioctl_kernel_logging
+ *
+ * @brief   nfc_ioctl_kernel_logging
+ *
+ * (arg = 0) ; NO_LOGGING
+ * (arg = 1) ; COMMS_LOGGING - BASIC LOGGING - Mainly just comms over I2C
+ * (arg = 2) ; FULL_LOGGING - ENABLE ALL  - DBG messages for handlers etc.
+ *           ; ! Be aware as amount of logging could impact behaviour !
+ *
+ *
+ */
+int nfc_ioctl_kernel_logging(unsigned long arg,  struct file *filp)
+{
+	int retval = 0;
+	struct qca199x_dev *qca199x_dev = container_of(filp->private_data,
+							   struct qca199x_dev,
+							   qca199x_device);
+	if (arg == 0) {
+		dev_dbg(&qca199x_dev->client->dev,
+		"nfc_ioctl_kernel_logging : level = NO_LOGGING\n");
+		logging_level = 0;
+	} else if (arg == 1) {
+		dev_dbg(&qca199x_dev->client->dev,
+		"nfc_ioctl_kernel_logging: level = COMMS_LOGGING only\n");
+		logging_level = 1;
+	} else if (arg == 2) {
+		dev_dbg(&qca199x_dev->client->dev,
+		"nfc_ioctl_kernel_logging: level = FULL_LOGGING\n");
+		logging_level = 2;
+	}
+	return retval;
+}
+
+static long nfc_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
+{
+	int r = 0;
+
+	switch (cmd) {
+
+	case NFC_SET_PWR:
+		nfc_ioctl_power_states(pfile, cmd, arg);
+		break;
+	case NFCC_MODE:
+		break;
+	case NFC_KERNEL_LOGGING_MODE:
+		nfc_ioctl_kernel_logging(arg, pfile);
+		break;
+	case SET_RX_BLOCK:
+		break;
+	case SET_EMULATOR_TEST_POINT:
+		break;
+	default:
+		r = -ENOIOCTLCMD;
+	}
+	return r;
+}
+
+static const struct file_operations nfc_dev_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.poll  = nfc_poll,
+	.read  = nfc_read,
+	.write = nfc_write,
+	.open = nfc_open,
+	.unlocked_ioctl = nfc_ioctl
+};
+
+void dumpqca1990(struct i2c_client *client)
+{
+	int r = 0;
+	int i = 0;
+	unsigned char raw_reg_rd = {0x0};
+	unsigned short temp_addr;
+
+	temp_addr = client->addr;
+	client->addr = 0x0E;
+
+	for (i = 0; i < MAX_QCA_REG; i++) {
+		raw_reg_rd = i;
+		if (((i >= 0x0) && (i < 0x4)) || ((i > 0x7) && (i < 0xA)) ||
+		((i > 0xF) && (i < 0x12)) || ((i > 0x39) && (i < 0x4d)) ||
+		((i > 0x69) && (i < 0x74)) || (i == 0x18) || (i == 0x30) ||
+		(i == 0x58)) {
+			r = nfc_i2c_write(client, &raw_reg_rd, 1);
+			msleep(20);
+			r = i2c_master_recv(client, &raw_reg_rd, 1);
+		}
+	}
+	client->addr = temp_addr;
+}
+
+static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+	int r;
+
+	r = i2c_master_send(client, buf, len);
+	dev_dbg(&client->dev, "send: %d\n", r);
+	if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+		usleep_range(6000, 10000);
+		r = i2c_master_send(client, buf, len);
+		dev_dbg(&client->dev, "send2: %d\n", r);
+	}
+	if (r != len)
+		return -EREMOTEIO;
+
+	return r;
+}
+
+int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+{
+	int r = 0;
+	unsigned char raw_1p8_CONTROL_011[]	= {0x11, XTAL_CLOCK};
+	unsigned char raw_1P8_CONTROL_010[]	= {0x10, PWR_EN};
+	unsigned char raw_1P8_X0_0B0[]		= {0xB0, (FREQ_SEL)};
+	unsigned char raw_slave1[]		= {0x09, NCI_I2C_SLAVE};
+	unsigned char raw_slave2[]		= {0x8, 0x10};
+	unsigned char raw_s73[]			= {0x73, 0x02};
+	unsigned char raw_slave1_rd		= {0x0};
+	unsigned char raw_1P8_PAD_CFG_CLK_REQ[]	= {0xA5, 0x1};
+	unsigned char buf[4];
+
+	/* Set I2C address to enable configuration of QCA1990 */
+	client->addr = curr_addr;
+	RAW(s73, 0x02);
+
+	r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+	usleep(1000);
+	RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+	r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+						sizeof(raw_1p8_CONTROL_011));
+	usleep(1000);
+	RAW(1P8_CONTROL_010, (0x8));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+					sizeof(raw_1P8_CONTROL_010));
+
+	usleep(10000);  /* 10ms wait */
+	RAW(1P8_CONTROL_010, (0xC));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+					sizeof(raw_1P8_CONTROL_010));
+	usleep(100);  /* 100uS wait */
+	RAW(1P8_X0_0B0, (FREQ_SEL_19));
+	r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0));
+	usleep(1000);
+
+	/* PWR_EN = 1 */
+	RAW(1P8_CONTROL_010, (0xd));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+						sizeof(raw_1P8_CONTROL_010));
+	usleep(20000);  /* 20ms wait */
+	/* LS_EN = 1 */
+	RAW(1P8_CONTROL_010, 0xF);
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+						sizeof(raw_1P8_CONTROL_010));
+	usleep(20000);  /* 20ms wait */
+
+	/* Enable the PMIC clock */
+	RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+					  sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+	usleep(1000);
+
+	RAW(slave2, 0x10);
+	r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+	usleep(1000);
+	{
+		r = i2c_master_send(client, buf, 1);
+		memset(buf, 0xAA, sizeof(buf));
+		r = i2c_master_recv(client, buf, 1);
+	}
+	RAW(slave1, NCI_I2C_SLAVE);
+	r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+	usleep(1000);
+
+	/* QCA199x NFCC CPU should now boot... */
+	r = i2c_master_recv(client, &raw_slave1_rd, 1);
+	/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+	client->addr = NCI_I2C_SLAVE;
+
+	return r;
+}
+
+static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata)
+{
+	int r = 0;
+	struct device_node *np = dev->of_node;
+
+	r = of_property_read_u32(np, "reg", &pdata->reg);
+	if (r)
+		return -EINVAL;
+
+	r = of_property_read_u32(np, "qcom,clk-gpio", &pdata->ven_gpio);
+	if (r)
+		return -EINVAL;
+
+	pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
+	if ((!gpio_is_valid(pdata->dis_gpio)))
+		return -EINVAL;
+
+	pdata->irq_gpio = of_get_named_gpio(np, "qcom,irq-gpio", 0);
+	if ((!gpio_is_valid(pdata->irq_gpio)))
+		return -EINVAL;
+
+	return r;
+}
+
+static int qca199x_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int r = 0;
+	int irqn = 0;
+	struct clk *nfc_clk;
+	struct device_node *node = client->dev.of_node;
+	struct qca199x_platform_data *platform_data;
+	struct qca199x_dev *qca199x_dev;
+
+	if (client->dev.of_node) {
+		platform_data = devm_kzalloc(&client->dev,
+			sizeof(struct qca199x_platform_data), GFP_KERNEL);
+		if (!platform_data) {
+			dev_err(&client->dev,
+			"nfc-nci probe: Failed to allocate memory\n");
+			return -ENOMEM;
+		}
+		r = nfc_parse_dt(&client->dev, platform_data);
+		if (r)
+			return r;
+	} else {
+		platform_data = client->dev.platform_data;
+	}
+	if (!platform_data)
+		return -EINVAL;
+	dev_dbg(&client->dev,
+		"nfc-nci probe: %s, inside nfc-nci flags = %x\n",
+		__func__, client->flags);
+	if (platform_data == NULL) {
+		dev_err(&client->dev, "nfc-nci probe: failed\n");
+		return -ENODEV;
+	}
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "nfc-nci probe: need I2C_FUNC_I2C\n");
+		return -ENODEV;
+	}
+	qca199x_dev = kzalloc(sizeof(*qca199x_dev), GFP_KERNEL);
+	if (qca199x_dev == NULL) {
+		dev_err(&client->dev,
+		"nfc-nci probe: failed to allocate memory for module data\n");
+		return -ENOMEM;
+	}
+	if (gpio_is_valid(platform_data->irq_gpio)) {
+		r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
+		if (r) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+				platform_data->irq_gpio);
+			goto err_irq;
+		}
+		r = gpio_direction_input(platform_data->irq_gpio);
+		if (r) {
+
+			dev_err(&client->dev,
+			"unable to set direction for gpio [%d]\n",
+				platform_data->irq_gpio);
+			goto err_irq;
+		}
+		gpio_to_irq(0);
+		irqn = gpio_to_irq(platform_data->irq_gpio);
+		if (irqn < 0) {
+			r = irqn;
+			goto err_irq;
+		}
+		client->irq = irqn;
+
+	} else {
+		dev_err(&client->dev, "irq gpio not provided\n");
+		goto err_free_dev;
+	}
+	if (gpio_is_valid(platform_data->dis_gpio)) {
+		r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio");
+		if (r) {
+			dev_err(&client->dev,
+			"NFC: unable to request gpio [%d]\n",
+				platform_data->dis_gpio);
+			goto err_dis_gpio;
+		}
+		r = gpio_direction_output(platform_data->dis_gpio, 1);
+		if (r) {
+			dev_err(&client->dev,
+				"NFC: unable to set direction for gpio [%d]\n",
+					platform_data->dis_gpio);
+			goto err_dis_gpio;
+		}
+	} else {
+		dev_err(&client->dev, "dis gpio not provided\n");
+		goto err_irq;
+	}
+
+	nfc_clk  = clk_get(&client->dev, "ref_clk");
+
+	if (nfc_clk == NULL)
+		goto err_dis_gpio;
+
+	r = clk_prepare_enable(nfc_clk);
+	if (r)
+		goto err_dis_gpio;
+
+	platform_data->ven_gpio = of_get_named_gpio(node,
+						"qcom,clk-gpio", 0);
+
+	if (gpio_is_valid(platform_data->ven_gpio)) {
+		r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
+		if (r) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->irq_gpio);
+			goto err_ven_gpio;
+		}
+		r = gpio_direction_input(platform_data->ven_gpio);
+		if (r) {
+
+			dev_err(&client->dev,
+			"unable to set direction for gpio [%d]\n",
+						platform_data->irq_gpio);
+			goto err_ven_gpio;
+		}
+
+	} else {
+
+		dev_err(&client->dev, "ven gpio not provided\n");
+		goto err_dis_gpio;
+	}
+	qca199x_dev->dis_gpio = platform_data->dis_gpio;
+	qca199x_dev->irq_gpio = platform_data->irq_gpio;
+	qca199x_dev->ven_gpio = platform_data->ven_gpio;
+	qca199x_dev->client = client;
+
+	/* init mutex and queues */
+	init_waitqueue_head(&qca199x_dev->read_wq);
+	mutex_init(&qca199x_dev->read_mutex);
+	spin_lock_init(&qca199x_dev->irq_enabled_lock);
+
+	qca199x_dev->qca199x_device.minor = MISC_DYNAMIC_MINOR;
+	qca199x_dev->qca199x_device.name = "nfc-nci";
+	qca199x_dev->qca199x_device.fops = &nfc_dev_fops;
+
+	r = misc_register(&qca199x_dev->qca199x_device);
+	if (r) {
+		dev_err(&client->dev, "misc_register failed\n");
+		goto err_misc_register;
+	}
+
+	logging_level = 0;
+	/* request irq.  The irq is set whenever the chip has data available
+	* for reading.  It is cleared when all data has been read.
+	*/
+	nfcc_initialise(client, platform_data->reg);
+
+	qca199x_dev->irq_enabled = true;
+	r = request_irq(client->irq, qca199x_dev_irq_handler,
+			  IRQF_TRIGGER_RISING, client->name, qca199x_dev);
+	if (r) {
+		dev_err(&client->dev, "nfc-nci probe: request_irq failed\n");
+		goto err_request_irq_failed;
+	}
+	qca199x_disable_irq(qca199x_dev);
+	i2c_set_clientdata(client, qca199x_dev);
+	dev_dbg(&client->dev,
+	"nfc-nci probe: %s, probing qca1990 exited successfully\n",
+		 __func__);
+	return 0;
+
+err_request_irq_failed:
+	misc_deregister(&qca199x_dev->qca199x_device);
+err_misc_register:
+	mutex_destroy(&qca199x_dev->read_mutex);
+err_ven_gpio:
+	gpio_free(platform_data->ven_gpio);
+err_dis_gpio:
+	gpio_free(platform_data->dis_gpio);
+err_irq:
+	gpio_free(platform_data->irq_gpio);
+err_free_dev:
+	kfree(qca199x_dev);
+	return r;
+}
+
+static int qca199x_remove(struct i2c_client *client)
+{
+	struct qca199x_dev *qca199x_dev;
+
+	qca199x_dev = i2c_get_clientdata(client);
+	free_irq(client->irq, qca199x_dev);
+	misc_deregister(&qca199x_dev->qca199x_device);
+	mutex_destroy(&qca199x_dev->read_mutex);
+	gpio_free(qca199x_dev->irq_gpio);
+	gpio_free(qca199x_dev->dis_gpio);
+	gpio_free(qca199x_dev->ven_gpio);
+	kfree(qca199x_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id qca199x_id[] = {
+	{"qca199x-i2c", 0},
+	{}
+};
+
+static struct i2c_driver qca199x = {
+	.id_table = qca199x_id,
+	.probe = qca199x_probe,
+	.remove = qca199x_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "nfc-nci",
+		.of_match_table = msm_match_table,
+	},
+};
+
+/*
+ * module load/unload record keeping
+ */
+static int __init qca199x_dev_init(void)
+{
+	return i2c_add_driver(&qca199x);
+}
+module_init(qca199x_dev_init);
+
+static void __exit qca199x_dev_exit(void)
+{
+	i2c_del_driver(&qca199x);
+}
+module_exit(qca199x_dev_exit);
+
+MODULE_DESCRIPTION("NFC QCA199x");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
new file mode 100644
index 0000000..4398df7
--- /dev/null
+++ b/drivers/nfc/nfc-nci.h
@@ -0,0 +1,222 @@
+/* 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 __NFC_NCI_H
+#define __NFC_NCI_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include <linux/semaphore.h>
+#include <linux/completion.h>
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+
+struct nfc_device {
+	struct cdev cdev;
+	struct class *char_class;
+};
+
+enum ehandler_mode {
+	UNSOLICITED_READ_MODE = 0,
+	SOLICITED_READ_MODE
+};
+
+enum ekernel_logging_mode {
+	LEVEL_0 = 0,	/* For Basic Comms, such asNCI TX/TX to NFCC */
+	LEVEL_1,	/* Other Debug e.g. Notifications, ISR hit, etc ..*/
+	LEVEL_2,
+	LEVEL_3,
+	LEVEL_4,
+	LEVEL_5
+};
+
+struct DeviceMode {
+	enum ehandler_mode	handle_flavour;
+} tDeviceMode;
+
+#define NFC_DRIVER_NAME			"nfc-nci"
+#define NFC_I2C_DRIVER_NAME		"NCI NFC I2C Interface",
+
+#define NCI_I2C_SLAVE			(0x2C)
+#define NFC_I2C_BUS			3	/* 6, 10, 4, 5 */
+#define NFC_SET_PWR			_IOW(0xE9, 0x01, unsigned int)
+#define NFCC_MODE			_IOW(0xE9, 0x02, unsigned int)
+#define NFC_KERNEL_LOGGING_MODE		_IOW(0xE9, 0x03, unsigned int)
+#define SET_RX_BLOCK			_IOW(0xE9, 0x04, unsigned int)
+#define SET_EMULATOR_TEST_POINT		_IOW(0xE9, 0x05, unsigned int)
+
+#define NFC_MAX_I2C_TRANSFER		(0x0400)
+#define NFC_MSG_MAX_SIZE		(0x21)
+
+#define NFC_RX_BUFFER_CNT_START		(0x0)
+
+#define NFC_RX_BUFFER_BLOCK_SIZE	(0x120)		/* Bytes per Block */
+#define NFC_RX_BUFFER_PAGE_SIZE		(0x1000)	/* Page size Bytes */
+#define NFC_RX_BUFFER_PAGES		(0x8)
+#define NFC_RX_ORDER_FREE_PAGES		(0x3)		/* Free 8 Pages */
+
+/* The total no. of Blocks */
+#define NFC_RX_BUFFER_CNT_LIMIT		(unsigned short)(	\
+						(		\
+						((NFC_RX_BUFFER_PAGE_SIZE) *\
+						(NFC_RX_BUFFER_PAGES))/\
+						(NFC_RX_BUFFER_BLOCK_SIZE)\
+						)		\
+						)		\
+
+#define PAYLOAD_HEADER_LENGTH		(0x3)
+#define PAYLOAD_LENGTH_MAX		(256)
+#define BYTE				(0x8)
+#define NCI_IDENTIFIER			(0x10)
+
+/** Power Management Related **/
+
+#define NFCC_WAKE			(0x01)
+#define NFCC_SLEEP			(0x00)
+
+#define XTAL_CLOCK			(0X00)
+#define REFERENCE_CLOCK			(0X01)
+
+/* LDO Trim Settings */
+#define IPTAT_TRIM			(0x1F)
+#define V1P1_TRIM			(0x0F)
+#define V1P8_TRIM			(0x0F)
+#define VBATT_OK_THRESHOLD		(0x07)
+
+#define PWR_EN		(0x08)		/* Enable 1.1V LDO Regulator */
+#define LS_EN		(0x04)		/* Enable 1.1V->1.8V Level Shifters */
+
+/* Write '1' to cause wake event to NFCC. If set NFCC will not go to SLEEP */
+#define NCI_WAKE	(0x02)
+
+#define NCI_ENA		(0x01)		/* Write '1' to enable PLL */
+#define FREQ_SEL	(0x00)		/* XO Frequency Select */
+#define FREQ_SEL_13	(0x00)		/* XO Frequency Select = 13.56MHz */
+#define FREQ_SEL_19	(0x01)		/* XO Frequency Select = 19.20 MHz */
+#define FREQ_SEL_26	(0x02)		/* XO Frequency Select = 26.00 MHz */
+#define FREQ_SEL_27	(0x03)		/* XO Frequency Select = 27.12 MHz */
+#define FREQ_SEL_37	(0x04)		/* XO Frequency Select = 37.40 MHz */
+#define FREQ_SEL_38	(0x05)		/* XO Frequency Select = 38.40 MHz */
+#define FREQ_SEL_40	(0x06)		/* XO Frequency Select = 40.00 MHz */
+#define FREQ_SEL_48	(0x07)		/* XO Frequency Select = 48.00 MHz */
+#define FREQ_SEL_27	(0x03)		/* XO Frequency Select */
+
+
+#define QUALIFY_REFCLK	(0x80)
+#define QUALIFY_OSC	(0x40)
+#define LOCALBIASXTAL	(0x20)
+#define BIAS2X_FORCE	(0x10)
+#define BIAS2X		(0x08)
+#define LBIAS2X		(0x04)
+#define SMALLRF		(0x02)
+#define SMALLRBIAS	(0x01)
+
+/* Select as appropriate */
+#define CRYSTAL_OSC	((QUALIFY_REFCLK) | (QUALIFY_OSC) |	\
+			(LOCALBIASXTAL) | (BIAS2X_FORCE) |	\
+			(BIAS2X) | (LBIAS2X) | (SMALLRF) | (SMALLRBIAS))
+
+#define CDACIN		(0x3F)	/* Tuning range for load capacitor at X1*/
+#define CDACOUT		(0x3F)	/* Tuning range for load capacitor at X2*/
+
+#define RAW(reg, value)		(raw_##reg[1] = value)
+
+/* Logging macro with threshold control */
+#define PRINTK(LEVEL, THRESHOLD, pString, ...)		(	\
+		if (LEVEL > THRESHOLD) {			\
+			pr_info(pString, ##__VA_ARGS__);		\
+		}						\
+							)
+
+/* board config */
+struct nfc_platform_data {
+	int (*request_resources) (struct i2c_client *client);
+	void (*free_resources) (void);
+	void (*enable) (int fw);
+	int (*test) (void);
+	void (*disable) (void);
+};
+/*
+ * Internal NFCC Hardware states. At present these may not be possible to
+ * detect in software as possibly no power when
+ * in monitor state! Also, need to detect DISABLE control GPIO from PMIC.
+ */
+enum nfcc_hardware_state {
+	NFCC_STATE_MONITOR,	/* VBAT < h/w Critcal Voltage */
+	/* VBAT > H/W Critical Voltage;
+	Lowest Power Mode - DISABLE = 1; only
+	possible when phone is ON */
+	NFCC_STATE_HPD,
+	/* VBAT > H/W Critical Voltage; DISABLE = 0;
+	Only possible when phone is ON */
+	NFCC_STSTE_ULPM,
+	/* VBAT > H/W Critical Voltage; DISABLE = 0;
+	Powered by PMIC & VBAT; 1.8V I/O supply on; VDDPX available, boot is
+	initiated by host over I2C */
+	NFCC_STATE_NORMAL_REGION1,
+	/* VBAT > H/W Critical Voltage; DISABLE = 0;
+	Powered by VBAT; 1.8V I/O supply on; VDDPX available, boot is initiated
+	by host over I2C */
+	NFCC_STATE_NORMAL_REGION2,
+};
+
+/* We assume here that VBATT > h/w Critical Voltage */
+enum nfcc_state {
+	/* Assume In ULPM state, ready for initialisation, cannot detect for
+	Monitor or HPD states */
+	NFCC_STATE_COLD,
+	/* (VDDPX==1) && (Following I2C initialisation). In Region 1 or Region2
+	state WAKE */
+	NFCC_STATE_NORMAL_WAKE,
+	/* (VDDPX==1) && (Following I2C initialisation). In Region 1 or Region2
+	state SLEEP */
+	NFCC_STATE_NORMAL_SLEEP,
+};
+
+
+enum nfcc_irq {
+	NFCC_NO_INT,
+	NFCC_INT,
+};
+
+
+struct nfc_info {
+	struct	miscdevice			miscdev;
+	struct	i2c_client			*i2c_dev;
+	struct	regulator_bulk_data		regs[3];
+	enum	nfcc_state			state;
+	wait_queue_head_t			read_wait;
+	loff_t					read_offset;
+	struct	mutex				read_mutex;
+	struct	mutex				mutex;
+	u8					*buf;
+	size_t					buflen;
+	spinlock_t				irq_enabled_lock;
+	unsigned int				count_irq;
+	enum	nfcc_irq			read_irq;
+};
+
+
+struct nfc_i2c_platform_data {
+	unsigned int	nfc_irq_gpio;
+	unsigned int	nfc_clk_en_gpio;
+	unsigned int	dis_gpio;
+	unsigned int	irq_gpio;
+	unsigned int	ven_gpio;
+	unsigned int	firm_gpio;
+	unsigned int	reg;
+};
+#endif
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index aaf5cc0..87ddf59 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -346,11 +346,18 @@
 	uint32_t mask[4];
 	int i;
 
-	if (attrib->attrib_mask & IPA_FLT_TOS) {
-		nbytes = scnprintf(buff + cnt, sz - cnt, "tos:%d ",
-				attrib->u.v4.tos);
+
+	if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+		nbytes = scnprintf(buff + cnt, sz - cnt, "tos_value:%d ",
+				attrib->tos_value);
 		cnt += nbytes;
 	}
+	if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+		nbytes = scnprintf(buff + cnt, sz - cnt, "tos_mask:%d ",
+				attrib->tos_mask);
+		cnt += nbytes;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
 		nbytes = scnprintf(buff + cnt, sz - cnt, "protocol:%d ",
 				attrib->u.v4.protocol);
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index e057c5a..64c77a0 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -119,12 +119,12 @@
 {
 	int result;
 
-	read_lock(&ipa_rm_ctx->lock);
+	write_lock(&ipa_rm_ctx->lock);
 	result = ipa_rm_dep_graph_add_dependency(
 						ipa_rm_ctx->dep_graph,
 						resource_name,
 						depends_on_name);
-	read_unlock(&ipa_rm_ctx->lock);
+	write_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_add_dependency);
@@ -145,12 +145,12 @@
 			enum ipa_rm_resource_name depends_on_name)
 {
 	int result;
-	read_lock(&ipa_rm_ctx->lock);
+	write_lock(&ipa_rm_ctx->lock);
 	result = ipa_rm_dep_graph_delete_dependency(
 			  ipa_rm_ctx->dep_graph,
 			  resource_name,
 			  depends_on_name);
-	read_unlock(&ipa_rm_ctx->lock);
+	write_unlock(&ipa_rm_ctx->lock);
 	return result;
 }
 EXPORT_SYMBOL(ipa_rm_delete_dependency);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 6430c07..5c27c40 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -67,13 +67,31 @@
 	}
 	rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
 	rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
-	if (entry->hdr)
+	if (entry->hdr) {
 		rule_hdr->u.hdr.hdr_offset =
 			entry->hdr->offset_entry->offset >> 2;
-	else
+	} else {
 		rule_hdr->u.hdr.hdr_offset = 0;
-
+	}
 	buf += sizeof(struct ipa_rt_rule_hw_hdr);
+	if ((ip == IPA_IP_v4) &&
+		(entry->rule.attrib.attrib_mask & IPA_FLT_TOS)) {
+			entry->rule.attrib.tos_value =
+				(entry->rule.attrib.u.v4.tos << 5);
+			entry->rule.attrib.tos_mask = 0xe0;
+			entry->rule.attrib.attrib_mask &= ~IPA_FLT_TOS;
+			entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
+	}
+
+	if ((ip == IPA_IP_v6) &&
+		(entry->rule.attrib.attrib_mask & IPA_FLT_TC)) {
+			entry->rule.attrib.tos_value =
+				(entry->rule.attrib.u.v6.tc << 5);
+			entry->rule.attrib.tos_mask = 0xe0;
+			entry->rule.attrib.attrib_mask &= ~IPA_FLT_TC;
+			entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
+	}
+
 	if (ipa_generate_hw_rule(ip, &rule->attrib, &buf, &en_rule)) {
 		IPAERR("fail to generate hw rule\n");
 		return -EPERM;
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 23de300..21a6dc4 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -237,6 +237,20 @@
 			*buf = ipa_pad_to_32(*buf);
 		}
 
+		if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+			if (ipa_ofst_meq32[ofst_meq32] == -1) {
+				IPAERR("ran out of meq32 eq\n");
+				return -EPERM;
+			}
+			*en_rule |= ipa_ofst_meq32[ofst_meq32];
+			/* 0 => offset of TOS in v4 header */
+			*buf = ipa_write_8(0, *buf);
+			*buf = ipa_write_32((attrib->tos_mask << 16), *buf);
+			*buf = ipa_write_32(attrib->tos_value, *buf);
+			*buf = ipa_pad_to_32(*buf);
+			ofst_meq32++;
+		}
+
 		if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
 			*en_rule |= IPA_PROTOCOL_EQ;
 			*buf = ipa_write_8(attrib->u.v4.protocol, *buf);
@@ -568,6 +582,20 @@
 			*buf = ipa_pad_to_32(*buf);
 		}
 
+		if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+			if (ipa_ofst_meq32[ofst_meq32] == -1) {
+				IPAERR("ran out of meq32 eq\n");
+				return -EPERM;
+			}
+			*en_rule |= ipa_ofst_meq32[ofst_meq32];
+			/* 0 => offset of TOS in v4 header */
+			*buf = ipa_write_8(0, *buf);
+			*buf = ipa_write_32((attrib->tos_mask << 20), *buf);
+			*buf = ipa_write_32(attrib->tos_value, *buf);
+			*buf = ipa_pad_to_32(*buf);
+			ofst_meq32++;
+		}
+
 		if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
 			*en_rule |= IPA_FLT_FLOW_LABEL;
 			 /* FIXME FL is only 20 bits */
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index b390280..fae09fc 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -153,7 +153,6 @@
 	bool prod_stopped;
 
 	struct completion prod_avail[MAX_BAMS];
-	struct completion cons_avail[MAX_BAMS];
 	struct completion cons_released[MAX_BAMS];
 	struct completion prod_released[MAX_BAMS];
 
@@ -878,7 +877,6 @@
 
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
 	info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
-	complete_all(&info.cons_avail[cur_bam]);
 
 	spin_lock(&usb_bam_lock);
 
@@ -1024,7 +1022,7 @@
 	}
 }
 
-static void wait_for_prod_granted(enum usb_bam cur_bam, bool start_cons)
+static void wait_for_prod_granted(enum usb_bam cur_bam)
 {
 	int ret;
 
@@ -1038,8 +1036,6 @@
 			__func__);
 
 	init_completion(&info.prod_avail[cur_bam]);
-	if (start_cons)
-		init_completion(&info.cons_avail[cur_bam]);
 
 	ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
 	if (!ret) {
@@ -1056,22 +1052,14 @@
 		pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
 }
 
-void wait_for_cons_granted(enum usb_bam cur_bam)
+void notify_usb_connected(enum usb_bam cur_bam)
 {
-	pr_debug("%s: Waiting for CONS\n", __func__);
-	if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
-		if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
-						USB_BAM_TIMEOUT))
-			pr_err("%s: Timeout wainting for CONS_REQUEST\n",
-			__func__);
-		pr_err("%s: Finished waiting for CONS\n", __func__);
-	}
+	pr_debug("%s: enter\n", __func__);
 
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
 	if (cur_bam == HSUSB_BAM)
 		info.connect_complete = 1;
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
-	pr_debug("%s: CONS is granted\n", __func__);
 
 	if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
 		pr_debug("%s: Notify CONS_GRANTED\n", __func__);
@@ -1080,20 +1068,6 @@
 	}
 }
 
-void usb_bam_wait_for_cons_granted(
-	struct usb_bam_connect_ipa_params *ipa_params)
-{
-	struct usb_bam_pipe_connect *pipe_connect;
-	enum usb_bam cur_bam;
-	u8 src_idx;
-
-	src_idx = ipa_params->src_idx;
-	pipe_connect = &usb_bam_connections[src_idx];
-	cur_bam = pipe_connect->bam_type;
-
-	wait_for_cons_granted(cur_bam);
-}
-
 static void wait_for_prod_release(enum usb_bam cur_bam)
 {
 	int ret;
@@ -1270,8 +1244,8 @@
 	info.lpm_wait_handshake[HSUSB_BAM] = true;
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
 
-	wait_for_prod_granted(HSUSB_BAM, true);
-	wait_for_cons_granted(HSUSB_BAM);
+	wait_for_prod_granted(HSUSB_BAM);
+	notify_usb_connected(HSUSB_BAM);
 	if (info.cons_stopped) {
 		ipa_resume_pipes();
 		if (info.start) {
@@ -1339,7 +1313,7 @@
 	usb_bam_resume_hsic_host();
 
 	/* Ensure getting the producer resource */
-	wait_for_prod_granted(HSIC_BAM, false);
+	wait_for_prod_granted(HSIC_BAM);
 }
 
 void msm_bam_hsic_notify_on_resume(void)
@@ -1500,7 +1474,7 @@
 
 	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
 		pr_debug("%s: Starting connect sequence\n", __func__);
-		wait_for_prod_granted(cur_bam, true);
+		wait_for_prod_granted(cur_bam);
 	}
 
 	ret = connect_pipe_ipa(idx, ipa_params);
@@ -1524,7 +1498,7 @@
 	ctx.pipes_enabled_per_bam[cur_bam] += 1;
 	spin_unlock(&usb_bam_lock);
 	if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
-		wait_for_cons_granted(cur_bam);
+		notify_usb_connected(cur_bam);
 
 	if (cur_bam == HSUSB_BAM)
 		mutex_unlock(&info.suspend_resume_mutex);
@@ -1586,7 +1560,7 @@
 		if (pipe_connect->peer_bam == IPA_P_BAM &&
 		    pipe_connect->bam_type == HSIC_BAM &&
 		    info.cur_prod_state[HSIC_BAM] != IPA_RM_RESOURCE_GRANTED) {
-			wait_for_prod_granted(HSIC_BAM, false);
+			wait_for_prod_granted(HSIC_BAM);
 		}
 
 		/*
@@ -1618,7 +1592,7 @@
 
 		if (pipe_connect->bam_type == HSUSB_BAM) {
 			/* A2 wakeup not from LPM (CONS was up) */
-			wait_for_prod_granted(pipe_connect->bam_type, true);
+			wait_for_prod_granted(pipe_connect->bam_type);
 			if (info.start) {
 				pr_debug("%s: Enqueue PROD transfer", __func__);
 				info.start(info.start_stop_param,
@@ -2568,8 +2542,6 @@
 		ctx.is_bam_inactivity[i] = false;
 		init_completion(&info.prod_avail[i]);
 		complete(&info.prod_avail[i]);
-		init_completion(&info.cons_avail[i]);
-		complete(&info.cons_avail[i]);
 		init_completion(&info.cons_released[i]);
 		complete(&info.cons_released[i]);
 		init_completion(&info.prod_released[i]);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 14cba58..12aef1c 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -45,8 +45,10 @@
 #define BMS1_OCV_USE_LIMIT_CTL		0x4C
 /* Delay control */
 #define BMS1_S1_DELAY_CTL		0x5A
-/* CC interrupt threshold */
-#define BMS1_CC_THR0			0x7A
+/* OCV interrupt threshold */
+#define BMS1_OCV_THR0			0x50
+/* SW CC interrupt threshold */
+#define BMS1_SW_CC_THR0			0xA0
 /* OCV for r registers */
 #define BMS1_OCV_FOR_R_DATA0		0x80
 #define BMS1_VSENSE_FOR_R_DATA0		0x82
@@ -120,6 +122,16 @@
 	int chargecycles;
 };
 
+struct bms_irq {
+	unsigned int	irq;
+	unsigned long	disabled;
+};
+
+struct bms_wakeup_source {
+	struct wakeup_source	source;
+	unsigned long		disabled;
+};
+
 struct qpnp_bms_chip {
 	struct device			*dev;
 	struct power_supply		bms_psy;
@@ -176,7 +188,7 @@
 	int				low_soc_calc_threshold;
 	int				low_soc_calculate_soc_ms;
 	int				calculate_soc_ms;
-	struct wake_lock		soc_wake_lock;
+	struct bms_wakeup_source	soc_wake_source;
 	struct wake_lock		cv_wake_lock;
 
 	uint16_t			ocv_reading_at_100;
@@ -248,6 +260,8 @@
 	u8				charge_increase;
 	int				fcc_new_sysfs;
 	int				fcc_update_complete;
+	struct bms_irq			sw_cc_thr_irq;
+	struct bms_irq			ocv_thr_irq;
 };
 
 static struct of_device_id qpnp_bms_match_table[] = {
@@ -371,6 +385,38 @@
 	return qpnp_masked_write_base(chip, chip->base + addr, mask, val);
 }
 
+static void bms_stay_awake(struct bms_wakeup_source *source)
+{
+	if (__test_and_clear_bit(0, &source->disabled)) {
+		__pm_stay_awake(&source->source);
+		pr_debug("enabled source %s\n", source->source.name);
+	}
+}
+
+static void bms_relax(struct bms_wakeup_source *source)
+{
+	if (!__test_and_set_bit(0, &source->disabled)) {
+		__pm_relax(&source->source);
+		pr_debug("disabled source %s\n", source->source.name);
+	}
+}
+
+static void enable_bms_irq(struct bms_irq *irq)
+{
+	if (__test_and_clear_bit(0, &irq->disabled)) {
+		enable_irq(irq->irq);
+		pr_debug("enabled irq %d\n", irq->irq);
+	}
+}
+
+static void disable_bms_irq(struct bms_irq *irq)
+{
+	if (!__test_and_set_bit(0, &irq->disabled)) {
+		disable_irq(irq->irq);
+		pr_debug("disabled irq %d\n", irq->irq);
+	}
+}
+
 #define HOLD_OREG_DATA		BIT(0)
 static int lock_output_data(struct qpnp_bms_chip *chip)
 {
@@ -412,7 +458,6 @@
 
 #define VADC_CALIB_UV		625000
 #define VBATT_MUL_FACTOR	3
-
 static int adjust_vbatt_reading(struct qpnp_bms_chip *chip, int reading_uv)
 {
 	s64 numerator, denominator;
@@ -490,6 +535,30 @@
 	return result_uv;
 }
 
+static s64 cc_reverse_adjust_for_gain(s64 uv)
+{
+	struct qpnp_iadc_calib calibration;
+	int gain;
+	s64 result_uv;
+
+	qpnp_iadc_get_gain_and_offset(&calibration);
+	gain = (int)calibration.gain_raw - (int)calibration.offset_raw;
+
+	pr_debug("reverse adjusting_uv = %lld\n", uv);
+	if (gain == 0) {
+		pr_debug("gain is %d, not adjusting\n", gain);
+		return uv;
+	}
+	pr_debug("adjusting by factor: %hu/%lld = %lld%%\n",
+			gain, QPNP_ADC_GAIN_IDEAL,
+			div64_s64((s64)gain * 100LL,
+				(s64)QPNP_ADC_GAIN_IDEAL));
+
+	result_uv = div64_s64(uv * (s64)gain, QPNP_ADC_GAIN_IDEAL);
+	pr_debug("result_uv = %lld\n", result_uv);
+	return result_uv;
+}
+
 static int convert_vsense_to_uv(struct qpnp_bms_chip *chip,
 					int16_t reading)
 {
@@ -565,6 +634,20 @@
 }
 
 #define CC_36_BIT_MASK 0xFFFFFFFFFLL
+static uint64_t convert_s64_to_s36(int64_t raw64)
+{
+	return (uint64_t) raw64 & CC_36_BIT_MASK;
+}
+
+#define SIGN_EXTEND_36_TO_64_MASK (-1LL ^ CC_36_BIT_MASK)
+static int64_t convert_s36_to_s64(uint64_t raw36)
+{
+	raw36 = raw36 & CC_36_BIT_MASK;
+	/* convert 36 bit signed value into 64 signed value */
+	return (raw36 >> 35) == 0LL ?
+		raw36 : (SIGN_EXTEND_36_TO_64_MASK | raw36);
+}
+
 static int read_cc_raw(struct qpnp_bms_chip *chip, int64_t *reading,
 							int cc_type)
 {
@@ -582,12 +665,7 @@
 		return -ENXIO;
 	}
 
-	raw_reading = raw_reading & CC_36_BIT_MASK;
-	/* convert 36 bit signed value into 64 signed value */
-	*reading = (raw_reading >> 35) == 0LL ?
-		raw_reading : ((-1LL ^ CC_36_BIT_MASK) | raw_reading);
-	pr_debug("before conversion: %llx, after conversion: %llx\n",
-			raw_reading, *reading);
+	*reading = convert_s36_to_s64(raw_reading);
 
 	return 0;
 }
@@ -1282,6 +1360,59 @@
 	return rc;
 }
 
+/* Returns estimated battery resistance */
+static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
+{
+	return chip->rbatt_mohm * 1000;
+}
+
+/* Returns instantaneous current in uA */
+static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
+{
+	int rc, result_ua;
+
+	rc = get_battery_current(chip, &result_ua);
+	if (rc) {
+		pr_err("failed to get current: %d\n", rc);
+		return rc;
+	}
+	return result_ua;
+}
+
+/* Returns coulomb counter in uAh */
+static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
+{
+	int64_t cc_raw;
+
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+	read_cc_raw(chip, &cc_raw, false);
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	return calculate_cc(chip, cc_raw, CC, NORESET);
+}
+
+/* Returns shadow coulomb counter in uAh */
+static int get_prop_bms_charge_counter_shadow(struct qpnp_bms_chip *chip)
+{
+	int64_t cc_raw;
+
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+	read_cc_raw(chip, &cc_raw, true);
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	return calculate_cc(chip, cc_raw, SHDW_CC, NORESET);
+}
+
+/* Returns full charge design in uAh */
+static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
+{
+	return chip->fcc_mah * 1000;
+}
+
 static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
 {
 	unsigned long now_tm_sec = 0;
@@ -1920,6 +2051,92 @@
 	}
 }
 
+static int64_t convert_cc_uah_to_raw(struct qpnp_bms_chip *chip, int64_t cc_uah)
+{
+	int64_t cc_uv, cc_pvh, cc_raw;
+
+	cc_pvh = cc_uah * chip->r_sense_uohm;
+	cc_uv = div_s64(cc_pvh * SLEEP_CLK_HZ * SECONDS_PER_HOUR,
+				CC_READING_TICKS * 1000000LL);
+	cc_raw = div_s64(cc_uv * CC_READING_RESOLUTION_D,
+			CC_READING_RESOLUTION_N);
+	return cc_raw;
+}
+
+#define CC_STEP_INCREMENT_UAH	1500
+#define OCV_STEP_INCREMENT	0x10
+static void configure_soc_wakeup(struct qpnp_bms_chip *chip,
+				struct soc_params *params,
+				int batt_temp, int target_soc)
+{
+	int target_ocv_uv;
+	int64_t target_cc_uah, cc_raw_64, current_shdw_cc_raw_64;
+	int64_t current_shdw_cc_uah, iadc_comp_factor;
+	uint64_t cc_raw, current_shdw_cc_raw;
+	int16_t ocv_raw, current_ocv_raw;
+
+	current_shdw_cc_raw = 0;
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+	qpnp_read_wrapper(chip, (u8 *)&current_ocv_raw,
+			chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+	current_shdw_cc_uah = get_prop_bms_charge_counter_shadow(chip);
+	current_shdw_cc_raw_64 = convert_cc_uah_to_raw(chip,
+			current_shdw_cc_uah);
+
+	/*
+	 * Calculate the target shadow coulomb counter threshold for when
+	 * the SoC changes.
+	 *
+	 * Since the BMS driver resets the shadow coulomb counter every
+	 * 20 seconds when the device is awake, calculate the threshold as
+	 * a delta from the current shadow coulomb count.
+	 */
+	target_cc_uah = (100 - target_soc)
+		* (params->fcc_uah - params->uuc_uah)
+		/ 100 - current_shdw_cc_uah;
+	if (target_cc_uah < 0) {
+		/*
+		 * If the target cc is below 0, that means we have already
+		 * passed the point where SoC should have fallen.
+		 * Set a wakeup in a few more mAh and check back again
+		 */
+		target_cc_uah = CC_STEP_INCREMENT_UAH;
+	}
+	iadc_comp_factor = 100000;
+	qpnp_iadc_comp_result(&iadc_comp_factor);
+	target_cc_uah = div64_s64(target_cc_uah * 100000, iadc_comp_factor);
+	target_cc_uah = cc_reverse_adjust_for_gain(target_cc_uah);
+	cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
+	cc_raw = convert_s64_to_s36(cc_raw_64);
+
+	find_ocv_for_soc(chip, params, batt_temp, target_soc, &target_ocv_uv);
+	ocv_raw = convert_vbatt_uv_to_raw(chip, target_ocv_uv);
+
+	/*
+	 * If the current_ocv_raw was updated since reaching 100% and is lower
+	 * than the calculated target ocv threshold, set the new target
+	 * threshold 1.5mAh lower in order to check if the SoC changed yet.
+	 */
+	if (current_ocv_raw != chip->ocv_reading_at_100
+			&& current_ocv_raw < ocv_raw)
+		ocv_raw = current_ocv_raw - OCV_STEP_INCREMENT;
+
+	qpnp_write_wrapper(chip, (u8 *)&cc_raw,
+			chip->base + BMS1_SW_CC_THR0, 5);
+	qpnp_write_wrapper(chip, (u8 *)&ocv_raw,
+			chip->base + BMS1_OCV_THR0, 2);
+
+	pr_debug("current sw_cc_raw = 0x%llx, current ocv = 0x%hx\n",
+			current_shdw_cc_raw, (uint16_t)current_ocv_raw);
+	pr_debug("target_cc_uah = %lld, raw64 = 0x%llx, raw 36 = 0x%llx, ocv_raw = 0x%hx\n",
+			target_cc_uah,
+			(uint64_t)cc_raw_64, cc_raw,
+			(uint16_t)ocv_raw);
+}
+
 #define SLEEP_RECALC_INTERVAL	3
 static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
 					struct raw_soc_params *raw,
@@ -2022,7 +2239,13 @@
 	/* always clamp soc due to BMS hw/sw immaturities */
 	new_calculated_soc = clamp_soc_based_on_voltage(chip,
 					new_calculated_soc);
-
+	/*
+	 * If the battery is full, configure the cc threshold so the system
+	 * wakes up after SoC changes
+	 */
+	if (is_battery_full(chip))
+		configure_soc_wakeup(chip, &params,
+				batt_temp, bound_soc(new_calculated_soc - 1));
 done_calculating:
 	mutex_lock(&chip->last_soc_mutex);
 	previous_soc = chip->calculated_soc;
@@ -2101,8 +2324,7 @@
 	struct qpnp_vadc_result result;
 	struct raw_soc_params raw;
 
-	if (!wake_lock_active(&chip->soc_wake_lock))
-		wake_lock(&chip->soc_wake_lock);
+	bms_stay_awake(&chip->soc_wake_source);
 	mutex_lock(&chip->vbat_monitor_mutex);
 	qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
 	mutex_unlock(&chip->vbat_monitor_mutex);
@@ -2127,7 +2349,7 @@
 			mutex_unlock(&chip->last_ocv_uv_mutex);
 		}
 	}
-	wake_unlock(&chip->soc_wake_lock);
+	bms_relax(&chip->soc_wake_source);
 	return soc;
 }
 
@@ -2681,8 +2903,20 @@
 			pr_debug("charging ended\n");
 			charging_ended(chip);
 		}
+
+		if (status == POWER_SUPPLY_STATUS_FULL) {
+			pr_debug("battery full\n");
+			enable_bms_irq(&chip->ocv_thr_irq);
+			enable_bms_irq(&chip->sw_cc_thr_irq);
+		} else if (chip->battery_status
+				== POWER_SUPPLY_STATUS_FULL) {
+			pr_debug("battery not full any more\n");
+			disable_bms_irq(&chip->ocv_thr_irq);
+			disable_bms_irq(&chip->sw_cc_thr_irq);
+		}
+
 		chip->battery_status = status;
-		/* a new battery was inserted or removed, so force a soc
+		/* battery charge status has changed, so force a soc
 		 * recalculation to update the SoC */
 		schedule_work(&chip->recalc_work);
 	}
@@ -2716,59 +2950,6 @@
 	return report_state_of_charge(chip);
 }
 
-/* Returns estimated battery resistance */
-static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
-{
-	return chip->rbatt_mohm * 1000;
-}
-
-/* Returns instantaneous current in uA */
-static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
-{
-	int rc, result_ua;
-
-	rc = get_battery_current(chip, &result_ua);
-	if (rc) {
-		pr_err("failed to get current: %d\n", rc);
-		return rc;
-	}
-	return result_ua;
-}
-
-/* Returns coulomb counter in uAh */
-static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
-{
-	int64_t cc_raw;
-
-	mutex_lock(&chip->bms_output_lock);
-	lock_output_data(chip);
-	read_cc_raw(chip, &cc_raw, CC);
-	unlock_output_data(chip);
-	mutex_unlock(&chip->bms_output_lock);
-
-	return calculate_cc(chip, cc_raw, CC, NORESET);
-}
-
-/* Returns shadow coulomb counter in uAh */
-static int get_prop_bms_charge_counter_shadow(struct qpnp_bms_chip *chip)
-{
-	int64_t cc_raw;
-
-	mutex_lock(&chip->bms_output_lock);
-	lock_output_data(chip);
-	read_cc_raw(chip, &cc_raw, SHDW_CC);
-	unlock_output_data(chip);
-	mutex_unlock(&chip->bms_output_lock);
-
-	return calculate_cc(chip, cc_raw, SHDW_CC, NORESET);
-}
-
-/* Returns full charge design in uAh */
-static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
-{
-	return chip->fcc_mah * 1000;
-}
-
 static void qpnp_bms_external_power_changed(struct power_supply *psy)
 {
 	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
@@ -3019,6 +3200,26 @@
 			chip->shutdown_soc_invalid);
 }
 
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_bms_chip *chip = _chip;
+
+	pr_debug("ocv_thr irq triggered\n");
+	bms_stay_awake(&chip->soc_wake_source);
+	schedule_work(&chip->recalc_work);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bms_sw_cc_thr_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_bms_chip *chip = _chip;
+
+	pr_debug("sw_cc_thr irq triggered\n");
+	bms_stay_awake(&chip->soc_wake_source);
+	schedule_work(&chip->recalc_work);
+	return IRQ_HANDLED;
+}
+
 #define PALLADIUM_ID_MIN	0x7F40
 #define PALLADIUM_ID_MAX	0x7F5A
 #define DESAY_5200_ID_MIN	0x7F7F
@@ -3199,6 +3400,35 @@
 	chip->first_time_calc_uuc = 1;
 }
 
+#define SPMI_SETUP_IRQ(irq_name)					\
+do {									\
+	chip->irq_name##_irq.irq = spmi_get_irq_byname(chip->spmi,	\
+					resource, #irq_name);		\
+	if (chip->irq_name##_irq.irq < 0) {				\
+		pr_err("Unable to get " #irq_name " irq\n");		\
+		return -ENXIO;						\
+	}								\
+	rc = devm_request_irq(chip->dev, chip->irq_name##_irq.irq,	\
+			bms_##irq_name##_irq_handler,			\
+			IRQF_TRIGGER_RISING, #irq_name, chip);		\
+	if (rc < 0) {							\
+		pr_err("Unable to request " #irq_name " irq: %d\n", rc);\
+		return -ENXIO;						\
+	}								\
+} while (0)
+
+static int bms_setup_irqs(struct qpnp_bms_chip *chip,
+			struct spmi_resource *resource)
+{
+	int rc;
+
+	SPMI_SETUP_IRQ(sw_cc_thr);
+	enable_irq_wake(chip->sw_cc_thr_irq.irq);
+	SPMI_SETUP_IRQ(ocv_thr);
+	enable_irq_wake(chip->ocv_thr_irq.irq);
+	return 0;
+}
+
 #define REG_OFFSET_PERP_TYPE			0x04
 #define REG_OFFSET_PERP_SUBTYPE			0x05
 #define BMS_BMS_TYPE				0xD
@@ -3246,6 +3476,11 @@
 
 		if (type == BMS_BMS_TYPE && subtype == BMS_BMS1_SUBTYPE) {
 			chip->base = resource->start;
+			rc = bms_setup_irqs(chip, spmi_resource);
+			if (rc) {
+				pr_err("Could not register irqs\n");
+				return rc;
+			}
 		} else if (type == BMS_IADC_TYPE
 				&& (subtype == BMS_IADC1_SUBTYPE
 				|| subtype == BMS_IADC2_SUBTYPE)) {
@@ -3509,8 +3744,7 @@
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
 
-	wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
-			"qpnp_soc_lock");
+	wakeup_source_init(&chip->soc_wake_source.source, "qpnp_soc_wake");
 	wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
 			"qpnp_low_voltage_lock");
 	wake_lock_init(&chip->cv_wake_lock, WAKE_LOCK_SUSPEND,
@@ -3588,7 +3822,7 @@
 	power_supply_unregister(&chip->bms_psy);
 error_setup:
 	dev_set_drvdata(&spmi->dev, NULL);
-	wake_lock_destroy(&chip->soc_wake_lock);
+	wakeup_source_trash(&chip->soc_wake_source.source);
 	wake_lock_destroy(&chip->low_voltage_wake_lock);
 	wake_lock_destroy(&chip->cv_wake_lock);
 error_resource:
@@ -3640,9 +3874,8 @@
 				- (int)(time_since_last_recalc * 1000));
 	}
 
-	if (!wake_lock_active(&chip->soc_wake_lock)
-			&& time_until_next_recalc == 0)
-		wake_lock(&chip->soc_wake_lock);
+	if (time_until_next_recalc == 0)
+		bms_stay_awake(&chip->soc_wake_source);
 	schedule_delayed_work(&chip->calculate_soc_delayed_work,
 		round_jiffies_relative(msecs_to_jiffies
 		(time_until_next_recalc)));
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 4a3ea76..97d47db 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -325,35 +325,7 @@
 	}
 	pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
 	if (pstat != 0) {
-		int i = 0;
-		for (i = dev->pipe_b; i < MSM_SLIM_NPORTS; i++) {
-			if (pstat & 1 << i) {
-				u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
-							i, dev->ver));
-				if (val & (1 << 19)) {
-					dev->ctrl.ports[i].err =
-						SLIM_P_DISCONNECT;
-					dev->pipes[i-dev->pipe_b].connected =
-							false;
-					/*
-					 * SPS will call completion since
-					 * ERROR flags are registered
-					 */
-				} else if (val & (1 << 2))
-					dev->ctrl.ports[i].err =
-							SLIM_P_OVERFLOW;
-				else if (val & (1 << 3))
-					dev->ctrl.ports[i].err =
-						SLIM_P_UNDERFLOW;
-			}
-			writel_relaxed(1, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
-							dev->ver));
-		}
-		/*
-		 * Guarantee that port interrupt bit(s) clearing writes go
-		 * through before exiting ISR
-		 */
-		mb();
+		return msm_slim_port_irq_handler(dev, pstat);
 	}
 
 	return IRQ_HANDLED;
@@ -446,16 +418,13 @@
 		if (mc != SLIM_MSG_MC_DISCONNECT_PORT)
 			dev->err = msm_slim_connect_pipe_port(dev, *puc);
 		else {
-			struct msm_slim_endp *endpoint = &dev->pipes[*puc];
-			struct sps_register_event sps_event;
-			memset(&sps_event, 0, sizeof(sps_event));
-			sps_register_event(endpoint->sps, &sps_event);
-			sps_disconnect(endpoint->sps);
 			/*
 			 * Remove channel disconnects master-side ports from
 			 * channel. No need to send that again on the bus
+			 * Only disable port
 			 */
-			dev->pipes[*puc].connected = false;
+			writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
+					(*puc + dev->port_b), dev->ver));
 			mutex_unlock(&dev->tx_lock);
 			if (msgv >= 0)
 				msm_slim_put_ctrl(dev);
@@ -468,7 +437,7 @@
 				msm_slim_put_ctrl(dev);
 			return dev->err;
 		}
-		*(puc) = *(puc) + dev->pipe_b;
+		*(puc) = *(puc) + dev->port_b;
 	}
 	if (txn->mt == SLIM_MSG_MT_CORE &&
 		mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
@@ -1258,7 +1227,8 @@
 	dev->ctrl.set_laddr = msm_set_laddr;
 	dev->ctrl.xfer_msg = msm_xfer_msg;
 	dev->ctrl.wakeup =  msm_clk_pause_wakeup;
-	dev->ctrl.config_port = msm_config_port;
+	dev->ctrl.alloc_port = msm_alloc_port;
+	dev->ctrl.dealloc_port = msm_dealloc_port;
 	dev->ctrl.port_xfer = msm_slim_port_xfer;
 	dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
 	/* Reserve some messaging BW for satellite-apps driver communication */
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 6962d53..509c1e8 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -89,6 +89,7 @@
 	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
 	void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
 	u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
+	u32 pstat;
 
 	if (stat & NGD_INT_TX_MSG_SENT) {
 		writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
@@ -147,6 +148,10 @@
 		mb();
 		dev_err(dev->dev, "NGD IE VE change");
 	}
+
+	pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
+	if (pstat != 0)
+		return msm_slim_port_irq_handler(dev, pstat);
 	return IRQ_HANDLED;
 }
 
@@ -357,19 +362,16 @@
 		 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
 		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
 		wbuf[0] == dev->pgdla) {
-		if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+		if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
 			dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
 		else {
-			struct msm_slim_endp *endpoint = &dev->pipes[wbuf[1]];
-			struct sps_register_event sps_event;
-			memset(&sps_event, 0, sizeof(sps_event));
-			sps_register_event(endpoint->sps, &sps_event);
-			sps_disconnect(endpoint->sps);
 			/*
 			 * Remove channel disconnects master-side ports from
 			 * channel. No need to send that again on the bus
+			 * Only disable port
 			 */
-			dev->pipes[wbuf[1]].connected = false;
+			writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
+					(wbuf[1] + dev->port_b), dev->ver));
 			mutex_unlock(&dev->tx_lock);
 			msm_slim_put_ctrl(dev);
 			return 0;
@@ -1083,7 +1085,8 @@
 	dev->ctrl.allocbw = ngd_allocbw;
 	dev->ctrl.xfer_msg = ngd_xfer_msg;
 	dev->ctrl.wakeup =  ngd_clk_pause_wakeup;
-	dev->ctrl.config_port = msm_config_port;
+	dev->ctrl.alloc_port = msm_alloc_port;
+	dev->ctrl.dealloc_port = msm_dealloc_port;
 	dev->ctrl.port_xfer = msm_slim_port_xfer;
 	dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
 	dev->bam_mem = bam_mem;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 0166196..a63ee76 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -73,6 +73,52 @@
 #endif
 }
 
+irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat)
+{
+	int i;
+	u32 int_en = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+							dev->ver));
+	/*
+	 * different port-interrupt than what we enabled, ignore.
+	 * This may happen if overflow/underflow is reported, but
+	 * was disabled due to unavailability of buffers provided by
+	 * client.
+	 */
+	if ((pstat & int_en) == 0)
+		return IRQ_HANDLED;
+	for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
+		if (pstat & (1 << i)) {
+			u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
+						i, dev->ver));
+			if (val & MSM_PORT_OVERFLOW) {
+				dev->ctrl.ports[i-dev->port_b].err =
+						SLIM_P_OVERFLOW;
+			} else if (val & MSM_PORT_UNDERFLOW) {
+				dev->ctrl.ports[i-dev->port_b].err =
+					SLIM_P_UNDERFLOW;
+			}
+		}
+	}
+	/*
+	 * Disable port interrupt here. Re-enable when more
+	 * buffers are provided for this port.
+	 */
+	writel_relaxed((int_en & (~pstat)),
+			PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+					dev->ver));
+	/* clear port interrupts */
+	writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
+							dev->ver));
+	pr_info("disabled overflow/underflow for port 0x%x", pstat);
+
+	/*
+	 * Guarantee that port interrupt bit(s) clearing writes go
+	 * through before exiting ISR
+	 */
+	mb();
+	return IRQ_HANDLED;
+}
+
 int msm_slim_init_endpoint(struct msm_slim_ctrl *dev, struct msm_slim_endp *ep)
 {
 	int ret;
@@ -138,17 +184,27 @@
 void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn)
 {
 	u32 set_cfg = DEF_WATERMARK | DEF_ALIGN | DEF_PACK | ENABLE_PORT;
-	u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
-					dev->ver));
 	writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pn, dev->ver));
 	writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pn, dev->ver));
 	writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pn, dev->ver));
-	writel_relaxed((int_port | 1 << pn) , PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
-								dev->ver));
 	/* Make sure that port registers are updated before returning */
 	mb();
 }
 
+static void msm_slim_disconn_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
+{
+	struct msm_slim_endp *endpoint = &dev->pipes[pn];
+	struct sps_register_event sps_event;
+	writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (pn + dev->port_b),
+					dev->ver));
+	/* Make sure port register is updated */
+	mb();
+	memset(&sps_event, 0, sizeof(sps_event));
+	sps_register_event(endpoint->sps, &sps_event);
+	sps_disconnect(endpoint->sps);
+	dev->pipes[pn].connected = false;
+}
+
 int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
 {
 	struct msm_slim_endp *endpoint = &dev->pipes[pn];
@@ -162,16 +218,26 @@
 	cfg->options = SPS_O_DESC_DONE | SPS_O_ERROR |
 				SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
 
-	if (dev->pipes[pn].connected) {
-		ret = sps_set_config(dev->pipes[pn].sps, cfg);
-		if (ret) {
-			dev_err(dev->dev, "sps pipe-port set config erro:%x\n",
-						ret);
-			return ret;
+	if (dev->pipes[pn].connected &&
+			dev->ctrl.ports[pn].state == SLIM_P_CFG) {
+		return -EISCONN;
+	} else if (dev->pipes[pn].connected) {
+		writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (pn + dev->port_b),
+						dev->ver));
+		/* Make sure port disabling goes through */
+		mb();
+		/* Is pipe already connected in desired direction */
+		if ((dev->ctrl.ports[pn].flow == SLIM_SRC &&
+			cfg->mode == SPS_MODE_DEST) ||
+			(dev->ctrl.ports[pn].flow == SLIM_SINK &&
+			 cfg->mode == SPS_MODE_SRC)) {
+			msm_hw_set_port(dev, pn + dev->port_b);
+			return 0;
 		}
+		msm_slim_disconn_pipe_port(dev, pn);
 	}
 
-	stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->pipe_b),
+	stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->port_b),
 					dev->ver));
 	if (dev->ctrl.ports[pn].flow == SLIM_SRC) {
 		cfg->destination = dev->bam.hdl;
@@ -191,17 +257,21 @@
 		cfg->mode = SPS_MODE_SRC;
 	}
 	/* Space for desciptor FIFOs */
-	cfg->desc.size = MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec);
-	cfg->config = SPS_CONFIG_DEFAULT;
-	ret = sps_connect(dev->pipes[pn].sps, cfg);
+	ret = msm_slim_sps_mem_alloc(dev, &cfg->desc,
+				MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec));
+	if (ret)
+		pr_err("mem alloc for descr failed:%d", ret);
+	else
+		ret = sps_connect(dev->pipes[pn].sps, cfg);
+
 	if (!ret) {
 		dev->pipes[pn].connected = true;
-		msm_hw_set_port(dev, pn + dev->pipe_b);
+		msm_hw_set_port(dev, pn + dev->port_b);
 	}
 	return ret;
 }
 
-int msm_config_port(struct slim_controller *ctrl, u8 pn)
+int msm_alloc_port(struct slim_controller *ctrl, u8 pn)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 	struct msm_slim_endp *endpoint;
@@ -209,7 +279,7 @@
 	if (ctrl->ports[pn].req == SLIM_REQ_HALF_DUP ||
 		ctrl->ports[pn].req == SLIM_REQ_MULTI_CH)
 		return -EPROTONOSUPPORT;
-	if (pn >= (MSM_SLIM_NPORTS - dev->pipe_b))
+	if (pn >= (MSM_SLIM_NPORTS - dev->port_b))
 		return -ENODEV;
 
 	endpoint = &dev->pipes[pn];
@@ -218,6 +288,22 @@
 	return ret;
 }
 
+void msm_dealloc_port(struct slim_controller *ctrl, u8 pn)
+{
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	struct msm_slim_endp *endpoint;
+	if (pn >= (MSM_SLIM_NPORTS - dev->port_b))
+		return;
+	endpoint = &dev->pipes[pn];
+	if (dev->pipes[pn].connected)
+		msm_slim_disconn_pipe_port(dev, pn);
+	if (endpoint->sps) {
+		struct sps_connect *config = &endpoint->config;
+		msm_slim_free_endpoint(endpoint);
+		msm_slim_sps_mem_free(dev, &config->desc);
+	}
+}
+
 enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
 				u8 pn, u8 **done_buf, u32 *done_len)
 {
@@ -241,6 +327,25 @@
 	return SLIM_P_INPROGRESS;
 }
 
+static void msm_slim_port_cb(struct sps_event_notify *ev)
+{
+
+	struct completion *comp = ev->data.transfer.user;
+	struct sps_iovec *iovec = &ev->data.transfer.iovec;
+
+	if (ev->event_id == SPS_EVENT_DESC_DONE) {
+
+		pr_debug("desc done iovec = (0x%x 0x%x 0x%x)\n",
+			iovec->addr, iovec->size, iovec->flags);
+
+	} else {
+		pr_err("%s: ERR event %d\n",
+					__func__, ev->event_id);
+	}
+	if (comp)
+		complete(comp);
+}
+
 int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
 			u32 len, struct completion *comp)
 {
@@ -251,20 +356,29 @@
 		return -ENODEV;
 
 
-	ctrl->ports[pn].xcomp = comp;
 	sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR);
 	sreg.mode = SPS_TRIGGER_WAIT;
-	sreg.xfer_done = comp;
-	sreg.callback = NULL;
-	sreg.user = &ctrl->ports[pn];
+	sreg.xfer_done = NULL;
+	sreg.callback = msm_slim_port_cb;
+	sreg.user = NULL;
 	ret = sps_register_event(dev->pipes[pn].sps, &sreg);
 	if (ret) {
 		dev_dbg(dev->dev, "sps register event error:%x\n", ret);
 		return ret;
 	}
-	ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, NULL,
+	ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, comp,
 				SPS_IOVEC_FLAG_INT);
 	dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
+	if (!ret) {
+		/* Enable port interrupts */
+		u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+						dev->ver));
+		if (!(int_port & (1 << (dev->port_b + pn))))
+			writel_relaxed((int_port | (1 << (dev->port_b + pn))),
+				PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver));
+		/* Make sure that port registers are updated before returning */
+		mb();
+	}
 
 	return ret;
 }
@@ -680,7 +794,7 @@
 		if ((sec_props.ees[dev->ee].pipe_mask >> i) & 0x1)
 			break;
 	}
-	dev->pipe_b = i - 7;
+	dev->port_b = i - 7;
 
 	/* Register the BAM device with the SPS driver */
 	ret = sps_register_bam_device(&bam_props, &bam_handle);
@@ -750,6 +864,12 @@
 	if (dev->use_tx_msgqs >= MSM_MSGQ_ENABLED)
 		msm_slim_remove_ep(dev, &dev->tx_msgq, &dev->use_tx_msgqs);
 	if (dereg) {
+		int i;
+		for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
+			if (dev->pipes[i - dev->port_b].connected)
+				msm_dealloc_port(&dev->ctrl,
+						i - dev->port_b);
+		}
 		sps_deregister_bam_device(dev->bam.hdl);
 		dev->bam.hdl = 0L;
 	}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index f8f625e..896e196 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -13,6 +13,7 @@
 #ifndef _SLIM_MSM_H
 #define _SLIM_MSM_H
 
+#include <linux/irq.h>
 #include <linux/kthread.h>
 #include <mach/msm_qmi_interface.h>
 
@@ -152,6 +153,12 @@
 	PGD_VE_STAT_V1		= 0x1710,
 };
 
+enum msm_slim_port_status {
+	MSM_PORT_OVERFLOW	= 1 << 2,
+	MSM_PORT_UNDERFLOW	= 1 << 3,
+	MSM_PORT_DISCONNECT	= 1 << 19,
+};
+
 enum msm_ctrl_state {
 	MSM_CTRL_AWAKE,
 	MSM_CTRL_SLEEPING,
@@ -177,7 +184,6 @@
 	struct sps_connect		config;
 	struct sps_register_event	event;
 	struct sps_mem_buffer		buf;
-	struct completion		*xcomp;
 	bool				connected;
 };
 
@@ -224,7 +230,7 @@
 	u8			pgdla;
 	enum msm_slim_msgq	use_rx_msgqs;
 	enum msm_slim_msgq	use_tx_msgqs;
-	int			pipe_b;
+	int			port_b;
 	struct completion	reconf;
 	bool			reconf_busy;
 	bool			chan_active;
@@ -271,11 +277,13 @@
 int msm_slim_rx_dequeue(struct msm_slim_ctrl *dev, u8 *buf);
 int msm_slim_get_ctrl(struct msm_slim_ctrl *dev);
 void msm_slim_put_ctrl(struct msm_slim_ctrl *dev);
+irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat);
 int msm_slim_init_endpoint(struct msm_slim_ctrl *dev, struct msm_slim_endp *ep);
 void msm_slim_free_endpoint(struct msm_slim_endp *ep);
 void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn);
+int msm_alloc_port(struct slim_controller *ctrl, u8 pn);
+void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
 int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
-int msm_config_port(struct slim_controller *ctrl, u8 pn);
 enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
 				u8 pn, u8 **done_buf, u32 *done_len);
 int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index e9f056e..201470f 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1089,8 +1089,11 @@
 		}
 		break;
 	}
-	if (i >= ctrl->nports)
+	if (i >= ctrl->nports) {
 		ret = -EDQUOT;
+		goto alloc_err;
+	}
+	ret = 0;
 	for (j = i; j < i + nphysp; j++) {
 		ctrl->ports[j].state = SLIM_P_UNCFG;
 		ctrl->ports[j].req = req;
@@ -1098,7 +1101,8 @@
 			ctrl->ports[j].flow = SLIM_SINK;
 		else
 			ctrl->ports[j].flow = SLIM_SRC;
-		ret = ctrl->config_port(ctrl, j);
+		if (ctrl->alloc_port)
+			ret = ctrl->alloc_port(ctrl, j);
 		if (ret) {
 			for (; j >= i; j--)
 				ctrl->ports[j].state = SLIM_P_FREE;
@@ -1126,17 +1130,26 @@
 	for (i = 0; i < nports; i++) {
 		u8 pn;
 		pn = SLIM_HDL_TO_PORT(hdl[i]);
-		if (ctrl->ports[pn].state == SLIM_P_CFG) {
-			int j;
-			dev_err(&ctrl->dev, "Can't dealloc connected port:%d",
-					i);
+
+		if (pn >= ctrl->nports || ctrl->ports[pn].state == SLIM_P_CFG) {
+			int j, ret;
+			if (pn >= ctrl->nports) {
+				dev_err(&ctrl->dev, "invalid port number");
+				ret = -EINVAL;
+			} else {
+				dev_err(&ctrl->dev,
+					"Can't dealloc connected port:%d", i);
+				ret = -EISCONN;
+			}
 			for (j = i - 1; j >= 0; j--) {
 				pn = SLIM_HDL_TO_PORT(hdl[j]);
 				ctrl->ports[pn].state = SLIM_P_UNCFG;
 			}
 			mutex_unlock(&ctrl->m_ctrl);
-			return -EISCONN;
+			return ret;
 		}
+		if (ctrl->dealloc_port)
+			ctrl->dealloc_port(ctrl, pn);
 		ctrl->ports[pn].state = SLIM_P_FREE;
 	}
 	mutex_unlock(&ctrl->m_ctrl);
@@ -1215,6 +1228,8 @@
  * Channel specified in chanh needs to be allocated first.
  * Returns -EALREADY if source is already configured for this channel.
  * Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid direction is specified for non-manager port,
+ * or if the manager side port number is out of bounds, or in incorrect state
  */
 int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh)
 {
@@ -1223,12 +1238,23 @@
 	u8 chan = SLIM_HDL_TO_CHIDX(chanh);
 	struct slim_ich *slc = &ctrl->chans[chan];
 	enum slim_port_flow flow = SLIM_HDL_TO_FLOW(srch);
+	u8 la = SLIM_HDL_TO_LA(srch);
 
-	if (flow != SLIM_SRC)
+	/* manager ports don't have direction when they are allocated */
+	if (la != SLIM_LA_MANAGER && flow != SLIM_SRC)
 		return -EINVAL;
 
 	mutex_lock(&ctrl->sched.m_reconf);
 
+	if (la == SLIM_LA_MANAGER) {
+		u8 pn = SLIM_HDL_TO_PORT(srch);
+		if (pn >= ctrl->nports ||
+			ctrl->ports[pn].state != SLIM_P_UNCFG) {
+			ret = -EINVAL;
+			goto connect_src_err;
+		}
+	}
+
 	if (slc->state == SLIM_CH_FREE) {
 		ret = -ENOTCONN;
 		goto connect_src_err;
@@ -1264,6 +1290,9 @@
  * Channel specified in chanh needs to be allocated first.
  * Returns -EALREADY if sink is already configured for this channel.
  * Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid parameters are passed, or invalid direction is
+ * specified for non-manager port, or if the manager side port number is out of
+ * bounds, or in incorrect state
  */
 int slim_connect_sink(struct slim_device *sb, u32 *sinkh, int nsink, u16 chanh)
 {
@@ -1290,8 +1319,14 @@
 
 	for (j = 0; j < nsink; j++) {
 		enum slim_port_flow flow = SLIM_HDL_TO_FLOW(sinkh[j]);
-		if (flow != SLIM_SINK)
+		u8 la = SLIM_HDL_TO_LA(sinkh[j]);
+		u8 pn = SLIM_HDL_TO_PORT(sinkh[j]);
+		if (la != SLIM_LA_MANAGER && flow != SLIM_SINK)
 			ret = -EINVAL;
+		else if (la == SLIM_LA_MANAGER &&
+				(pn >= ctrl->nports ||
+				ctrl->ports[pn].state != SLIM_P_UNCFG))
+				ret = -EINVAL;
 		else
 			ret = connect_port_ch(ctrl, chan, sinkh[j], SLIM_SINK);
 		if (ret) {
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 88074b9..a9c073b 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -69,6 +69,26 @@
 				ULPI_CLR(ULPI_MISC_A));
 }
 
+/* Link power management will reduce power consumption by
+ * short time HW suspend/resume.
+ */
+static void ci13xxx_msm_set_l1(struct ci13xxx *udc)
+{
+	int temp;
+	struct device *dev = udc->gadget.dev.parent;
+
+	dev_dbg(dev, "Enable link power management\n");
+
+	/* Enable remote wakeup and L1 for IN EPs */
+	writel_relaxed(0xffff0000, USB_L1_EP_CTRL);
+
+	temp = readl_relaxed(USB_L1_CONFIG);
+	temp |= L1_CONFIG_LPM_EN | L1_CONFIG_REMOTE_WAKEUP |
+		L1_CONFIG_GATE_SYS_CLK | L1_CONFIG_PHY_LPM |
+		L1_CONFIG_PLL;
+	writel_relaxed(temp, USB_L1_CONFIG);
+}
+
 static void ci13xxx_msm_connect(void)
 {
 	struct ci13xxx *udc = _udc;
@@ -109,6 +129,9 @@
 	writel_relaxed(0, USB_AHBBURST);
 	writel_relaxed(0x08, USB_AHBMODE);
 
+	if (udc->gadget.l1_supported)
+		ci13xxx_msm_set_l1(udc);
+
 	if (phy && (phy->flags & ENABLE_SECONDARY_PHY)) {
 		int	temp;
 
@@ -234,6 +257,7 @@
 	struct resource *res;
 	int ret;
 	struct ci13xxx_platform_data *pdata = pdev->dev.platform_data;
+	bool is_l1_supported = false;
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 
@@ -245,6 +269,8 @@
 		else
 			ci13xxx_msm_udc_driver.nz_itc =
 				1 << (pdata->log2_itc-1);
+
+		is_l1_supported = pdata->l1_supported;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -265,6 +291,8 @@
 		goto iounmap;
 	}
 
+	_udc->gadget.l1_supported = is_l1_supported;
+
 	_udc_ctxt.irq = platform_get_irq(pdev, 0);
 	if (_udc_ctxt.irq < 0) {
 		dev_err(&pdev->dev, "IRQ not found\n");
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index de4a233..27d67e3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -515,7 +515,8 @@
 
 	/*
 	 * A SuperSpeed device shall include the USB2.0 extension descriptor
-	 * and shall support LPM when operating in USB2.0 HS mode.
+	 * and shall support LPM when operating in USB2.0 HS mode, as well as
+	 * a HS device when operating in USB2.1 HS mode.
 	 */
 	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
 	bos->bNumDeviceCaps++;
@@ -525,33 +526,37 @@
 	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
 	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
 
-	/*
-	 * The Superspeed USB Capability descriptor shall be implemented by all
-	 * SuperSpeed devices.
-	 */
-	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
-	bos->bNumDeviceCaps++;
-	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
-	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
-	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
-	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
-	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
-	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
-				USB_FULL_SPEED_OPERATION |
-				USB_HIGH_SPEED_OPERATION |
-				USB_5GBPS_OPERATION);
-	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+	if (gadget_is_superspeed(cdev->gadget)) {
+		/*
+		 * The Superspeed USB Capability descriptor shall be
+		 * implemented by all SuperSpeed devices.
+		 */
+		ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+		bos->bNumDeviceCaps++;
+		le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+		ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+		ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+		ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+		ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+		ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+					USB_FULL_SPEED_OPERATION |
+					USB_HIGH_SPEED_OPERATION |
+					USB_5GBPS_OPERATION);
+		ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
 
-	/* Get Controller configuration */
-	if (cdev->gadget->ops->get_config_params)
-		cdev->gadget->ops->get_config_params(&dcd_config_params);
-	else {
-		dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
-		dcd_config_params.bU2DevExitLat =
-			cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+		/* Get Controller configuration */
+		if (cdev->gadget->ops->get_config_params)
+			cdev->gadget->ops->get_config_params
+				(&dcd_config_params);
+		else {
+			dcd_config_params.bU1devExitLat =
+				USB_DEFAULT_U1_DEV_EXIT_LAT;
+			dcd_config_params.bU2DevExitLat =
+				cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+		}
+		ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+		ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
 	}
-	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
-	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
 
 	return le16_to_cpu(bos->wTotalLength);
 }
@@ -1124,6 +1129,9 @@
 					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
 					DBG(cdev, "Config SS device in HS\n");
 				}
+			} else if (gadget->l1_supported) {
+				cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+				DBG(cdev, "Config HS device with LPM(L1)\n");
 			}
 
 			value = min(w_length, (u16) sizeof cdev->desc);
@@ -1164,7 +1172,8 @@
 				value = min(w_length, (u16) value);
 			break;
 		case USB_DT_BOS:
-			if (gadget_is_superspeed(gadget)) {
+			if (gadget_is_superspeed(gadget) ||
+				gadget->l1_supported) {
 				value = bos_desc(cdev);
 				value = min(w_length, (u16) value);
 			}
@@ -1371,6 +1380,10 @@
 		reset_config(cdev);
 	if (composite->disconnect)
 		composite->disconnect(cdev);
+	if (cdev->delayed_status != 0) {
+		INFO(cdev, "delayed status mismatch..resetting\n");
+		cdev->delayed_status = 0;
+	}
 	spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 022e641..a775459 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -730,11 +730,11 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		teth_bridge_disconnect();
 		ret = usb_bam_disconnect_ipa(&d->ipa_params);
 		if (ret)
 			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
 				__func__, ret);
+		teth_bridge_disconnect();
 	}
 }
 
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index d470edf..3322da5 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -177,13 +177,14 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		if (d->func_type == USB_FUNC_MBIM)
-			teth_bridge_disconnect();
 		if (d->func_type == USB_FUNC_ECM)
 			ecm_ipa_disconnect(d->ipa_params.priv);
 		ret = usb_bam_disconnect_ipa(&d->ipa_params);
 		if (ret)
 			pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
+		if (d->func_type == USB_FUNC_MBIM)
+			teth_bridge_disconnect();
+
 	}
 }
 
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 6727996..60788f5 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -36,6 +36,7 @@
 #include <mach/clk.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
+#include <linux/debugfs.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -896,6 +897,135 @@
 	return 0;
 }
 
+#if defined(CONFIG_DEBUG_FS)
+static u32 addr;
+#define BUF_SIZE	32
+static ssize_t debug_read_phy_data(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct msm_hcd *mhcd = file->private_data;
+	char *kbuf;
+	size_t c = 0;
+	u32 data = 0;
+	int ret = 0;
+
+	kbuf = kzalloc(sizeof(char) * BUF_SIZE, GFP_KERNEL);
+	pm_runtime_get(mhcd->dev);
+	data = msm_ulpi_read(mhcd, addr);
+	pm_runtime_put(mhcd->dev);
+	if (data < 0) {
+		dev_err(mhcd->dev,
+				"%s(): ulpi read timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	c = scnprintf(kbuf, BUF_SIZE, "addr: 0x%x: data: 0x%x\n", addr, data);
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, kbuf, c);
+
+	kfree(kbuf);
+
+	return ret;
+}
+
+static ssize_t debug_write_phy_data(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct msm_hcd *mhcd = file->private_data;
+	char kbuf[10];
+	u32 data = 0;
+
+	memset(kbuf, 0, 10);
+
+	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+		return -EFAULT;
+
+	if (sscanf(kbuf, "%x", &data) != 1)
+		return -EINVAL;
+
+	pm_runtime_get(mhcd->dev);
+	if (msm_ulpi_write(mhcd, data, addr) < 0) {
+		dev_err(mhcd->dev,
+				"%s(): ulpi write timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+	pm_runtime_put(mhcd->dev);
+
+	return count;
+}
+
+static ssize_t debug_phy_write_addr(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	char kbuf[10];
+	u32 temp;
+
+	memset(kbuf, 0, 10);
+
+	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+		return -EFAULT;
+
+	if (sscanf(kbuf, "%x", &temp) != 1)
+		return -EINVAL;
+
+	if (temp > 0x3F)
+		return -EINVAL;
+
+	addr = temp;
+
+	return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_rw_phy_ops = {
+	.open = debug_open,
+	.read = debug_read_phy_data,
+	.write = debug_write_phy_data,
+};
+
+const struct file_operations debug_write_phy_ops = {
+	.open = debug_open,
+	.write = debug_phy_write_addr,
+};
+
+static struct dentry *dent_ehci;
+
+static int ehci_debugfs_init(struct msm_hcd *mhcd)
+{
+	struct dentry *debug_phy_data;
+	struct dentry *debug_phy_addr;
+
+	dent_ehci = debugfs_create_dir(dev_name(mhcd->dev), 0);
+	if (IS_ERR(dent_ehci))
+		return -ENOENT;
+
+	debug_phy_data = debugfs_create_file("phy_reg_data", 0666,
+					dent_ehci, mhcd, &debug_rw_phy_ops);
+	if (!debug_phy_data) {
+		debugfs_remove(dent_ehci);
+		return -ENOENT;
+	}
+
+	debug_phy_addr = debugfs_create_file("phy_reg_addr", 0666,
+					dent_ehci, mhcd, &debug_write_phy_ops);
+	if (!debug_phy_addr) {
+		debugfs_remove_recursive(dent_ehci);
+		return -ENOENT;
+	}
+	return 0;
+}
+#else
+static int ehci_debugfs_init(struct msm_hcd *mhcd)
+{
+	return 0;
+}
+#endif
+
 static struct hc_driver msm_hc2_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Qualcomm EHCI Host Controller",
@@ -1205,6 +1335,9 @@
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
+	if (ehci_debugfs_init(mhcd) < 0)
+		dev_err(mhcd->dev, "%s: debugfs init failed\n", __func__);
+
 	return 0;
 
 vbus_deinit:
@@ -1275,6 +1408,9 @@
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
 
+#if defined(CONFIG_DEBUG_FS)
+	debugfs_remove_recursive(dent_ehci);
+#endif
 	return 0;
 }
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index a074e2d..c0b2771 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -851,6 +851,24 @@
 	return 0;
 }
 
+static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
+{
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	/* Check if target allows min_vote to be same as no_vote */
+	if (vote >= pdata->bus_scale_table->num_usecases)
+		vote = USB_NO_PERF_VOTE;
+
+	if (motg->bus_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+			motg->bus_perf_client, vote);
+		if (ret)
+			dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
+				   "for bus bw %d\n", __func__, vote, ret);
+	}
+}
+
 #define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC	(100 * 1000)
 
@@ -1040,6 +1058,8 @@
 	if (bus)
 		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
 
+	msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+
 	atomic_set(&motg->in_lpm, 1);
 	/* Enable ASYNC IRQ (if present) during LPM */
 	if (motg->async_irq)
@@ -1068,6 +1088,9 @@
 	disable_irq(motg->irq);
 	wake_lock(&motg->wlock);
 
+	/* Some platforms require BUS vote to enable/disable clocks */
+	msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
 	/* Vote for TCXO when waking up the phy */
 	if (motg->lpm_flags & XO_SHUTDOWN) {
 		if (!IS_ERR(motg->xo_clk)) {
@@ -1550,7 +1573,6 @@
 
 static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
 {
-	int ret;
 	struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
 	struct msm_otg_platform_data *pdata = motg->pdata;
 
@@ -1568,29 +1590,18 @@
 			pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
 
 		/* Configure BUS performance parameters for MAX bandwidth */
-		if (motg->bus_perf_client && debug_bus_voting_enabled) {
-			ret = msm_bus_scale_client_update_request(
-					motg->bus_perf_client, 1);
-			if (ret)
-				dev_err(motg->phy.dev, "%s: Failed to vote for "
-					   "bus bandwidth %d\n", __func__, ret);
-		}
+		if (debug_bus_voting_enabled)
+			msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+
 		usb_gadget_vbus_connect(otg->gadget);
 	} else {
 		dev_dbg(otg->phy->dev, "gadget off\n");
 		usb_gadget_vbus_disconnect(otg->gadget);
 		/* Configure BUS performance parameters to default */
-		if (motg->bus_perf_client) {
-			ret = msm_bus_scale_client_update_request(
-					motg->bus_perf_client, 0);
-			if (ret)
-				dev_err(motg->phy.dev, "%s: Failed to devote "
-					   "for bus bw %d\n", __func__, ret);
-		}
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
 		if (pdata->setup_gpio)
 			pdata->setup_gpio(OTG_STATE_UNDEFINED);
 	}
-
 }
 
 static int msm_otg_set_peripheral(struct usb_otg *otg,
@@ -3469,7 +3480,6 @@
 				size_t count, loff_t *ppos)
 {
 	char buf[8];
-	int ret;
 	struct seq_file *s = file->private_data;
 	struct msm_otg *motg = s->private;
 
@@ -3483,13 +3493,7 @@
 		debug_bus_voting_enabled = true;
 	} else {
 		debug_bus_voting_enabled = false;
-		if (motg->bus_perf_client) {
-			ret = msm_bus_scale_client_update_request(
-					motg->bus_perf_client, 0);
-			if (ret)
-				dev_err(motg->phy.dev, "%s: Failed to devote "
-					   "for bus bw %d\n", __func__, ret);
-		}
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
 	}
 
 	return count;
@@ -3712,6 +3716,7 @@
 				ofdev->dev.platform_data;
 		ci_pdata.log2_itc = otg_pdata->log2_itc;
 		ci_pdata.usb_core_id = 0;
+		ci_pdata.l1_supported = otg_pdata->l1_supported;
 		retval = platform_device_add_data(pdev, &ci_pdata,
 			sizeof(ci_pdata));
 		if (retval)
@@ -3843,6 +3848,9 @@
 	if (pdata->pmic_id_irq < 0)
 		pdata->pmic_id_irq = 0;
 
+	pdata->l1_supported = of_property_read_bool(node,
+				"qcom,hsusb-l1-supported");
+
 	return pdata;
 }
 
@@ -3881,17 +3889,17 @@
 		pdata = pdev->dev.platform_data;
 	}
 
-	motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+	motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
 	if (!motg) {
 		dev_err(&pdev->dev, "unable to allocate msm_otg\n");
 		return -ENOMEM;
 	}
 
-	motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+	motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
+							GFP_KERNEL);
 	if (!motg->phy.otg) {
 		dev_err(&pdev->dev, "unable to allocate usb_otg\n");
-		ret = -ENOMEM;
-		goto free_motg;
+		return -ENOMEM;
 	}
 
 	the_msm_otg = motg;
@@ -3899,6 +3907,19 @@
 	phy = &motg->phy;
 	phy->dev = &pdev->dev;
 
+	if (motg->pdata->bus_scale_table) {
+		motg->bus_perf_client =
+		    msm_bus_scale_register_client(motg->pdata->bus_scale_table);
+		if (!motg->bus_perf_client) {
+			dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
+						"scaling client!!\n", __func__);
+		} else {
+			debug_bus_voting_enabled = true;
+			/* Some platforms require BUS vote to control clocks */
+			msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+		}
+	}
+
 	/*
 	 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT.  Hence
 	 * PHY treat ACA ID_GND as float and no interrupt is generated.  But
@@ -3907,7 +3928,7 @@
 	if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
 		dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
 		ret = -EINVAL;
-		goto free_otg;
+		goto devote_bus_bw;
 	}
 
 	/* initialize reset counter */
@@ -4202,16 +4223,6 @@
 		pm_runtime_use_autosuspend(&pdev->dev);
 	}
 
-	if (motg->pdata->bus_scale_table) {
-		motg->bus_perf_client =
-		    msm_bus_scale_register_client(motg->pdata->bus_scale_table);
-		if (!motg->bus_perf_client)
-			dev_err(motg->phy.dev, "%s: Failed to register BUS "
-						"scaling client!!\n", __func__);
-		else
-			debug_bus_voting_enabled = true;
-	}
-
 	motg->usb_psy.name = "usb";
 	motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
 	motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
@@ -4279,10 +4290,12 @@
 		clk_put(motg->clk);
 	if (!IS_ERR(motg->phy_reset_clk))
 		clk_put(motg->phy_reset_clk);
-free_otg:
-	kfree(motg->phy.otg);
-free_motg:
-	kfree(motg);
+devote_bus_bw:
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
+
 	return ret;
 }
 
@@ -4363,11 +4376,11 @@
 		clk_put(motg->clk);
 	clk_put(motg->core_clk);
 
-	if (motg->bus_perf_client)
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
 		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
 
-	kfree(motg->phy.otg);
-	kfree(motg);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index e5b6603..aecb19d 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -826,20 +826,16 @@
 	struct ion_client *iclient = mdp3_res->ion_client;
 	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
 
-	if (!data->srcp_file) {
-		pr_debug("No img to put\n");
-		return 0;
-	}
-	if (data->flags & MDP_BLIT_SRC_GEM) {
-		pr_debug("memory source MDP_BLIT_SRC_GEM\n");
-	} else if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
-		pr_debug("fb mem buf=0x%x\n", data->addr);
+	 if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+		pr_info("mdp3_put_img fb mem buf=0x%x\n", data->addr);
 		fput_light(data->srcp_file, data->p_need);
 		data->srcp_file = NULL;
-	} else {
+	} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
 		ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
 		ion_free(iclient, data->srcp_ihdl);
 		data->srcp_ihdl = NULL;
+	} else {
+		return -EINVAL;
 	}
 	return 0;
 }
@@ -855,16 +851,9 @@
 
 	start = (unsigned long *) &data->addr;
 	len = (unsigned long *) &data->len;
-	data->flags |= img->flags;
+	data->flags = img->flags;
 	data->p_need = 0;
 
-	if (img->flags & MDP_BLIT_SRC_GEM) {
-		data->srcp_file = NULL;
-		ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
-					&data->addr, &data->len);
-		if (!ret)
-			goto done;
-	}
 	if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
 		file = fget_light(img->memory_id, &data->p_need);
 		if (file == NULL) {
@@ -889,8 +878,7 @@
 		data->srcp_file = file;
 		if (!ret)
 			goto done;
-	}
-	if (iclient) {
+	} else if (iclient) {
 		data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
 		if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
 			pr_err("error on ion_import_fd\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 339b888..f43d1ed 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -30,6 +30,8 @@
 
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
 static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
+static int mdp3_histogram_stop(struct mdp3_session_data *session,
+					u32 block);
 
 static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
 {
@@ -495,6 +497,8 @@
 
 	pr_debug("mdp3_ctrl_off stop mdp3 dma engine\n");
 
+	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
+
 	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
 
 	if (rc)
@@ -521,6 +525,7 @@
 
 off_error:
 	mdp3_session->status = 0;
+	mdp3_bufq_deinit(&mdp3_session->bufq_out);
 	mutex_unlock(&mdp3_session->lock);
 	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
 		mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
@@ -572,14 +577,11 @@
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
 
-	mdp3_ctrl_pan_display(mfd);
-
 	mutex_lock(&mdp3_session->lock);
 
 	if (mdp3_session->overlay.id == ndx && ndx == 1) {
 		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 		mdp3_bufq_deinit(&mdp3_session->bufq_in);
-		mdp3_bufq_deinit(&mdp3_session->bufq_out);
 	} else {
 		rc = -EINVAL;
 	}
@@ -661,12 +663,14 @@
 		mdp3_bufq_push(&mdp3_session->bufq_out, data);
 	}
 
-	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
+	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
 		mdp3_put_img(data);
 	}
-
 	mutex_unlock(&mdp3_session->lock);
+
+	mdss_fb_update_notify_update(mfd);
+
 	return rc;
 }
 
@@ -709,7 +713,7 @@
 				mdp3_session->intf);
 	} else {
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
-		mdp3_session->intf->stop(mdp3_session->intf);
+		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
 	}
 pan_error:
 	mutex_unlock(&mdp3_session->lock);
@@ -738,6 +742,288 @@
 	return ret;
 }
 
+static int mdp3_histogram_start(struct mdp3_session_data *session,
+					struct mdp_histogram_start_req *req)
+{
+	int ret;
+	struct mdp3_dma_histogram_config histo_config;
+
+	pr_debug("mdp3_histogram_start\n");
+	if (req->block != MDP_BLOCK_DMA_P ||
+		req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
+		pr_err("mdp3_histogram_start invalid request\n");
+		return -EINVAL;
+	}
+
+	if (!session->dma->histo_op ||
+		!session->dma->config_histo) {
+		pr_err("mdp3_histogram_start not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&session->histo_lock);
+
+	if (session->histo_status) {
+		pr_err("mdp3_histogram_start already started\n");
+		ret = -EBUSY;
+		goto histogram_start_err;
+	}
+
+	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
+	if (ret) {
+		pr_err("mdp3_histogram_start reset error\n");
+		goto histogram_start_err;
+	}
+
+	histo_config.frame_count = req->frame_cnt;
+	histo_config.bit_mask = req->bit_mask;
+	histo_config.auto_clear_en = 1;
+	histo_config.bit_mask_polarity = 0;
+	ret = session->dma->config_histo(session->dma, &histo_config);
+	if (ret) {
+		pr_err("mdp3_histogram_start config error\n");
+		goto histogram_start_err;
+	}
+
+	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_START);
+	if (ret) {
+		pr_err("mdp3_histogram_start config error\n");
+		goto histogram_start_err;
+	}
+
+	session->histo_status = 1;
+
+histogram_start_err:
+	mutex_unlock(&session->histo_lock);
+	return ret;
+}
+
+static int mdp3_histogram_stop(struct mdp3_session_data *session,
+					u32 block)
+{
+	int ret;
+	pr_debug("mdp3_histogram_stop\n");
+
+	if (!session->dma->histo_op || block != MDP_BLOCK_DMA_P) {
+		pr_err("mdp3_histogram_stop not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&session->histo_lock);
+
+	if (!session->histo_status) {
+		ret = 0;
+		goto histogram_stop_err;
+	}
+
+	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
+	if (ret)
+		pr_err("mdp3_histogram_stop error\n");
+
+	session->histo_status = 0;
+
+histogram_stop_err:
+	mutex_unlock(&session->histo_lock);
+	return ret;
+}
+
+static int mdp3_histogram_collect(struct mdp3_session_data *session,
+				struct mdp_histogram_data *hist)
+{
+	int ret;
+	struct mdp3_dma_histogram_data *mdp3_histo;
+
+	if (!session->dma->get_histo) {
+		pr_err("mdp3_histogram_collect not supported\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&session->histo_lock);
+
+	if (!session->histo_status) {
+		pr_err("mdp3_histogram_collect not started\n");
+		mutex_unlock(&session->histo_lock);
+		return -EPERM;
+	}
+
+	mutex_unlock(&session->histo_lock);
+
+	ret = session->dma->get_histo(session->dma);
+	if (ret) {
+		pr_err("mdp3_histogram_collect error = %d\n", ret);
+		return ret;
+	}
+
+	mdp3_histo = &session->dma->histo_data;
+
+	ret = copy_to_user(hist->c0, mdp3_histo->r_data,
+			sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
+	if (ret)
+		return ret;
+
+	ret = copy_to_user(hist->c1, mdp3_histo->g_data,
+			sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
+	if (ret)
+		return ret;
+
+	ret = copy_to_user(hist->c2, mdp3_histo->b_data,
+			sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM);
+	if (ret)
+		return ret;
+
+	ret = copy_to_user(hist->extra_info, mdp3_histo->extra,
+			sizeof(uint32_t) * 2);
+	if (ret)
+		return ret;
+
+	hist->bin_cnt = MDP_HISTOGRAM_BIN_NUM;
+	hist->block = MDP_BLOCK_DMA_P;
+	return ret;
+}
+
+static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd,
+					struct mdp_bl_scale_data *data)
+{
+	int ret = 0;
+	int curr_bl;
+	mutex_lock(&mfd->bl_lock);
+	curr_bl = mfd->bl_level;
+	mfd->bl_scale = data->scale;
+	mfd->bl_min_lvl = data->min_lvl;
+	pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+							mfd->bl_min_lvl);
+
+	/* update current backlight to use new scaling*/
+	mdss_fb_set_backlight(mfd, curr_bl);
+	mutex_unlock(&mfd->bl_lock);
+	return ret;
+}
+
+static int mdp3_pp_ioctl(struct msm_fb_data_type *mfd,
+					void __user *argp)
+{
+	int ret = -EINVAL;
+	struct msmfb_mdp_pp mdp_pp;
+
+	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
+	if (ret)
+		return ret;
+
+	switch (mdp_pp.op) {
+	case mdp_bl_scale_cfg:
+		ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+						&mdp_pp.data.bl_scale_data);
+		break;
+	default:
+		pr_err("Unsupported request to MDP_PP IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	if (!ret)
+		ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
+	return ret;
+}
+
+static int mdp3_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
+				void __user *argp)
+{
+	int ret = -ENOSYS;
+	struct mdp_histogram_data hist;
+	struct mdp_histogram_start_req hist_req;
+	u32 block;
+	struct mdp3_session_data *mdp3_session;
+
+	if (!mfd || !mfd->mdp.private1)
+		return -EINVAL;
+
+	mdp3_session = mfd->mdp.private1;
+
+	switch (cmd) {
+	case MSMFB_HISTOGRAM_START:
+		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+		if (ret)
+			return ret;
+
+		ret = mdp3_histogram_start(mdp3_session, &hist_req);
+		break;
+
+	case MSMFB_HISTOGRAM_STOP:
+		ret = copy_from_user(&block, argp, sizeof(int));
+		if (ret)
+			return ret;
+
+		ret = mdp3_histogram_stop(mdp3_session, block);
+		break;
+
+	case MSMFB_HISTOGRAM:
+		ret = copy_from_user(&hist, argp, sizeof(hist));
+		if (ret)
+			return ret;
+
+		ret = mdp3_histogram_collect(mdp3_session, &hist);
+		if (!ret)
+			ret = copy_to_user(argp, &hist, sizeof(hist));
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int mdp3_ctrl_lut_update(struct msm_fb_data_type *mfd,
+				struct fb_cmap *cmap)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct mdp3_dma_lut_config lut_config;
+	struct mdp3_dma_lut lut;
+	static u16 r[MDP_LUT_SIZE];
+	static u16 g[MDP_LUT_SIZE];
+	static u16 b[MDP_LUT_SIZE];
+
+	if (!mdp3_session->dma->config_lut)
+		return -EINVAL;
+
+	if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+		pr_err("mdp3_ctrl_lut_update invalid arguments\n");
+		return  -EINVAL;
+	}
+
+	rc = copy_from_user(r + cmap->start,
+					cmap->red, sizeof(u16)*cmap->len);
+	rc |= copy_from_user(g + cmap->start,
+					cmap->green, sizeof(u16)*cmap->len);
+	rc |= copy_from_user(b + cmap->start,
+					cmap->blue, sizeof(u16)*cmap->len);
+	if (rc)
+		return rc;
+
+	lut_config.lut_enable = 7;
+	lut_config.lut_sel = mdp3_session->lut_sel;
+	lut_config.lut_position = 0;
+	lut.color0_lut = r;
+	lut.color1_lut = g;
+	lut.color2_lut = b;
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (!mdp3_session->status) {
+		pr_err("%s, display off!\n", __func__);
+		mutex_unlock(&mdp3_session->lock);
+		return -EPERM;
+	}
+
+	rc = mdp3_session->dma->config_lut(mdp3_session->dma, &lut_config,
+					&lut);
+	if (rc)
+		pr_err("mdp3_ctrl_lut_update failed\n");
+
+	mdp3_session->lut_sel = (mdp3_session->lut_sel + 1) % 2;
+
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
 static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
 					u32 cmd, void __user *argp)
 {
@@ -754,10 +1040,19 @@
 
 	if (!mdp3_session->status) {
 		pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
-		return -EINVAL;
+		return -EPERM;
 	}
 
 	switch (cmd) {
+	case MSMFB_MDP_PP:
+		rc = mdp3_pp_ioctl(mfd, argp);
+		break;
+	case MSMFB_HISTOGRAM_START:
+	case MSMFB_HISTOGRAM_STOP:
+	case MSMFB_HISTOGRAM:
+		rc = mdp3_histo_ioctl(mfd, cmd, argp);
+		break;
+
 	case MSMFB_VSYNC_CTRL:
 	case MSMFB_OVERLAY_VSYNC_CTRL:
 		if (!copy_from_user(&val, argp, sizeof(val))) {
@@ -836,6 +1131,7 @@
 	mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
 	mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
 	mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
+	mdp3_interface->lut_update = mdp3_ctrl_lut_update;
 
 	mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
 	if (!mdp3_session) {
@@ -845,6 +1141,7 @@
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
 	INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
+	mutex_init(&mdp3_session->histo_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
 	if (!mdp3_session->dma) {
 		rc = -ENODEV;
@@ -864,6 +1161,8 @@
 	mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 	mdp3_bufq_init(&mdp3_session->bufq_in);
 	mdp3_bufq_init(&mdp3_session->bufq_out);
+	mdp3_session->histo_status = 0;
+	mdp3_session->lut_sel = 0;
 
 	init_timer(&mdp3_session->vsync_timer);
 	mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 0c2b0cd..0bbc2ac 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -47,6 +47,9 @@
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
 	struct work_struct vsync_work;
+	int histo_status;
+	struct mutex histo_lock;
+	int lut_sel;
 };
 
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3a46034..3b65405 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -19,6 +19,10 @@
 
 #define DMA_STOP_POLL_SLEEP_US 1000
 #define DMA_STOP_POLL_TIMEOUT_US 16000
+#define DMA_HISTO_RESET_TIMEOUT_MS 40
+#define DMA_LUT_CONFIG_MASK 0xfffffbe8
+#define DMA_CCS_CONFIG_MASK 0xfffffc17
+#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
 
 static void mdp3_vsync_intr_handler(int type, void *arg)
 {
@@ -45,12 +49,47 @@
 	mdp3_irq_disable_nosync(type);
 }
 
+static void mdp3_hist_done_intr_handler(int type, void *arg)
+{
+	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+	u32 isr, mask;
+
+	isr = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS);
+	mask = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_ENABLE);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_CLEAR, isr);
+
+	isr &= mask;
+	if (isr == 0)
+		return;
+
+	if (isr & MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT) {
+		spin_lock(&dma->histo_lock);
+		dma->histo_state = MDP3_DMA_HISTO_STATE_READY;
+		complete(&dma->histo_comp);
+		spin_unlock(&dma->histo_lock);
+	}
+	if (isr & MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT) {
+		spin_lock(&dma->histo_lock);
+		dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+		complete(&dma->histo_comp);
+		spin_unlock(&dma->histo_lock);
+	}
+}
+
 void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type)
 {
 	int irq_bit;
 
 	pr_debug("mdp3_dma_callback_enable type=%d\n", type);
 
+	if (dma->dma_sel == MDP3_DMA_P) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE)
+			mdp3_irq_enable(MDP3_INTR_DMA_P_HISTO);
+
+		if (type & MDP3_DMA_CALLBACK_TYPE_HIST_DONE)
+			mdp3_irq_enable(MDP3_INTR_DMA_P_HISTO);
+	}
+
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
 		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
 		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
@@ -79,6 +118,14 @@
 
 	pr_debug("mdp3_dma_callback_disable type=%d\n", type);
 
+	if (dma->dma_sel == MDP3_DMA_P) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE)
+			mdp3_irq_disable(MDP3_INTR_DMA_P_HISTO);
+
+		if (type & MDP3_DMA_CALLBACK_TYPE_HIST_DONE)
+			mdp3_irq_disable(MDP3_INTR_DMA_P_HISTO);
+	}
+
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
 		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
 		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
@@ -101,7 +148,7 @@
 
 static int mdp3_dma_callback_setup(struct mdp3_dma *dma)
 {
-	int rc;
+	int rc = 0;
 	struct mdp3_intr_cb vsync_cb = {
 		.cb = mdp3_vsync_intr_handler,
 		.data = dma,
@@ -112,14 +159,22 @@
 		.data = dma,
 	};
 
+	struct mdp3_intr_cb hist_cb = {
+		.cb = mdp3_hist_done_intr_handler,
+		.data = dma,
+	};
+
+	if (dma->dma_sel == MDP3_DMA_P)
+		rc = mdp3_set_intr_callback(MDP3_INTR_DMA_P_HISTO, &hist_cb);
+
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
 		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC)
-		rc = mdp3_set_intr_callback(MDP3_INTR_LCDC_START_OF_FRAME,
+		rc |= mdp3_set_intr_callback(MDP3_INTR_LCDC_START_OF_FRAME,
 					&vsync_cb);
 	else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
 		int irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE;
 		irq_bit += dma->dma_sel;
-		rc = mdp3_set_intr_callback(irq_bit, &vsync_cb);
+		rc |= mdp3_set_intr_callback(irq_bit, &vsync_cb);
 		irq_bit = MDP3_INTR_DMA_P_DONE;
 		if (dma->dma_sel == MDP3_DMA_S)
 			irq_bit = MDP3_INTR_DMA_S_DONE;
@@ -128,6 +183,7 @@
 		pr_err("mdp3_dma_callback_setup not suppported interface\n");
 		rc = -ENODEV;
 	}
+
 	return rc;
 }
 
@@ -291,24 +347,54 @@
 	return 0;
 }
 
-static int mdp3_dmap_ccs_config(struct mdp3_dma *dma,
-			struct mdp3_dma_color_correct_config *config,
-			struct mdp3_dma_ccs *ccs,
+static int mdp3_dmap_lut_config(struct mdp3_dma *dma,
+			struct mdp3_dma_lut_config *config,
 			struct mdp3_dma_lut *lut)
 {
+	u32 cc_config, addr, color;
 	int i;
-	u32 addr, cc_config, color;
 
-	cc_config = config->lut_enable;
-	if (config->ccs_enable)
-		cc_config |= BIT(3);
+	if (config->lut_enable && lut) {
+		addr = MDP3_REG_DMA_P_CSC_LUT1;
+		if (config->lut_sel)
+			addr = MDP3_REG_DMA_P_CSC_LUT2;
+
+		for (i = 0; i < MDP_LUT_SIZE; i++) {
+			color = lut->color0_lut[i] & 0xff;
+			color |= (lut->color1_lut[i] & 0xff) << 8;
+			color |= (lut->color2_lut[i] & 0xff) << 16;
+			MDP3_REG_WRITE(addr, color);
+			addr += 4;
+		}
+	}
+
+	cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG);
+	cc_config &= DMA_LUT_CONFIG_MASK;
+	cc_config |= config->lut_enable;
 	cc_config |= config->lut_position << 4;
+	cc_config |= config->lut_sel << 10;
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
+	wmb();
+
+	dma->lut_config = *config;
+	return 0;
+}
+
+static int mdp3_dmap_ccs_config(struct mdp3_dma *dma,
+			struct mdp3_dma_color_correct_config *config,
+			struct mdp3_dma_ccs *ccs)
+{
+	int i;
+	u32 cc_config, addr;
+
+	cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG);
+	cc_config &= DMA_CCS_CONFIG_MASK;
+	cc_config |= BIT(3);
 	cc_config |= config->ccs_sel << 5;
 	cc_config |= config->pre_bias_sel << 6;
 	cc_config |= config->post_bias_sel << 7;
 	cc_config |= config->pre_limit_sel << 8;
 	cc_config |= config->post_limit_sel << 9;
-	cc_config |= config->lut_sel << 10;
 
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
 
@@ -394,30 +480,6 @@
 		}
 	}
 
-	if (config->lut_enable && lut) {
-		if (lut->color0_lut1 && lut->color1_lut1 && lut->color2_lut1) {
-			addr = MDP3_REG_DMA_P_CSC_LUT1;
-			for (i = 0; i < 256; i++) {
-				color = lut->color0_lut1[i];
-				color |= lut->color1_lut1[i] << 8;
-				color |= lut->color2_lut1[i] << 16;
-				MDP3_REG_WRITE(addr, color);
-				addr += 4;
-			}
-		}
-
-		if (lut->color0_lut2 && lut->color1_lut2 && lut->color2_lut2) {
-			addr = MDP3_REG_DMA_P_CSC_LUT2;
-			for (i = 0; i < 256; i++) {
-				color = lut->color0_lut2[i];
-				color |= lut->color1_lut2[i] << 8;
-				color |= lut->color2_lut2[i] << 16;
-				MDP3_REG_WRITE(addr, color);
-				addr += 4;
-			}
-		}
-	}
-
 	dma->ccs_config = *config;
 	return 0;
 }
@@ -425,18 +487,28 @@
 static int mdp3_dmap_histo_config(struct mdp3_dma *dma,
 			struct mdp3_dma_histogram_config *histo_config)
 {
-	u32 hist_bit_mask, hist_control;
+	unsigned long flag;
+	u32 histo_bit_mask, histo_control;
+	u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT |
+			MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT;
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
 
 	if (histo_config->bit_mask_polarity)
-		hist_bit_mask = BIT(31);
-	hist_bit_mask |= histo_config->bit_mask;
+		histo_bit_mask = BIT(31);
+	histo_bit_mask |= histo_config->bit_mask;
 
 	if (histo_config->auto_clear_en)
-		hist_control = BIT(0);
+		histo_control = BIT(0);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_FRAME_CNT,
 			histo_config->frame_count);
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_BIT_MASK, hist_bit_mask);
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CONTROL, hist_control);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_BIT_MASK, histo_bit_mask);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CONTROL, histo_control);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, histo_isr_mask);
+
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	dma->histogram_config = *histo_config;
 	return 0;
 }
 
@@ -518,78 +590,174 @@
 	return 0;
 }
 
-static int mdp3_dmap_histo_get(struct mdp3_dma *dma,
-			struct mdp3_dma_histogram_data *data)
+static int mdp3_dmap_histo_get(struct mdp3_dma *dma)
 {
-	int i;
-	u32 addr, extra;
+	int i, state, timeout, ret;
+	u32 addr;
+	unsigned long flag;
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
+	state = dma->histo_state;
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	if (state != MDP3_DMA_HISTO_STATE_START &&
+		state != MDP3_DMA_HISTO_STATE_READY) {
+		pr_err("mdp3_dmap_histo_get invalid state %d\n", state);
+		return -EINVAL;
+	}
+
+	timeout = HIST_WAIT_TIMEOUT(dma->histogram_config.frame_count);
+	ret = wait_for_completion_killable_timeout(&dma->histo_comp, timeout);
+
+	if (ret == 0) {
+		pr_err("mdp3_dmap_histo_get time out\n");
+		ret = -ETIMEDOUT;
+	} else if (ret < 0) {
+		pr_err("mdp3_dmap_histo_get interrupted\n");
+	}
+
+	if (ret < 0)
+		return ret;
+
+	if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) {
+		pr_err("mdp3_dmap_histo_get after dma shut down\n");
+		return -EPERM;
+	}
 
 	addr = MDP3_REG_DMA_P_HIST_R_DATA;
-	for (i = 0; i < 32; i++) {
-		data->r_data[i] = MDP3_REG_READ(addr);
+	for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) {
+		dma->histo_data.r_data[i] = MDP3_REG_READ(addr);
 		addr += 4;
 	}
 
 	addr = MDP3_REG_DMA_P_HIST_G_DATA;
-	for (i = 0; i < 32; i++) {
-		data->g_data[i] = MDP3_REG_READ(addr);
+	for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) {
+		dma->histo_data.g_data[i] = MDP3_REG_READ(addr);
 		addr += 4;
 	}
 
 	addr = MDP3_REG_DMA_P_HIST_B_DATA;
-	for (i = 0; i < 32; i++) {
-		data->b_data[i] = MDP3_REG_READ(addr);
+	for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) {
+		dma->histo_data.b_data[i] = MDP3_REG_READ(addr);
 		addr += 4;
 	}
 
-	extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0);
-	data->r_min_value = (extra & 0x1F0000) >> 16;
-	data->r_max_value = (extra & 0x1F000000) >> 24;
-	extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1);
-	data->g_min_value = extra & 0x1F;
-	data->g_max_value = (extra & 0x1F00) >> 8;
-	data->b_min_value = (extra & 0x1F0000) >> 16;
-	data->b_max_value = (extra & 0x1F000000) >> 24;
+	dma->histo_data.extra[0] =
+			MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0);
+	dma->histo_data.extra[1] =
+			MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1);
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
+	init_completion(&dma->histo_comp);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
+	wmb();
+	dma->histo_state = MDP3_DMA_HISTO_STATE_START;
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	return 0;
+}
+
+static int mdp3_dmap_histo_start(struct mdp3_dma *dma)
+{
+	unsigned long flag;
+
+	if (dma->histo_state != MDP3_DMA_HISTO_STATE_IDLE)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
+
+	init_completion(&dma->histo_comp);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
+	wmb();
+	dma->histo_state = MDP3_DMA_HISTO_STATE_START;
+
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	mdp3_dma_callback_enable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_DONE);
+	return 0;
+
+}
+
+static int mdp3_dmap_histo_reset(struct mdp3_dma *dma)
+{
+	unsigned long flag;
+	int ret;
+	u32 cgc;
+
+	if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
+
+	init_completion(&dma->histo_comp);
+	cgc = MDP3_REG_READ(MDP3_REG_CGC_EN);
+	cgc &= ~BIT(10);
+	MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, BIT(0)|BIT(1));
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1);
+	wmb();
+	dma->histo_state = MDP3_DMA_HISTO_STATE_RESET;
+
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	mdp3_dma_callback_enable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE);
+	ret = wait_for_completion_killable_timeout(&dma->histo_comp,
+				msecs_to_jiffies(DMA_HISTO_RESET_TIMEOUT_MS));
+
+	if (ret == 0) {
+		pr_err("mdp3_dmap_histo_reset time out\n");
+		ret = -ETIMEDOUT;
+	} else if (ret < 0) {
+		pr_err("mdp3_dmap_histo_reset interrupted\n");
+	} else {
+		ret = 0;
+	}
+	mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE);
+	cgc |= BIT(10);
+	MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+
+	return ret;
+}
+
+static int mdp3_dmap_histo_stop(struct mdp3_dma *dma)
+{
+	unsigned long flag;
+	int cb_type = MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE |
+			MDP3_DMA_CALLBACK_TYPE_HIST_DONE;
+
+	spin_lock_irqsave(&dma->histo_lock, flag);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CANCEL_REQ, 1);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, 0);
+	wmb();
+	dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+
+	spin_unlock_irqrestore(&dma->histo_lock, flag);
+
+	mdp3_dma_callback_disable(dma, cb_type);
 	return 0;
 }
 
 static int mdp3_dmap_histo_op(struct mdp3_dma *dma, u32 op)
 {
+	int ret;
+
 	switch (op) {
 	case MDP3_DMA_HISTO_OP_START:
-		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
+		ret = mdp3_dmap_histo_start(dma);
 		break;
 	case MDP3_DMA_HISTO_OP_STOP:
-		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_STOP_REQ, 1);
-		break;
 	case MDP3_DMA_HISTO_OP_CANCEL:
-		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CANCEL_REQ, 1);
+		ret = mdp3_dmap_histo_stop(dma);
 		break;
 	case MDP3_DMA_HISTO_OP_RESET:
-		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1);
+		ret = mdp3_dmap_histo_reset(dma);
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-	return 0;
-}
-
-static int mdp3_dmap_histo_intr_status(struct mdp3_dma *dma, int *status)
-{
-	*status = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS);
-	return 0;
-}
-
-static int mdp3_dmap_histo_intr_enable(struct mdp3_dma *dma, u32 mask)
-{
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, mask);
-	return 0;
-}
-
-static int mdp3_dmap_histo_intr_clear(struct mdp3_dma *dma, u32 mask)
-{
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_CLEAR, mask);
-	return 0;
+	return ret;
 }
 
 static int mdp3_dma_start(struct mdp3_dma *dma, struct mdp3_intf *intf)
@@ -648,6 +816,7 @@
 	mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC |
 					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
 
+	init_completion(&dma->dma_comp);
 	return ret;
 }
 
@@ -667,13 +836,11 @@
 		dma->config_cursor = mdp3_dmap_cursor_config;
 		dma->config_ccs = mdp3_dmap_ccs_config;
 		dma->config_histo = mdp3_dmap_histo_config;
+		dma->config_lut = mdp3_dmap_lut_config;
 		dma->update = mdp3_dmap_update;
 		dma->update_cursor = mdp3_dmap_cursor_update;
 		dma->get_histo = mdp3_dmap_histo_get;
 		dma->histo_op = mdp3_dmap_histo_op;
-		dma->histo_intr_status = mdp3_dmap_histo_intr_status;
-		dma->histo_intr_enable = mdp3_dmap_histo_intr_enable;
-		dma->histo_intr_clear = mdp3_dmap_histo_intr_clear;
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
@@ -686,13 +853,11 @@
 		dma->config_cursor = NULL;
 		dma->config_ccs = NULL;
 		dma->config_histo = NULL;
+		dma->config_lut = NULL;
 		dma->update = mdp3_dmas_update;
 		dma->update_cursor = NULL;
 		dma->get_histo = NULL;
 		dma->histo_op = NULL;
-		dma->histo_intr_status = NULL;
-		dma->histo_intr_enable = NULL;
-		dma->histo_intr_clear = NULL;
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
@@ -704,10 +869,13 @@
 	}
 
 	spin_lock_init(&dma->dma_lock);
+	spin_lock_init(&dma->histo_lock);
 	init_completion(&dma->vsync_comp);
 	init_completion(&dma->dma_comp);
+	init_completion(&dma->histo_comp);
 	dma->vsync_client.handler = NULL;
 	dma->vsync_client.arg = NULL;
+	dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
 
 	memset(&dma->cursor, 0, sizeof(dma->cursor));
 	memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index c7b5f25..518bd58 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -16,6 +16,9 @@
 
 #include <linux/sched.h>
 
+#define MDP_HISTOGRAM_BIN_NUM	32
+#define MDP_LUT_SIZE 256
+
 enum {
 	MDP3_DMA_P,
 	MDP3_DMA_S,
@@ -119,8 +122,18 @@
 };
 
 enum {
+	MDP3_DMA_HISTO_STATE_UNKNOWN,
+	MDP3_DMA_HISTO_STATE_IDLE,
+	MDP3_DMA_HISTO_STATE_RESET,
+	MDP3_DMA_HISTO_STATE_START,
+	MDP3_DMA_HISTO_STATE_READY,
+};
+
+enum {
 	MDP3_DMA_CALLBACK_TYPE_VSYNC = 0x01,
 	MDP3_DMA_CALLBACK_TYPE_DMA_DONE = 0x02,
+	MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE = 0x04,
+	MDP3_DMA_CALLBACK_TYPE_HIST_DONE = 0x08,
 };
 
 struct mdp3_dma_source {
@@ -176,24 +189,24 @@
 };
 
 struct mdp3_dma_lut {
-	uint8_t *color0_lut1;
-	uint8_t *color1_lut1;
-	uint8_t *color2_lut1;
-	uint8_t *color0_lut2;
-	uint8_t *color1_lut2;
-	uint8_t *color2_lut2;
+	u16 *color0_lut;
+	u16 *color1_lut;
+	u16 *color2_lut;
+};
+
+struct mdp3_dma_lut_config {
+	int lut_enable;
+	u32 lut_sel;
+	u32 lut_position;
 };
 
 struct mdp3_dma_color_correct_config {
 	int ccs_enable;
-	int lut_enable;
-	u32 lut_sel;
 	u32 post_limit_sel;
 	u32 pre_limit_sel;
 	u32 post_bias_sel;
 	u32 pre_bias_sel;
 	u32 ccs_sel;
-	u32 lut_position;
 };
 
 struct mdp3_dma_histogram_config {
@@ -204,15 +217,10 @@
 };
 
 struct mdp3_dma_histogram_data {
-	uint8_t r_max_value;
-	uint8_t r_min_value;
-	uint8_t b_max_value;
-	uint8_t b_min_value;
-	uint8_t g_max_value;
-	uint8_t g_min_value;
-	uint8_t r_data[32];
-	uint8_t g_data[32];
-	uint8_t b_data[32];
+	u32 r_data[MDP_HISTOGRAM_BIN_NUM];
+	u32 g_data[MDP_HISTOGRAM_BIN_NUM];
+	u32 b_data[MDP_HISTOGRAM_BIN_NUM];
+	u32 extra[2];
 };
 
 struct mdp3_vsync_notification {
@@ -229,8 +237,10 @@
 	int available;
 
 	spinlock_t dma_lock;
+	spinlock_t histo_lock;
 	struct completion vsync_comp;
 	struct completion dma_comp;
+	struct completion histo_comp;
 	struct mdp3_vsync_notification vsync_client;
 
 	struct mdp3_dma_output_config output_config;
@@ -238,7 +248,10 @@
 
 	struct mdp3_dma_cursor cursor;
 	struct mdp3_dma_color_correct_config ccs_config;
+	struct mdp3_dma_lut_config lut_config;
 	struct mdp3_dma_histogram_config histogram_config;
+	int histo_state;
+	struct mdp3_dma_histogram_data histo_data;
 
 	int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
 
@@ -249,27 +262,22 @@
 
 	int (*config_ccs)(struct mdp3_dma *dma,
 			struct mdp3_dma_color_correct_config *config,
-			struct mdp3_dma_ccs *ccs,
+			struct mdp3_dma_ccs *ccs);
+
+	int (*config_lut)(struct mdp3_dma *dma,
+			struct mdp3_dma_lut_config *config,
 			struct mdp3_dma_lut *lut);
 
 	int (*update)(struct mdp3_dma *dma, void *buf, struct mdp3_intf *intf);
 
 	int (*update_cursor)(struct mdp3_dma *dma, int x, int y);
 
-	int (*get_histo)(struct mdp3_dma *dma,
-				struct mdp3_dma_histogram_data *data);
+	int (*get_histo)(struct mdp3_dma *dma);
 
 	int (*config_histo)(struct mdp3_dma *dma,
 				struct mdp3_dma_histogram_config *histo_config);
 
-	int (*histo_op)(struct mdp3_dma *dma,
-				u32 op);
-
-	int (*histo_intr_status)(struct mdp3_dma *dma, int *status);
-
-	int (*histo_intr_enable)(struct mdp3_dma *dma, u32 mask);
-
-	int (*histo_intr_clear)(struct mdp3_dma *dma, u32 mask);
+	int (*histo_op)(struct mdp3_dma *dma, u32 op);
 
 	void (*vsync_enable)(struct mdp3_dma *dma,
 			struct mdp3_vsync_notification *vsync_client);
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index f10206f..4afa37c 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -60,6 +60,9 @@
 #define MDP3_REG_EBI2_LCD0				0x003c
 #define MDP3_REG_EBI2_LCD0_YSTRIDE			0x0050
 
+/*clock control*/
+#define MDP3_REG_CGC_EN					0x0100
+
 /*DMA_P*/
 #define MDP3_REG_DMA_P_CONFIG				0x90000
 #define MDP3_REG_DMA_P_SIZE				0x90004
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 72e3c64..60b8b2e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1638,7 +1638,7 @@
 
 	if (status) {
 		MIPI_OUTP(base + 0x0068, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -1649,7 +1649,7 @@
 	status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
 	if (status & 0x0111) {
 		MIPI_OUTP(base + 0x00c0, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -1661,7 +1661,7 @@
 
 	if (status & 0x011111) {
 		MIPI_OUTP(base + 0x00b4, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -1673,7 +1673,7 @@
 
 	if (status & 0x44444489) {
 		MIPI_OUTP(base + 0x000c, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -1685,7 +1685,7 @@
 
 	if (status & 0x80000000) {
 		MIPI_OUTP(base + 0x0008, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index ab4ae4b..52224e2 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -312,6 +312,8 @@
 	u8 vert_deci;
 	struct mdss_mdp_img_rect src;
 	struct mdss_mdp_img_rect dst;
+	u32 phase_step_x;
+	u32 phase_step_y;
 
 	struct mdss_mdp_format_params *src_fmt;
 	struct mdss_mdp_plane_sizes src_planes;
@@ -545,6 +547,7 @@
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
 u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
+int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase);
 
 int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 741c7a7..4779d20 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -340,6 +340,7 @@
 #define MDSS_MDP_REG_WB_DST_MATRIX_ROW1			0x034
 #define MDSS_MDP_REG_WB_DST_MATRIX_ROW2			0x038
 #define MDSS_MDP_REG_WB_DST_MATRIX_ROW3			0x03C
+#define MDSS_MDP_REG_WB_DST_WRITE_CONFIG		0x048
 #define MDSS_MDP_REG_WB_ROTATION_DNSCALER		0x050
 #define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C03		0x060
 #define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C12		0x064
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 503d8e2..b7fe1bd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -205,6 +205,7 @@
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_YSTRIDE0, ystride0);
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_YSTRIDE1, ystride1);
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_OUT_SIZE, outsize);
+	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_WRITE_CONFIG, 0x58);
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 74e42dd..a78a10a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -180,6 +180,11 @@
 				pr_err("BWC: unequal src img and rect w,h\n");
 				return -EINVAL;
 			}
+
+			if (req->flags & MDP_DECIMATION_EN) {
+				pr_err("Can't enable BWC decode && decimate\n");
+				return -EINVAL;
+			}
 		}
 
 		if (req->flags & MDP_DEINTERLACE) {
@@ -315,6 +320,30 @@
 	return 0;
 }
 
+static int __mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe)
+{
+	u32 src;
+	int rc;
+
+	src = pipe->src.w >> pipe->horz_deci;
+	rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+	if (rc) {
+		pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
+				rc, src, pipe->dst.w);
+		return rc;
+	}
+
+	src = pipe->src.h >> pipe->vert_deci;
+	rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+	if (rc) {
+		pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
+				rc, src, pipe->dst.h);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
 				       struct mdp_overlay *req,
 				       struct mdss_mdp_pipe **ppipe)
@@ -535,6 +564,10 @@
 		goto exit_fail;
 	}
 
+	ret = __mdss_mdp_overlay_setup_scaling(pipe);
+	if (ret)
+		goto exit_fail;
+
 	ret = mdss_mdp_smp_reserve(pipe);
 	if (ret) {
 		pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -1939,6 +1972,7 @@
 	if (!mdp5_data->ctl->power_on)
 		return 0;
 
+	mdss_mdp_overlay_free_fb_pipe(mfd);
 	if (!mfd->ref_cnt) {
 		mdss_mdp_overlay_release_all(mfd);
 	} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 963d3fb..75b6056 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -607,39 +607,6 @@
 	return 0;
 }
 
-static int mdss_mdp_leading_zero(u32 num)
-{
-	u32 bit = 0x80000000;
-	int i;
-
-	for (i = 0; i < 32; i++) {
-		if (bit & num)
-			return i;
-		bit >>= 1;
-	}
-
-	return i;
-}
-
-static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
-{
-	u32 val, s;
-	int n;
-
-	n = mdss_mdp_leading_zero(src);
-	if (n > f_num)
-		n = f_num;
-	s = src << n;	/* maximum to reduce lose of resolution */
-	val = s / dst;
-	if (n < f_num) {
-		n = f_num - n;
-		val <<= n;
-		val |= ((s % dst) << n) / dst;
-	}
-
-	return val;
-}
-
 static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
 {
 	u32 scale_config = 0;
@@ -705,13 +672,14 @@
 		}
 
 		scale_config |= MDSS_MDP_SCALEY_EN;
+		phasey_step = pipe->phase_step_y;
 
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
-			u32 chr_dst_h = pipe->dst.h;
+			u32 chroma_shift = 0;
 			if (!pipe->vert_deci &&
 			    ((chroma_sample == MDSS_MDP_CHROMA_420) ||
 			    (chroma_sample == MDSS_MDP_CHROMA_H1V2)))
-				chr_dst_h *= 2;	/* 2x upsample chroma */
+				chroma_shift = 1; /* 2x upsample chroma */
 
 			if (src_h <= pipe->dst.h) {
 				scale_config |= /* G/Y, A */
@@ -722,17 +690,14 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
 
-			if (src_h <= chr_dst_h)
+			if ((src_h >> chroma_shift) <= pipe->dst.h)
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_BIL << 14);
 			else
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 14);
 
-			phasey_step = mdss_mdp_scale_phase_step(
-				PHASE_STEP_SHIFT, src_h, chr_dst_h);
-
-			writel_relaxed(phasey_step, pipe->base +
+			writel_relaxed(phasey_step >> chroma_shift, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
 		} else {
 			if (src_h <= pipe->dst.h)
@@ -744,9 +709,6 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
 		}
-
-		phasey_step = mdss_mdp_scale_phase_step(
-			PHASE_STEP_SHIFT, src_h, pipe->dst.h);
 	}
 
 	if ((src_w != pipe->dst.w) ||
@@ -762,14 +724,15 @@
 		}
 
 		scale_config |= MDSS_MDP_SCALEX_EN;
+		phasex_step = pipe->phase_step_x;
 
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
-			u32 chr_dst_w = pipe->dst.w;
+			u32 chroma_shift = 0;
 
 			if (!pipe->horz_deci &&
 			    ((chroma_sample == MDSS_MDP_CHROMA_420) ||
 			    (chroma_sample == MDSS_MDP_CHROMA_H2V1)))
-				chr_dst_w *= 2;	/* 2x upsample chroma */
+				chroma_shift = 1; /* 2x upsample chroma */
 
 			if (src_w <= pipe->dst.w) {
 				scale_config |= /* G/Y, A */
@@ -780,16 +743,14 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
 
-			if (src_w <= chr_dst_w)
+			if ((src_w >> chroma_shift) <= pipe->dst.w)
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_BIL << 12);
 			else
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 12);
 
-			phasex_step = mdss_mdp_scale_phase_step(
-				PHASE_STEP_SHIFT, src_w, chr_dst_w);
-			writel_relaxed(phasex_step, pipe->base +
+			writel_relaxed(phasex_step >> chroma_shift, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
 		} else {
 			if (src_w <= pipe->dst.w)
@@ -801,9 +762,6 @@
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
 		}
-
-		phasex_step = mdss_mdp_scale_phase_step(
-			PHASE_STEP_SHIFT, src_w, pipe->dst.w);
 	}
 
 	writel_relaxed(scale_config, pipe->base +
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b29b0eb..c7beb0e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -561,3 +561,23 @@
 
 	return ret;
 }
+
+int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase)
+{
+	u32 unit, residue;
+
+	if (dst == 0)
+		return -EINVAL;
+
+	unit = 1 << PHASE_STEP_SHIFT;
+	*out_phase = mult_frac(src, unit, dst);
+
+	/* check if overflow is possible */
+	if (src > dst) {
+		residue = *out_phase & (unit - 1);
+		if (residue && ((residue * dst) < (unit - residue)))
+			return -EOVERFLOW;
+	}
+
+	return 0;
+}
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 51a90b7..ee1c2ff 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -22,8 +22,9 @@
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *mask,
-			bool sync);
+			bool sync, bool *contended);
 extern int compact_pgdat(pg_data_t *pgdat, int order);
+extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
 
 /* Do not skip compaction more than 64 times */
@@ -61,10 +62,20 @@
 	return zone->compact_considered < (1UL << zone->compact_defer_shift);
 }
 
+/* Returns true if restarting compaction after many failures */
+static inline bool compaction_restarting(struct zone *zone, int order)
+{
+	if (order < zone->compact_order_failed)
+		return false;
+
+	return zone->compact_defer_shift == COMPACT_MAX_DEFER_SHIFT &&
+		zone->compact_considered >= 1UL << zone->compact_defer_shift;
+}
+
 #else
 static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *nodemask,
-			bool sync)
+			bool sync, bool *contended)
 {
 	return COMPACT_CONTINUE;
 }
@@ -74,6 +85,10 @@
 	return COMPACT_CONTINUE;
 }
 
+static inline void reset_isolation_suitable(pg_data_t *pgdat)
+{
+}
+
 static inline unsigned long compaction_suitable(struct zone *zone, int order)
 {
 	return COMPACT_SKIPPED;
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index f94efd2..14d38a5 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -66,7 +66,6 @@
 struct lruvec *mem_cgroup_lru_add_list(struct zone *, struct page *,
 				       enum lru_list);
 void mem_cgroup_lru_del_list(struct page *, enum lru_list);
-void mem_cgroup_lru_del(struct page *);
 struct lruvec *mem_cgroup_lru_move_lists(struct zone *, struct page *,
 					 enum lru_list, enum lru_list);
 
@@ -79,6 +78,8 @@
 
 extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
 				     int order);
+bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+				  struct mem_cgroup *memcg);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
 
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
@@ -92,10 +93,13 @@
 int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
 {
 	struct mem_cgroup *memcg;
+	int match;
+
 	rcu_read_lock();
 	memcg = mem_cgroup_from_task(rcu_dereference((mm)->owner));
+	match = __mem_cgroup_same_or_subtree(cgroup, memcg);
 	rcu_read_unlock();
-	return cgroup == memcg;
+	return match;
 }
 
 extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg);
@@ -262,10 +266,6 @@
 {
 }
 
-static inline void mem_cgroup_lru_del(struct page *page)
-{
-}
-
 static inline struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
 						       struct page *page,
 						       enum lru_list from,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3cc3062..b98b4b9 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -344,17 +344,6 @@
 	/* Architecture-specific MM context */
 	mm_context_t context;
 
-	/* Swap token stuff */
-	/*
-	 * Last value of global fault stamp as seen by this process.
-	 * In other words, this value gives an indication of how long
-	 * it has been since this task got the token.
-	 * Look at mm/thrash.c
-	 */
-	unsigned int faultstamp;
-	unsigned int token_priority;
-	unsigned int last_interval;
-
 	unsigned long flags; /* Must use atomic bitops to access the bits */
 
 	struct core_state *core_state; /* coredumping support */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index d63232a..7539e03 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -204,16 +204,14 @@
 #define LRU_ALL_EVICTABLE (LRU_ALL_FILE | LRU_ALL_ANON)
 #define LRU_ALL	     ((1 << NR_LRU_LISTS) - 1)
 
-/* Isolate inactive pages */
-#define ISOLATE_INACTIVE	((__force isolate_mode_t)0x1)
-/* Isolate active pages */
-#define ISOLATE_ACTIVE		((__force isolate_mode_t)0x2)
 /* Isolate clean file */
-#define ISOLATE_CLEAN		((__force isolate_mode_t)0x4)
+#define ISOLATE_CLEAN		((__force isolate_mode_t)0x1)
 /* Isolate unmapped file */
-#define ISOLATE_UNMAPPED	((__force isolate_mode_t)0x8)
+#define ISOLATE_UNMAPPED	((__force isolate_mode_t)0x2)
 /* Isolate for asynchronous migration */
-#define ISOLATE_ASYNC_MIGRATE	((__force isolate_mode_t)0x10)
+#define ISOLATE_ASYNC_MIGRATE	((__force isolate_mode_t)0x4)
+/* Isolate unevictable pages */
+#define ISOLATE_UNEVICTABLE	((__force isolate_mode_t)0x8)
 
 /* LRU Isolation modes. */
 typedef unsigned __bitwise__ isolate_mode_t;
@@ -378,6 +376,14 @@
 	 */
 	spinlock_t		lock;
 	int                     all_unreclaimable; /* All pages pinned */
+#if defined CONFIG_COMPACTION || defined CONFIG_CMA
+	/* Set to true when the PG_migrate_skip bits should be cleared */
+	bool			compact_blockskip_flush;
+
+	/* pfns where compaction scanners should start */
+	unsigned long		compact_cached_free_pfn;
+	unsigned long		compact_cached_migrate_pfn;
+#endif
 #ifdef CONFIG_MEMORY_HOTPLUG
 	/* see spanned/present_pages for more description */
 	seqlock_t		span_seqlock;
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 5151654..b2229d3 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -87,6 +87,7 @@
 #define IPA_FLT_NEXT_HDR       (1ul << 13)
 #define IPA_FLT_META_DATA      (1ul << 14)
 #define IPA_FLT_FRAGMENT       (1ul << 15)
+#define IPA_FLT_TOS_MASKED     (1ul << 16)
 
 /**
  * enum ipa_client_type - names for the various IPA "clients"
@@ -243,6 +244,8 @@
 	uint16_t dst_port_hi;
 	uint8_t type;
 	uint8_t code;
+	uint8_t tos_value;
+	uint8_t tos_mask;
 	uint32_t spi;
 	uint16_t src_port;
 	uint16_t dst_port;
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index 19ef95d..eed27f4 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -30,6 +30,9 @@
 	PB_migrate,
 	PB_migrate_end = PB_migrate + 3 - 1,
 			/* 3 bits required for migrate types */
+#ifdef CONFIG_COMPACTION
+	PB_migrate_skip,/* If set the block is skipped by compaction */
+#endif /* CONFIG_COMPACTION */
 	NR_PAGEBLOCK_BITS
 };
 
@@ -65,10 +68,22 @@
 void set_pageblock_flags_group(struct page *page, unsigned long flags,
 					int start_bitidx, int end_bitidx);
 
+#ifdef CONFIG_COMPACTION
+#define get_pageblock_skip(page) \
+			get_pageblock_flags_group(page, PB_migrate_skip,     \
+							PB_migrate_skip + 1)
+#define clear_pageblock_skip(page) \
+			set_pageblock_flags_group(page, 0, PB_migrate_skip,  \
+							PB_migrate_skip + 1)
+#define set_pageblock_skip(page) \
+			set_pageblock_flags_group(page, 1, PB_migrate_skip,  \
+							PB_migrate_skip + 1)
+#endif /* CONFIG_COMPACTION */
+
 #define get_pageblock_flags(page) \
-			get_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
+			get_pageblock_flags_group(page, 0, PB_migrate_end)
 #define set_pageblock_flags(page, flags) \
 			set_pageblock_flags_group(page, flags,	\
-						  0, NR_PAGEBLOCK_BITS-1)
+						  0, PB_migrate_end)
 
 #endif	/* PAGEBLOCK_FLAGS_H */
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 2683fd7..bd2ca82 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -26,14 +26,14 @@
 
 #ifdef CONFIG_ARCH_MSM8974
 int __init krait_power_init(void);
-void secondary_cpu_hs_init(void *base_ptr);
+void secondary_cpu_hs_init(void *base_ptr, int cpu);
 #else
 static inline int __init krait_power_init(void)
 {
 	return -ENOSYS;
 }
 
-static inline void secondary_cpu_hs_init(void *base_ptr) {}
+static inline void secondary_cpu_hs_init(void *base_ptr, int cpu) {}
 #endif
 
 #endif
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index fd07c45..a5ddc60 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -67,6 +67,17 @@
 	struct list_head same_anon_vma;	/* locked by anon_vma->mutex */
 };
 
+enum ttu_flags {
+	TTU_UNMAP = 0,			/* unmap mode */
+	TTU_MIGRATION = 1,		/* migration mode */
+	TTU_MUNLOCK = 2,		/* munlock mode */
+	TTU_ACTION_MASK = 0xff,
+
+	TTU_IGNORE_MLOCK = (1 << 8),	/* ignore mlock */
+	TTU_IGNORE_ACCESS = (1 << 9),	/* don't age */
+	TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */
+};
+
 #ifdef CONFIG_MMU
 static inline void get_anon_vma(struct anon_vma *anon_vma)
 {
@@ -161,16 +172,6 @@
 int page_referenced_one(struct page *, struct vm_area_struct *,
 	unsigned long address, unsigned int *mapcount, unsigned long *vm_flags);
 
-enum ttu_flags {
-	TTU_UNMAP = 0,			/* unmap mode */
-	TTU_MIGRATION = 1,		/* migration mode */
-	TTU_MUNLOCK = 2,		/* munlock mode */
-	TTU_ACTION_MASK = 0xff,
-
-	TTU_IGNORE_MLOCK = (1 << 8),	/* ignore mlock */
-	TTU_IGNORE_ACCESS = (1 << 9),	/* don't age */
-	TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */
-};
 #define TTU_ACTION(x) ((x) & TTU_ACTION_MASK)
 
 bool is_vma_temporary_stack(struct vm_area_struct *vma);
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 5c5b777..132135e 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -511,8 +511,11 @@
  * @wakeup: This function pointer implements controller-specific procedure
  *	to wake it up from clock-pause. Framework will call this to bring
  *	the controller out of clock pause.
- * @config_port: Configure a port and make it ready for data transfer. This is
- *	called by framework after connect_port message is sent successfully.
+ * @alloc_port: Allocate a port and make it ready for data transfer. This is
+ *	called by framework to make sure controller can take necessary steps
+ *	to initialize its port
+ * @dealloc_port: Counter-part of alloc_port. This is called by framework so
+ *	that controller can free resources associated with this port
  * @framer_handover: If this controller has multiple framers, this API will
  *	be called to switch between framers if controller desires to change
  *	the active framer.
@@ -557,7 +560,9 @@
 	int			(*get_laddr)(struct slim_controller *ctrl,
 				const u8 *ea, u8 elen, u8 *laddr);
 	int			(*wakeup)(struct slim_controller *ctrl);
-	int			(*config_port)(struct slim_controller *ctrl,
+	int			(*alloc_port)(struct slim_controller *ctrl,
+				u8 port);
+	void			(*dealloc_port)(struct slim_controller *ctrl,
 				u8 port);
 	int			(*framer_handover)(struct slim_controller *ctrl,
 				struct slim_framer *new_framer);
@@ -795,6 +800,8 @@
  * Channel specified in chanh needs to be allocated first.
  * Returns -EALREADY if source is already configured for this channel.
  * Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid direction is specified for non-manager port,
+ * or if the manager side port number is out of bounds, or in incorrect state
  */
 extern int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh);
 
@@ -808,6 +815,9 @@
  * Channel specified in chanh needs to be allocated first.
  * Returns -EALREADY if sink is already configured for this channel.
  * Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid parameters are passed, or invalid direction is
+ * specified for non-manager port, or if the manager side port number is out of
+ * bounds, or in incorrect state
  */
 extern int slim_connect_sink(struct slim_device *sb, u32 *sinkh, int nsink,
 				u16 chanh);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index b1fd5c7..d5bd6ee 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -251,7 +251,7 @@
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 					gfp_t gfp_mask, nodemask_t *mask);
-extern int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file);
+extern int __isolate_lru_page(struct page *page, isolate_mode_t mode);
 extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
 						  gfp_t gfp_mask, bool noswap);
 extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
@@ -355,23 +355,6 @@
 extern int try_to_free_swap(struct page *);
 struct backing_dev_info;
 
-/* linux/mm/thrash.c */
-extern struct mm_struct *swap_token_mm;
-extern void grab_swap_token(struct mm_struct *);
-extern void __put_swap_token(struct mm_struct *);
-extern void disable_swap_token(struct mem_cgroup *memcg);
-
-static inline int has_swap_token(struct mm_struct *mm)
-{
-	return (mm == swap_token_mm);
-}
-
-static inline void put_swap_token(struct mm_struct *mm)
-{
-	if (has_swap_token(mm))
-		__put_swap_token(mm);
-}
-
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 extern void
 mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
@@ -476,24 +459,6 @@
 	return entry;
 }
 
-/* linux/mm/thrash.c */
-static inline void put_swap_token(struct mm_struct *mm)
-{
-}
-
-static inline void grab_swap_token(struct mm_struct *mm)
-{
-}
-
-static inline int has_swap_token(struct mm_struct *mm)
-{
-	return 0;
-}
-
-static inline void disable_swap_token(struct mem_cgroup *memcg)
-{
-}
-
 static inline void
 mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
 {
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 82044f7..fea832e 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -545,6 +545,7 @@
 	const char			*name;
 	struct device			dev;
 	u8				usb_core_id;
+	bool				l1_supported;
 };
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 04b99b7..44c6d7f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -42,6 +42,20 @@
 #define MSM_VENDOR_ID			BIT(16)
 
 /**
+ * Requested USB votes for BUS bandwidth
+ *
+ * USB_NO_PERF_VOTE     BUS Vote for inactive USB session or disconnect
+ * USB_MAX_PERF_VOTE    Maximum BUS bandwidth vote
+ * USB_MIN_PERF_VOTE    Minimum BUS bandwidth vote (for some hw same as NO_PERF)
+ *
+ */
+enum usb_bus_vote {
+	USB_NO_PERF_VOTE = 0,
+	USB_MAX_PERF_VOTE,
+	USB_MIN_PERF_VOTE,
+};
+
+/**
  * Supported USB modes
  *
  * USB_PERIPHERAL       Only peripheral mode is supported.
@@ -207,6 +221,7 @@
  * @log2_itc: value of 2^(log2_itc-1) will be used as the
  *              interrupt threshold (ITC), when log2_itc is
  *              between 1 to 7.
+ * @l1_supported: enable link power management support.
  */
 struct msm_otg_platform_data {
 	int *phy_init_seq;
@@ -231,6 +246,7 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 	const char *mhl_dev_name;
 	int log2_itc;
+	bool l1_supported;
 };
 
 /* phy related flags */
@@ -414,6 +430,7 @@
 	 */
 	int log2_itc;
 	void *prv_data;
+	bool l1_supported;
 };
 
 struct msm_hsic_host_platform_data {
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 0d57d93..f3f4c3b 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -39,6 +39,15 @@
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 #define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
 
+#define USB_L1_EP_CTRL	     (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG	     (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN	BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK	BIT(7)
+#define L1_CONFIG_PHY_LPM	BIT(10)
+#define L1_CONFIG_PLL		BIT(11)
+
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK         (3 << 30)
 #define PORTSC_PTS_ULPI         (3 << 30)
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index 06f8e38..8bbb324 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -37,8 +37,12 @@
 		KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
 		KSWAPD_SKIP_CONGESTION_WAIT,
 		PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+#ifdef CONFIG_MIGRATION
+		PGMIGRATE_SUCCESS, PGMIGRATE_FAIL,
+#endif
 #ifdef CONFIG_COMPACTION
-		COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
+		COMPACTMIGRATE_SCANNED, COMPACTFREE_SCANNED,
+		COMPACTISOLATED,
 		COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
 #endif
 #ifdef CONFIG_HUGETLB_PAGE
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 0d3b5a0..7e98ef3 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6930,8 +6930,8 @@
 } __packed;
 
 /* Ultrasound supported formats */
-#define US_POINT_EPOS_FORMAT 0x00012310
-#define US_RAW_FORMAT        0x0001127C
-#define US_PROX_FORMAT       0x0001272B
+#define US_POINT_EPOS_FORMAT_V2 0x0001272D
+#define US_RAW_FORMAT_V2        0x0001272C
+#define US_PROX_FORMAT_V2       0x0001272E
 
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index f64560e..bab3b87 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -13,7 +13,7 @@
 #define RECLAIM_WB_ANON		0x0001u
 #define RECLAIM_WB_FILE		0x0002u
 #define RECLAIM_WB_MIXED	0x0010u
-#define RECLAIM_WB_SYNC		0x0004u
+#define RECLAIM_WB_SYNC		0x0004u /* Unused, all reclaim async */
 #define RECLAIM_WB_ASYNC	0x0008u
 
 #define show_reclaim_flags(flags)				\
@@ -25,15 +25,15 @@
 		{RECLAIM_WB_ASYNC,	"RECLAIM_WB_ASYNC"}	\
 		) : "RECLAIM_WB_NONE"
 
-#define trace_reclaim_flags(page, sync) ( \
+#define trace_reclaim_flags(page) ( \
 	(page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
-	(sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC)   \
+	(RECLAIM_WB_ASYNC) \
 	)
 
-#define trace_shrink_flags(file, sync) ( \
-	(sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_MIXED : \
-			(file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON)) |  \
-	(sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
+#define trace_shrink_flags(file) \
+	( \
+		(file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
+		(RECLAIM_WB_ASYNC) \
 	)
 
 TRACE_EVENT(mm_vmscan_kswapd_sleep,
@@ -263,22 +263,16 @@
 		unsigned long nr_requested,
 		unsigned long nr_scanned,
 		unsigned long nr_taken,
-		unsigned long nr_lumpy_taken,
-		unsigned long nr_lumpy_dirty,
-		unsigned long nr_lumpy_failed,
 		isolate_mode_t isolate_mode,
 		int file),
 
-	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file),
+	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
 
 	TP_STRUCT__entry(
 		__field(int, order)
 		__field(unsigned long, nr_requested)
 		__field(unsigned long, nr_scanned)
 		__field(unsigned long, nr_taken)
-		__field(unsigned long, nr_lumpy_taken)
-		__field(unsigned long, nr_lumpy_dirty)
-		__field(unsigned long, nr_lumpy_failed)
 		__field(isolate_mode_t, isolate_mode)
 		__field(int, file)
 	),
@@ -288,22 +282,16 @@
 		__entry->nr_requested = nr_requested;
 		__entry->nr_scanned = nr_scanned;
 		__entry->nr_taken = nr_taken;
-		__entry->nr_lumpy_taken = nr_lumpy_taken;
-		__entry->nr_lumpy_dirty = nr_lumpy_dirty;
-		__entry->nr_lumpy_failed = nr_lumpy_failed;
 		__entry->isolate_mode = isolate_mode;
 		__entry->file = file;
 	),
 
-	TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu file=%d",
+	TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
 		__entry->isolate_mode,
 		__entry->order,
 		__entry->nr_requested,
 		__entry->nr_scanned,
 		__entry->nr_taken,
-		__entry->nr_lumpy_taken,
-		__entry->nr_lumpy_dirty,
-		__entry->nr_lumpy_failed,
 		__entry->file)
 );
 
@@ -313,13 +301,10 @@
 		unsigned long nr_requested,
 		unsigned long nr_scanned,
 		unsigned long nr_taken,
-		unsigned long nr_lumpy_taken,
-		unsigned long nr_lumpy_dirty,
-		unsigned long nr_lumpy_failed,
 		isolate_mode_t isolate_mode,
 		int file),
 
-	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
+	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
@@ -329,13 +314,10 @@
 		unsigned long nr_requested,
 		unsigned long nr_scanned,
 		unsigned long nr_taken,
-		unsigned long nr_lumpy_taken,
-		unsigned long nr_lumpy_dirty,
-		unsigned long nr_lumpy_failed,
 		isolate_mode_t isolate_mode,
 		int file),
 
-	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
+	TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
@@ -395,88 +377,6 @@
 		show_reclaim_flags(__entry->reclaim_flags))
 );
 
-TRACE_EVENT(replace_swap_token,
-	TP_PROTO(struct mm_struct *old_mm,
-		 struct mm_struct *new_mm),
-
-	TP_ARGS(old_mm, new_mm),
-
-	TP_STRUCT__entry(
-		__field(struct mm_struct*,	old_mm)
-		__field(unsigned int,		old_prio)
-		__field(struct mm_struct*,	new_mm)
-		__field(unsigned int,		new_prio)
-	),
-
-	TP_fast_assign(
-		__entry->old_mm   = old_mm;
-		__entry->old_prio = old_mm ? old_mm->token_priority : 0;
-		__entry->new_mm   = new_mm;
-		__entry->new_prio = new_mm->token_priority;
-	),
-
-	TP_printk("old_token_mm=%p old_prio=%u new_token_mm=%p new_prio=%u",
-		  __entry->old_mm, __entry->old_prio,
-		  __entry->new_mm, __entry->new_prio)
-);
-
-DECLARE_EVENT_CLASS(put_swap_token_template,
-	TP_PROTO(struct mm_struct *swap_token_mm),
-
-	TP_ARGS(swap_token_mm),
-
-	TP_STRUCT__entry(
-		__field(struct mm_struct*, swap_token_mm)
-	),
-
-	TP_fast_assign(
-		__entry->swap_token_mm = swap_token_mm;
-	),
-
-	TP_printk("token_mm=%p", __entry->swap_token_mm)
-);
-
-DEFINE_EVENT(put_swap_token_template, put_swap_token,
-	TP_PROTO(struct mm_struct *swap_token_mm),
-	TP_ARGS(swap_token_mm)
-);
-
-DEFINE_EVENT_CONDITION(put_swap_token_template, disable_swap_token,
-	TP_PROTO(struct mm_struct *swap_token_mm),
-	TP_ARGS(swap_token_mm),
-	TP_CONDITION(swap_token_mm != NULL)
-);
-
-TRACE_EVENT_CONDITION(update_swap_token_priority,
-	TP_PROTO(struct mm_struct *mm,
-		 unsigned int old_prio,
-		 struct mm_struct *swap_token_mm),
-
-	TP_ARGS(mm, old_prio, swap_token_mm),
-
-	TP_CONDITION(mm->token_priority != old_prio),
-
-	TP_STRUCT__entry(
-		__field(struct mm_struct*, mm)
-		__field(unsigned int, old_prio)
-		__field(unsigned int, new_prio)
-		__field(struct mm_struct*, swap_token_mm)
-		__field(unsigned int, swap_token_prio)
-	),
-
-	TP_fast_assign(
-		__entry->mm		= mm;
-		__entry->old_prio	= old_prio;
-		__entry->new_prio	= mm->token_priority;
-		__entry->swap_token_mm	= swap_token_mm;
-		__entry->swap_token_prio = swap_token_mm ? swap_token_mm->token_priority : 0;
-	),
-
-	TP_printk("mm=%p old_prio=%u new_prio=%u swap_token_mm=%p token_prio=%u",
-		  __entry->mm, __entry->old_prio, __entry->new_prio,
-		  __entry->swap_token_mm, __entry->swap_token_prio)
-);
-
 #endif /* _TRACE_VMSCAN_H */
 
 /* This part must be outside protection */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2f0d7542..01f68c4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4902,7 +4902,7 @@
  * @root: the css supporsed to be an ancestor of the child.
  *
  * Returns true if "root" is an ancestor of "child" in its hierarchy. Because
- * this function reads css->id, this use rcu_dereference() and rcu_read_lock().
+ * this function reads css->id, the caller must hold rcu_read_lock().
  * But, considering usual usage, the csses should be valid objects after test.
  * Assuming that the caller will do some action to the child if this returns
  * returns true, the caller must take "child";s reference count.
@@ -4914,18 +4914,18 @@
 {
 	struct css_id *child_id;
 	struct css_id *root_id;
-	bool ret = true;
 
-	rcu_read_lock();
 	child_id  = rcu_dereference(child->id);
+	if (!child_id)
+		return false;
 	root_id = rcu_dereference(root->id);
-	if (!child_id
-	    || !root_id
-	    || (child_id->depth < root_id->depth)
-	    || (child_id->stack[root_id->depth] != root_id->id))
-		ret = false;
-	rcu_read_unlock();
-	return ret;
+	if (!root_id)
+		return false;
+	if (child_id->depth < root_id->depth)
+		return false;
+	if (child_id->stack[root_id->depth] != root_id->id)
+		return false;
+	return true;
 }
 
 void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fd126f8..aafa4c1 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5118,7 +5118,7 @@
 
 static int perf_swevent_init(struct perf_event *event)
 {
-	int event_id = event->attr.config;
+	u64 event_id = event->attr.config;
 
 	if (event->attr.type != PERF_TYPE_SOFTWARE)
 		return -ENOENT;
diff --git a/kernel/fork.c b/kernel/fork.c
index 0de735c..a8bf721 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -597,7 +597,6 @@
 			list_del(&mm->mmlist);
 			spin_unlock(&mmlist_lock);
 		}
-		put_swap_token(mm);
 		if (mm->binfmt)
 			module_put(mm->binfmt->module);
 		mmdrop(mm);
@@ -815,10 +814,6 @@
 	memcpy(mm, oldmm, sizeof(*mm));
 	mm_init_cpumask(mm);
 
-	/* Initializing for Swap token stuff */
-	mm->token_priority = 0;
-	mm->last_interval = 0;
-
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	mm->pmd_huge_pte = NULL;
 #endif
@@ -896,10 +891,6 @@
 		goto fail_nomem;
 
 good_mm:
-	/* Initializing for Swap token stuff */
-	mm->token_priority = 0;
-	mm->last_interval = 0;
-
 	tsk->mm = mm;
 	tsk->active_mm = mm;
 	return 0;
diff --git a/mm/Makefile b/mm/Makefile
index 8aada89..ccecbf9 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -25,7 +25,7 @@
 obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
 
 obj-$(CONFIG_BOUNCE)	+= bounce.o
-obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o thrash.o
+obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
 obj-$(CONFIG_HAS_DMA)	+= dmapool.o
 obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
 obj-$(CONFIG_NUMA) 	+= mempolicy.o
diff --git a/mm/compaction.c b/mm/compaction.c
index 353f1c5..673142d 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -16,6 +16,21 @@
 #include <linux/sysfs.h>
 #include "internal.h"
 
+#ifdef CONFIG_COMPACTION
+static inline void count_compact_event(enum vm_event_item item)
+{
+	count_vm_event(item);
+}
+
+static inline void count_compact_events(enum vm_event_item item, long delta)
+{
+	count_vm_events(item, delta);
+}
+#else
+#define count_compact_event(item) do { } while (0)
+#define count_compact_events(item, delta) do { } while (0)
+#endif
+
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 
 #define CREATE_TRACE_POINTS
@@ -50,44 +65,228 @@
 	return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE;
 }
 
+#ifdef CONFIG_COMPACTION
+/* Returns true if the pageblock should be scanned for pages to isolate. */
+static inline bool isolation_suitable(struct compact_control *cc,
+					struct page *page)
+{
+	if (cc->ignore_skip_hint)
+		return true;
+
+	return !get_pageblock_skip(page);
+}
+
+/*
+ * This function is called to clear all cached information on pageblocks that
+ * should be skipped for page isolation when the migrate and free page scanner
+ * meet.
+ */
+static void __reset_isolation_suitable(struct zone *zone)
+{
+	unsigned long start_pfn = zone->zone_start_pfn;
+	unsigned long end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+	unsigned long pfn;
+
+	zone->compact_cached_migrate_pfn = start_pfn;
+	zone->compact_cached_free_pfn = end_pfn;
+	zone->compact_blockskip_flush = false;
+
+	/* Walk the zone and mark every pageblock as suitable for isolation */
+	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
+		struct page *page;
+
+		cond_resched();
+
+		if (!pfn_valid(pfn))
+			continue;
+
+		page = pfn_to_page(pfn);
+		if (zone != page_zone(page))
+			continue;
+
+		clear_pageblock_skip(page);
+	}
+}
+
+void reset_isolation_suitable(pg_data_t *pgdat)
+{
+	int zoneid;
+
+	for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
+		struct zone *zone = &pgdat->node_zones[zoneid];
+		if (!populated_zone(zone))
+			continue;
+
+		/* Only flush if a full compaction finished recently */
+		if (zone->compact_blockskip_flush)
+			__reset_isolation_suitable(zone);
+	}
+}
+
+/*
+ * If no pages were isolated then mark this pageblock to be skipped in the
+ * future. The information is later cleared by __reset_isolation_suitable().
+ */
+static void update_pageblock_skip(struct compact_control *cc,
+			struct page *page, unsigned long nr_isolated,
+			bool migrate_scanner)
+{
+	struct zone *zone = cc->zone;
+	if (!page)
+		return;
+
+	if (!nr_isolated) {
+		unsigned long pfn = page_to_pfn(page);
+		set_pageblock_skip(page);
+
+		/* Update where compaction should restart */
+		if (migrate_scanner) {
+			if (!cc->finished_update_migrate &&
+			    pfn > zone->compact_cached_migrate_pfn)
+				zone->compact_cached_migrate_pfn = pfn;
+		} else {
+			if (!cc->finished_update_free &&
+			    pfn < zone->compact_cached_free_pfn)
+				zone->compact_cached_free_pfn = pfn;
+		}
+	}
+}
+#else
+static inline bool isolation_suitable(struct compact_control *cc,
+					struct page *page)
+{
+	return true;
+}
+
+static void update_pageblock_skip(struct compact_control *cc,
+			struct page *page, unsigned long nr_isolated,
+			bool migrate_scanner)
+{
+}
+#endif /* CONFIG_COMPACTION */
+
+static inline bool should_release_lock(spinlock_t *lock)
+{
+	return need_resched() || spin_is_contended(lock);
+}
+
+/*
+ * Compaction requires the taking of some coarse locks that are potentially
+ * very heavily contended. Check if the process needs to be scheduled or
+ * if the lock is contended. For async compaction, back out in the event
+ * if contention is severe. For sync compaction, schedule.
+ *
+ * Returns true if the lock is held.
+ * Returns false if the lock is released and compaction should abort
+ */
+static bool compact_checklock_irqsave(spinlock_t *lock, unsigned long *flags,
+				      bool locked, struct compact_control *cc)
+{
+	if (should_release_lock(lock)) {
+		if (locked) {
+			spin_unlock_irqrestore(lock, *flags);
+			locked = false;
+		}
+
+		/* async aborts if taking too long or contended */
+		if (!cc->sync) {
+			cc->contended = true;
+			return false;
+		}
+
+		cond_resched();
+	}
+
+	if (!locked)
+		spin_lock_irqsave(lock, *flags);
+	return true;
+}
+
+static inline bool compact_trylock_irqsave(spinlock_t *lock,
+			unsigned long *flags, struct compact_control *cc)
+{
+	return compact_checklock_irqsave(lock, flags, false, cc);
+}
+
+/* Returns true if the page is within a block suitable for migration to */
+static bool suitable_migration_target(struct page *page)
+{
+	int migratetype = get_pageblock_migratetype(page);
+
+	/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
+	if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
+		return false;
+
+	/* If the page is a large free page, then allow migration */
+	if (PageBuddy(page) && page_order(page) >= pageblock_order)
+		return true;
+
+	/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
+	if (migrate_async_suitable(migratetype))
+		return true;
+
+	/* Otherwise skip the block */
+	return false;
+}
+
 /*
  * Isolate free pages onto a private freelist. Caller must hold zone->lock.
  * If @strict is true, will abort returning 0 on any invalid PFNs or non-free
  * pages inside of the pageblock (even though it may still end up isolating
  * some pages).
  */
-static unsigned long isolate_freepages_block(unsigned long blockpfn,
+static unsigned long isolate_freepages_block(struct compact_control *cc,
+				unsigned long blockpfn,
 				unsigned long end_pfn,
 				struct list_head *freelist,
 				bool strict)
 {
 	int nr_scanned = 0, total_isolated = 0;
-	struct page *cursor;
+	struct page *cursor, *valid_page = NULL;
+	unsigned long nr_strict_required = end_pfn - blockpfn;
+	unsigned long flags;
+	bool locked = false;
 
 	cursor = pfn_to_page(blockpfn);
 
-	/* Isolate free pages. This assumes the block is valid */
+	/* Isolate free pages. */
 	for (; blockpfn < end_pfn; blockpfn++, cursor++) {
 		int isolated, i;
 		struct page *page = cursor;
 
-		if (!pfn_valid_within(blockpfn)) {
-			if (strict)
-				return 0;
-			continue;
-		}
 		nr_scanned++;
-
-		if (!PageBuddy(page)) {
-			if (strict)
-				return 0;
+		if (!pfn_valid_within(blockpfn))
 			continue;
-		}
+		if (!valid_page)
+			valid_page = page;
+		if (!PageBuddy(page))
+			continue;
+
+		/*
+		 * The zone lock must be held to isolate freepages.
+		 * Unfortunately this is a very coarse lock and can be
+		 * heavily contended if there are parallel allocations
+		 * or parallel compactions. For async compaction do not
+		 * spin on the lock and we acquire the lock as late as
+		 * possible.
+		 */
+		locked = compact_checklock_irqsave(&cc->zone->lock, &flags,
+								locked, cc);
+		if (!locked)
+			break;
+
+		/* Recheck this is a suitable migration target under lock */
+		if (!strict && !suitable_migration_target(page))
+			break;
+
+		/* Recheck this is a buddy page under lock */
+		if (!PageBuddy(page))
+			continue;
 
 		/* Found a free page, break it into order-0 pages */
 		isolated = split_free_page(page);
 		if (!isolated && strict)
-			return 0;
+			break;
 		total_isolated += isolated;
 		for (i = 0; i < isolated; i++) {
 			list_add(&page->lru, freelist);
@@ -102,6 +301,25 @@
 	}
 
 	trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
+
+	/*
+	 * If strict isolation is requested by CMA then check that all the
+	 * pages requested were isolated. If there were any failures, 0 is
+	 * returned and CMA will fail.
+	 */
+	if (strict && nr_strict_required > total_isolated)
+		total_isolated = 0;
+
+	if (locked)
+		spin_unlock_irqrestore(&cc->zone->lock, flags);
+
+	/* Update the pageblock-skip if the whole pageblock was scanned */
+	if (blockpfn == end_pfn)
+		update_pageblock_skip(cc, valid_page, total_isolated, false);
+
+	count_compact_events(COMPACTFREE_SCANNED, nr_scanned);
+	if (total_isolated)
+		count_compact_events(COMPACTISOLATED, total_isolated);
 	return total_isolated;
 }
 
@@ -119,17 +337,14 @@
  * a free page).
  */
 unsigned long
-isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn)
+isolate_freepages_range(struct compact_control *cc,
+			unsigned long start_pfn, unsigned long end_pfn)
 {
-	unsigned long isolated, pfn, block_end_pfn, flags;
-	struct zone *zone = NULL;
+	unsigned long isolated, pfn, block_end_pfn;
 	LIST_HEAD(freelist);
 
-	if (pfn_valid(start_pfn))
-		zone = page_zone(pfn_to_page(start_pfn));
-
 	for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) {
-		if (!pfn_valid(pfn) || zone != page_zone(pfn_to_page(pfn)))
+		if (!pfn_valid(pfn) || cc->zone != page_zone(pfn_to_page(pfn)))
 			break;
 
 		/*
@@ -139,10 +354,8 @@
 		block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 		block_end_pfn = min(block_end_pfn, end_pfn);
 
-		spin_lock_irqsave(&zone->lock, flags);
-		isolated = isolate_freepages_block(pfn, block_end_pfn,
+		isolated = isolate_freepages_block(cc, pfn, block_end_pfn,
 						   &freelist, true);
-		spin_unlock_irqrestore(&zone->lock, flags);
 
 		/*
 		 * In strict mode, isolate_freepages_block() returns 0 if
@@ -173,7 +386,7 @@
 }
 
 /* Update the number of anon and file isolated pages in the zone */
-static void acct_isolated(struct zone *zone, struct compact_control *cc)
+static void acct_isolated(struct zone *zone, bool locked, struct compact_control *cc)
 {
 	struct page *page;
 	unsigned int count[2] = { 0, };
@@ -181,8 +394,14 @@
 	list_for_each_entry(page, &cc->migratepages, lru)
 		count[!!page_is_file_cache(page)]++;
 
-	__mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
-	__mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+	/* If locked we can use the interrupt unsafe versions */
+	if (locked) {
+		__mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+		__mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+	} else {
+		mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+		mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+	}
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
@@ -206,6 +425,7 @@
  * @cc:		Compaction control structure.
  * @low_pfn:	The first PFN of the range.
  * @end_pfn:	The one-past-the-last PFN of the range.
+ * @unevictable: true if it allows to isolate unevictable pages
  *
  * Isolate all pages that can be migrated from the range specified by
  * [low_pfn, end_pfn).  Returns zero if there is a fatal signal
@@ -221,12 +441,15 @@
  */
 unsigned long
 isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
-			   unsigned long low_pfn, unsigned long end_pfn)
+		unsigned long low_pfn, unsigned long end_pfn, bool unevictable)
 {
 	unsigned long last_pageblock_nr = 0, pageblock_nr;
 	unsigned long nr_scanned = 0, nr_isolated = 0;
 	struct list_head *migratelist = &cc->migratepages;
-	isolate_mode_t mode = ISOLATE_ACTIVE|ISOLATE_INACTIVE;
+	isolate_mode_t mode = 0;
+	unsigned long flags;
+	bool locked = false;
+	struct page *page = NULL, *valid_page = NULL;
 
 	/*
 	 * Ensure that there are not too many pages isolated from the LRU
@@ -246,25 +469,14 @@
 
 	/* Time to isolate some pages for migration */
 	cond_resched();
-	spin_lock_irq(&zone->lru_lock);
 	for (; low_pfn < end_pfn; low_pfn++) {
-		struct page *page;
-		bool locked = true;
-
 		/* give a chance to irqs before checking need_resched() */
-		if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) {
-			spin_unlock_irq(&zone->lru_lock);
-			locked = false;
+		if (locked && !((low_pfn+1) % SWAP_CLUSTER_MAX)) {
+			if (should_release_lock(&zone->lru_lock)) {
+				spin_unlock_irqrestore(&zone->lru_lock, flags);
+				locked = false;
+			}
 		}
-		if (need_resched() || spin_is_contended(&zone->lru_lock)) {
-			if (locked)
-				spin_unlock_irq(&zone->lru_lock);
-			cond_resched();
-			spin_lock_irq(&zone->lru_lock);
-			if (fatal_signal_pending(current))
-				break;
-		} else if (!locked)
-			spin_lock_irq(&zone->lru_lock);
 
 		/*
 		 * migrate_pfn does not necessarily start aligned to a
@@ -293,6 +505,14 @@
 		if (page_zone(page) != zone)
 			continue;
 
+		if (!valid_page)
+			valid_page = page;
+
+		/* If isolation recently failed, do not retry */
+		pageblock_nr = low_pfn >> pageblock_order;
+		if (!isolation_suitable(cc, page))
+			goto next_pageblock;
+
 		/* Skip if free */
 		if (PageBuddy(page))
 			continue;
@@ -302,24 +522,43 @@
 		 * migration is optimistic to see if the minimum amount of work
 		 * satisfies the allocation
 		 */
-		pageblock_nr = low_pfn >> pageblock_order;
 		if (!cc->sync && last_pageblock_nr != pageblock_nr &&
 		    !migrate_async_suitable(get_pageblock_migratetype(page))) {
-			low_pfn += pageblock_nr_pages;
-			low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
-			last_pageblock_nr = pageblock_nr;
-			continue;
+			cc->finished_update_migrate = true;
+			goto next_pageblock;
 		}
 
+		/* Check may be lockless but that's ok as we recheck later */
 		if (!PageLRU(page))
 			continue;
 
 		/*
-		 * PageLRU is set, and lru_lock excludes isolation,
-		 * splitting and collapsing (collapsing has already
-		 * happened if PageLRU is set).
+		 * PageLRU is set. lru_lock normally excludes isolation
+		 * splitting and collapsing (collapsing has already happened
+		 * if PageLRU is set) but the lock is not necessarily taken
+		 * here and it is wasteful to take it just to check transhuge.
+		 * Check TransHuge without lock and skip the whole pageblock if
+		 * it's either a transhuge or hugetlbfs page, as calling
+		 * compound_order() without preventing THP from splitting the
+		 * page underneath us may return surprising results.
 		 */
 		if (PageTransHuge(page)) {
+			if (!locked)
+				goto next_pageblock;
+			low_pfn += (1 << compound_order(page)) - 1;
+			continue;
+		}
+
+		/* Check if it is ok to still hold the lock */
+		locked = compact_checklock_irqsave(&zone->lru_lock, &flags,
+								locked, cc);
+		if (!locked || fatal_signal_pending(current))
+			break;
+
+		/* Recheck PageLRU and PageTransHuge under lock */
+		if (!PageLRU(page))
+			continue;
+		if (PageTransHuge(page)) {
 			low_pfn += (1 << compound_order(page)) - 1;
 			continue;
 		}
@@ -327,13 +566,17 @@
 		if (!cc->sync)
 			mode |= ISOLATE_ASYNC_MIGRATE;
 
+		if (unevictable)
+			mode |= ISOLATE_UNEVICTABLE;
+
 		/* Try isolate the page */
-		if (__isolate_lru_page(page, mode, 0) != 0)
+		if (__isolate_lru_page(page, mode) != 0)
 			continue;
 
 		VM_BUG_ON(PageTransCompound(page));
 
 		/* Successfully isolated */
+		cc->finished_update_migrate = true;
 		del_page_from_lru_list(zone, page, page_lru(page));
 		list_add(&page->lru, migratelist);
 		cc->nr_migratepages++;
@@ -344,42 +587,35 @@
 			++low_pfn;
 			break;
 		}
+
+		continue;
+
+next_pageblock:
+		low_pfn += pageblock_nr_pages;
+		low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
+		last_pageblock_nr = pageblock_nr;
 	}
 
-	acct_isolated(zone, cc);
+	acct_isolated(zone, locked, cc);
 
-	spin_unlock_irq(&zone->lru_lock);
+	if (locked)
+		spin_unlock_irqrestore(&zone->lru_lock, flags);
+
+	/* Update the pageblock-skip if the whole pageblock was scanned */
+	if (low_pfn == end_pfn)
+		update_pageblock_skip(cc, valid_page, nr_isolated, true);
 
 	trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
 
+	count_compact_events(COMPACTMIGRATE_SCANNED, nr_scanned);
+	if (nr_isolated)
+		count_compact_events(COMPACTISOLATED, nr_isolated);
+
 	return low_pfn;
 }
 
 #endif /* CONFIG_COMPACTION || CONFIG_CMA */
 #ifdef CONFIG_COMPACTION
-
-/* Returns true if the page is within a block suitable for migration to */
-static bool suitable_migration_target(struct page *page)
-{
-
-	int migratetype = get_pageblock_migratetype(page);
-
-	/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
-	if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
-		return false;
-
-	/* If the page is a large free page, then allow migration */
-	if (PageBuddy(page) && page_order(page) >= pageblock_order)
-		return true;
-
-	/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
-	if (migrate_async_suitable(migratetype))
-		return true;
-
-	/* Otherwise skip the block */
-	return false;
-}
-
 /*
  * Based on information in the current compact_control, find blocks
  * suitable for isolating free pages from and then isolate them.
@@ -389,7 +625,6 @@
 {
 	struct page *page;
 	unsigned long high_pfn, low_pfn, pfn, zone_end_pfn, end_pfn;
-	unsigned long flags;
 	int nr_freepages = cc->nr_freepages;
 	struct list_head *freelist = &cc->freepages;
 
@@ -437,29 +672,34 @@
 		if (!suitable_migration_target(page))
 			continue;
 
-		/*
-		 * Found a block suitable for isolating free pages from. Now
-		 * we disabled interrupts, double check things are ok and
-		 * isolate the pages. This is to minimise the time IRQs
-		 * are disabled
-		 */
+		/* If isolation recently failed, do not retry */
+		if (!isolation_suitable(cc, page))
+			continue;
+
+		/* Found a block suitable for isolating free pages from */
 		isolated = 0;
-		spin_lock_irqsave(&zone->lock, flags);
-		if (suitable_migration_target(page)) {
-			end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
-			isolated = isolate_freepages_block(pfn, end_pfn,
-							   freelist, false);
-			nr_freepages += isolated;
-		}
-		spin_unlock_irqrestore(&zone->lock, flags);
+
+		/*
+		 * As pfn may not start aligned, pfn+pageblock_nr_page
+		 * may cross a MAX_ORDER_NR_PAGES boundary and miss
+		 * a pfn_valid check. Ensure isolate_freepages_block()
+		 * only scans within a pageblock
+		 */
+		end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
+		end_pfn = min(end_pfn, zone_end_pfn);
+		isolated = isolate_freepages_block(cc, pfn, end_pfn,
+						   freelist, false);
+		nr_freepages += isolated;
 
 		/*
 		 * Record the highest PFN we isolated pages from. When next
 		 * looking for free pages, the search will restart here as
 		 * page migration may have returned some pages to the allocator
 		 */
-		if (isolated)
+		if (isolated) {
+			cc->finished_update_free = true;
 			high_pfn = max(high_pfn, pfn);
+		}
 	}
 
 	/* split_free_page does not map the pages */
@@ -544,8 +784,8 @@
 	}
 
 	/* Perform the isolation */
-	low_pfn = isolate_migratepages_range(zone, cc, low_pfn, end_pfn);
-	if (!low_pfn)
+	low_pfn = isolate_migratepages_range(zone, cc, low_pfn, end_pfn, false);
+	if (!low_pfn || cc->contended)
 		return ISOLATE_ABORT;
 
 	cc->migrate_pfn = low_pfn;
@@ -563,8 +803,18 @@
 		return COMPACT_PARTIAL;
 
 	/* Compaction run completes if the migrate and free scanner meet */
-	if (cc->free_pfn <= cc->migrate_pfn)
+	if (cc->free_pfn <= cc->migrate_pfn) {
+		/*
+		 * Mark that the PG_migrate_skip information should be cleared
+		 * by kswapd when it goes to sleep. kswapd does not set the
+		 * flag itself as the decision to be clear should be directly
+		 * based on an allocation request.
+		 */
+		if (!current_is_kswapd())
+			zone->compact_blockskip_flush = true;
+
 		return COMPACT_COMPLETE;
+	}
 
 	/*
 	 * order == -1 is expected when compacting via
@@ -582,12 +832,14 @@
 
 	/* Direct compactor: Is a suitable page free? */
 	for (order = cc->order; order < MAX_ORDER; order++) {
+		struct free_area *area = &zone->free_area[order];
+
 		/* Job done if page is free of the right migratetype */
-		if (!list_empty(&zone->free_area[order].free_list[cc->migratetype]))
+		if (!list_empty(&area->free_list[cc->migratetype]))
 			return COMPACT_PARTIAL;
 
 		/* Job done if allocation would set block type */
-		if (order >= pageblock_order && zone->free_area[order].nr_free)
+		if (cc->order >= pageblock_order && area->nr_free)
 			return COMPACT_PARTIAL;
 	}
 
@@ -647,6 +899,8 @@
 static int compact_zone(struct zone *zone, struct compact_control *cc)
 {
 	int ret;
+	unsigned long start_pfn = zone->zone_start_pfn;
+	unsigned long end_pfn = zone->zone_start_pfn + zone->spanned_pages;
 
 	ret = compaction_suitable(zone, cc->order);
 	switch (ret) {
@@ -659,10 +913,29 @@
 		;
 	}
 
-	/* Setup to move all movable pages to the end of the zone */
-	cc->migrate_pfn = zone->zone_start_pfn;
-	cc->free_pfn = cc->migrate_pfn + zone->spanned_pages;
-	cc->free_pfn &= ~(pageblock_nr_pages-1);
+	/*
+	 * Setup to move all movable pages to the end of the zone. Used cached
+	 * information on where the scanners should start but check that it
+	 * is initialised by ensuring the values are within zone boundaries.
+	 */
+	cc->migrate_pfn = zone->compact_cached_migrate_pfn;
+	cc->free_pfn = zone->compact_cached_free_pfn;
+	if (cc->free_pfn < start_pfn || cc->free_pfn > end_pfn) {
+		cc->free_pfn = end_pfn & ~(pageblock_nr_pages-1);
+		zone->compact_cached_free_pfn = cc->free_pfn;
+	}
+	if (cc->migrate_pfn < start_pfn || cc->migrate_pfn > end_pfn) {
+		cc->migrate_pfn = start_pfn;
+		zone->compact_cached_migrate_pfn = cc->migrate_pfn;
+	}
+
+	/*
+	 * Clear pageblock skip if there were failures recently and compaction
+	 * is about to be retried after being deferred. kswapd does not do
+	 * this reset as it'll reset the cached information when going to sleep.
+	 */
+	if (compaction_restarting(zone, cc->order) && !current_is_kswapd())
+		__reset_isolation_suitable(zone);
 
 	migrate_prep_local();
 
@@ -673,6 +946,8 @@
 		switch (isolate_migratepages(zone, cc)) {
 		case ISOLATE_ABORT:
 			ret = COMPACT_PARTIAL;
+			putback_lru_pages(&cc->migratepages);
+			cc->nr_migratepages = 0;
 			goto out;
 		case ISOLATE_NONE:
 			continue;
@@ -687,10 +962,6 @@
 		update_nr_listpages(cc);
 		nr_remaining = cc->nr_migratepages;
 
-		count_vm_event(COMPACTBLOCKS);
-		count_vm_events(COMPACTPAGES, nr_migrate - nr_remaining);
-		if (nr_remaining)
-			count_vm_events(COMPACTPAGEFAILED, nr_remaining);
 		trace_mm_compaction_migratepages(nr_migrate - nr_remaining,
 						nr_remaining);
 
@@ -698,8 +969,11 @@
 		if (err) {
 			putback_lru_pages(&cc->migratepages);
 			cc->nr_migratepages = 0;
+			if (err == -ENOMEM) {
+				ret = COMPACT_PARTIAL;
+				goto out;
+			}
 		}
-
 	}
 
 out:
@@ -712,8 +986,9 @@
 
 static unsigned long compact_zone_order(struct zone *zone,
 				 int order, gfp_t gfp_mask,
-				 bool sync)
+				 bool sync, bool *contended)
 {
+	unsigned long ret;
 	struct compact_control cc = {
 		.nr_freepages = 0,
 		.nr_migratepages = 0,
@@ -725,7 +1000,13 @@
 	INIT_LIST_HEAD(&cc.freepages);
 	INIT_LIST_HEAD(&cc.migratepages);
 
-	return compact_zone(zone, &cc);
+	ret = compact_zone(zone, &cc);
+
+	VM_BUG_ON(!list_empty(&cc.freepages));
+	VM_BUG_ON(!list_empty(&cc.migratepages));
+
+	*contended = cc.contended;
+	return ret;
 }
 
 int sysctl_extfrag_threshold = 500;
@@ -737,12 +1018,14 @@
  * @gfp_mask: The GFP mask of the current allocation
  * @nodemask: The allowed nodes to allocate from
  * @sync: Whether migration is synchronous or not
+ * @contended: Return value that is true if compaction was aborted due to lock contention
+ * @page: Optionally capture a free page of the requested order during compaction
  *
  * This is the main entry point for direct page compaction.
  */
 unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *nodemask,
-			bool sync)
+			bool sync, bool *contended)
 {
 	enum zone_type high_zoneidx = gfp_zone(gfp_mask);
 	int may_enter_fs = gfp_mask & __GFP_FS;
@@ -752,15 +1035,11 @@
 	int rc = COMPACT_SKIPPED;
 	int alloc_flags = 0;
 
-	/*
-	 * Check whether it is worth even starting compaction. The order check is
-	 * made because an assumption is made that the page allocator can satisfy
-	 * the "cheaper" orders without taking special steps
-	 */
+	/* Check if the GFP flags allow compaction */
 	if (!order || !may_enter_fs || !may_perform_io)
 		return rc;
 
-	count_vm_event(COMPACTSTALL);
+	count_compact_event(COMPACTSTALL);
 
 #ifdef CONFIG_CMA
 	if (allocflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
@@ -771,7 +1050,8 @@
 								nodemask) {
 		int status;
 
-		status = compact_zone_order(zone, order, gfp_mask, sync);
+		status = compact_zone_order(zone, order, gfp_mask, sync,
+						contended);
 		rc = max(status, rc);
 
 		/* If a normal allocation would succeed, stop compacting */
@@ -808,7 +1088,7 @@
 		if (cc->order > 0) {
 			int ok = zone_watermark_ok(zone, cc->order,
 						low_wmark_pages(zone), 0, 0);
-			if (ok && cc->order > zone->compact_order_failed)
+			if (ok && cc->order >= zone->compact_order_failed)
 				zone->compact_order_failed = cc->order + 1;
 			/* Currently async compaction is never deferred. */
 			else if (!ok && cc->sync)
@@ -843,7 +1123,7 @@
 }
 
 /* Compact all nodes in the system */
-static int compact_nodes(void)
+static void compact_nodes(void)
 {
 	int nid;
 
@@ -852,8 +1132,6 @@
 
 	for_each_online_node(nid)
 		compact_node(nid);
-
-	return COMPACT_COMPLETE;
 }
 
 /* The written value is actually unused, all memory is compacted */
@@ -864,7 +1142,7 @@
 			void __user *buffer, size_t *length, loff_t *ppos)
 {
 	if (write)
-		return compact_nodes();
+		compact_nodes();
 
 	return 0;
 }
diff --git a/mm/internal.h b/mm/internal.h
index 8c6fd44..3439ef4 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -120,17 +120,24 @@
 	unsigned long free_pfn;		/* isolate_freepages search base */
 	unsigned long migrate_pfn;	/* isolate_migratepages search base */
 	bool sync;			/* Synchronous migration */
+	bool ignore_skip_hint;		/* Scan blocks even if marked skip */
+	bool finished_update_free;	/* True when the zone cached pfns are
+					 * no longer being updated
+					 */
+	bool finished_update_migrate;
 
 	int order;			/* order a direct compactor needs */
 	int migratetype;		/* MOVABLE, RECLAIMABLE etc */
 	struct zone *zone;
+	bool contended;			/* True if a lock was contended */
 };
 
 unsigned long
-isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn);
+isolate_freepages_range(struct compact_control *cc,
+			unsigned long start_pfn, unsigned long end_pfn);
 unsigned long
 isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
-			   unsigned long low_pfn, unsigned long end_pfn);
+	unsigned long low_pfn, unsigned long end_pfn, bool unevictable);
 
 #endif
 
@@ -356,3 +363,6 @@
 #define ALLOC_HIGH		0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET		0x40 /* check for correct cpuset */
 #define ALLOC_CMA		0x80 /* allow allocations from CMA areas */
+
+unsigned long reclaim_clean_pages_from_list(struct zone *zone,
+					    struct list_head *page_list);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7685d4a..d436634 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1116,11 +1116,6 @@
 	mz->lru_size[lru] -= 1 << compound_order(page);
 }
 
-void mem_cgroup_lru_del(struct page *page)
-{
-	mem_cgroup_lru_del_list(page, page_lru(page));
-}
-
 /**
  * mem_cgroup_lru_move_lists - account for moving a page between lrus
  * @zone: zone of the page
@@ -1149,15 +1144,25 @@
  * Checks whether given mem is same or in the root_mem_cgroup's
  * hierarchy subtree
  */
-static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
-		struct mem_cgroup *memcg)
+bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+				  struct mem_cgroup *memcg)
 {
-	if (root_memcg != memcg) {
-		return (root_memcg->use_hierarchy &&
-			css_is_ancestor(&memcg->css, &root_memcg->css));
-	}
+	if (root_memcg == memcg)
+		return true;
+	if (!root_memcg->use_hierarchy)
+		return false;
+	return css_is_ancestor(&memcg->css, &root_memcg->css);
+}
 
-	return true;
+static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+				       struct mem_cgroup *memcg)
+{
+	bool ret;
+
+	rcu_read_lock();
+	ret = __mem_cgroup_same_or_subtree(root_memcg, memcg);
+	rcu_read_unlock();
+	return ret;
 }
 
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
@@ -5610,7 +5615,6 @@
 	if (mm) {
 		if (mc.to)
 			mem_cgroup_move_charge(mm);
-		put_swap_token(mm);
 		mmput(mm);
 	}
 	if (mc.to)
diff --git a/mm/memory.c b/mm/memory.c
index 2111354..b6ab040 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2935,7 +2935,6 @@
 	delayacct_set_flag(DELAYACCT_PF_SWAPIN);
 	page = lookup_swap_cache(entry);
 	if (!page) {
-		grab_swap_token(mm); /* Contend for token _before_ read-in */
 		page = swapin_readahead(entry,
 					GFP_HIGHUSER_MOVABLE, vma, address);
 		if (!page) {
@@ -2965,6 +2964,7 @@
 	}
 
 	locked = lock_page_or_retry(page, mm, flags);
+
 	delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
 	if (!locked) {
 		ret |= VM_FAULT_RETRY;
diff --git a/mm/migrate.c b/mm/migrate.c
index 79a791f..4f5c02e 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -969,6 +969,7 @@
 {
 	int retry = 1;
 	int nr_failed = 0;
+	int nr_succeeded = 0;
 	int pass = 0;
 	struct page *page;
 	struct page *page2;
@@ -997,6 +998,7 @@
 				trace_migrate_retry(retry);
 				break;
 			case 0:
+				nr_succeeded++;
 				break;
 			default:
 				/* Permanent failure */
@@ -1007,6 +1009,10 @@
 	}
 	rc = 0;
 out:
+	if (nr_succeeded)
+		count_vm_events(PGMIGRATE_SUCCESS, nr_succeeded);
+	if (nr_failed)
+		count_vm_events(PGMIGRATE_FAIL, nr_failed);
 	if (!swapwrite)
 		current->flags &= ~PF_SWAPWRITE;
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8a93508..5148c1a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1441,6 +1441,45 @@
 		set_page_refcounted(page + i);
 }
 
+static int __isolate_free_page(struct page *page, unsigned int order)
+{
+	unsigned long watermark;
+	struct zone *zone;
+	int mt;
+
+	BUG_ON(!PageBuddy(page));
+
+	zone = page_zone(page);
+	mt = get_pageblock_migratetype(page);
+
+	if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt)) {
+		/* Obey watermarks as if the page was being allocated */
+		watermark = low_wmark_pages(zone) + (1 << order);
+		if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+			return 0;
+
+		__mod_zone_freepage_state(zone, -(1UL << order), mt);
+	}
+
+	/* Remove page from free list */
+	list_del(&page->lru);
+	zone->free_area[order].nr_free--;
+	rmv_page_order(page);
+
+	/* Set the pageblock if the isolated page is at least a pageblock */
+	if (order >= pageblock_order - 1) {
+		struct page *endpage = page + (1 << order) - 1;
+		for (; page < endpage; page += pageblock_nr_pages) {
+			mt = get_pageblock_migratetype(page);
+			if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt))
+				set_pageblock_migratetype(page,
+							  MIGRATE_MOVABLE);
+		}
+	}
+
+	return 1UL << order;
+}
+
 /*
  * Similar to split_page except the page is already free. As this is only
  * being used for migration, the migratetype of the block also changes.
@@ -1454,45 +1493,18 @@
 int split_free_page(struct page *page)
 {
 	unsigned int order;
-	unsigned long watermark;
-	struct zone *zone;
-	int mt;
+	int nr_pages;
 
-	BUG_ON(!PageBuddy(page));
-
-	zone = page_zone(page);
 	order = page_order(page);
-	mt = get_pageblock_migratetype(page);
 
-	/* Obey watermarks as if the page was being allocated */
-	watermark = low_wmark_pages(zone) + (1 << order);
-	if (!is_migrate_cma(mt) && mt != MIGRATE_ISOLATE &&
-	    !zone_watermark_ok(zone, 0, watermark, 0, 0))
+	nr_pages = __isolate_free_page(page, order);
+	if (!nr_pages)
 		return 0;
 
-	/* Remove page from free list */
-	list_del(&page->lru);
-	zone->free_area[order].nr_free--;
-	rmv_page_order(page);
-
-	if (unlikely(mt != MIGRATE_ISOLATE))
-		__mod_zone_freepage_state(zone, -(1UL << order), mt);
-
 	/* Split into individual pages */
 	set_page_refcounted(page);
 	split_page(page, order);
-
-	if (order >= pageblock_order - 1) {
-		struct page *endpage = page + (1 << order) - 1;
-		for (; page < endpage; page += pageblock_nr_pages) {
-			mt = get_pageblock_migratetype(page);
-			if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt))
-				set_pageblock_migratetype(page,
-							  MIGRATE_MOVABLE);
-		}
-	}
-
-	return 1 << order;
+	return nr_pages;
 }
 
 /*
@@ -2134,11 +2146,9 @@
 	struct zonelist *zonelist, enum zone_type high_zoneidx,
 	nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
 	int migratetype, bool sync_migration,
-	bool *deferred_compaction,
+	bool *contended_compaction, bool *deferred_compaction,
 	unsigned long *did_some_progress)
 {
-	struct page *page;
-
 	if (!order)
 		return NULL;
 
@@ -2149,9 +2159,12 @@
 
 	current->flags |= PF_MEMALLOC;
 	*did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
-						nodemask, sync_migration);
+						nodemask, sync_migration,
+						contended_compaction);
 	current->flags &= ~PF_MEMALLOC;
+
 	if (*did_some_progress != COMPACT_SKIPPED) {
+		struct page *page;
 
 		/* Page migration frees to the PCP lists but we want merging */
 		drain_pages(get_cpu());
@@ -2162,6 +2175,7 @@
 				alloc_flags, preferred_zone,
 				migratetype);
 		if (page) {
+			preferred_zone->compact_blockskip_flush = false;
 			preferred_zone->compact_considered = 0;
 			preferred_zone->compact_defer_shift = 0;
 			if (order >= preferred_zone->compact_order_failed)
@@ -2195,7 +2209,7 @@
 	struct zonelist *zonelist, enum zone_type high_zoneidx,
 	nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
 	int migratetype, bool sync_migration,
-	bool *deferred_compaction,
+	bool *contended_compaction, bool *deferred_compaction,
 	unsigned long *did_some_progress)
 {
 	return NULL;
@@ -2362,6 +2376,7 @@
 	unsigned long did_some_progress;
 	bool sync_migration = false;
 	bool deferred_compaction = false;
+	bool contended_compaction = false;
 
 	/*
 	 * In the slowpath, we sanity check order to avoid ever trying to
@@ -2443,6 +2458,7 @@
 					nodemask,
 					alloc_flags, preferred_zone,
 					migratetype, sync_migration,
+					&contended_compaction,
 					&deferred_compaction,
 					&did_some_progress);
 	if (page)
@@ -2452,10 +2468,11 @@
 	/*
 	 * If compaction is deferred for high-order allocations, it is because
 	 * sync compaction recently failed. In this is the case and the caller
-	 * has requested the system not be heavily disrupted, fail the
-	 * allocation now instead of entering direct reclaim
+	 * requested a movable allocation that does not heavily disrupt the
+	 * system then fail the allocation instead of entering direct reclaim.
 	 */
-	if (deferred_compaction && (gfp_mask & __GFP_NO_KSWAPD))
+	if ((deferred_compaction || contended_compaction) &&
+						(gfp_mask & __GFP_NO_KSWAPD))
 		goto nopage;
 
 	/* Try direct reclaim and then allocating */
@@ -2526,6 +2543,7 @@
 					nodemask,
 					alloc_flags, preferred_zone,
 					migratetype, sync_migration,
+					&contended_compaction,
 					&deferred_compaction,
 					&did_some_progress);
 		if (page)
@@ -5592,26 +5610,28 @@
 }
 
 /*
- * This is designed as sub function...plz see page_isolation.c also.
- * set/clear page block's type to be ISOLATE.
- * page allocater never alloc memory from ISOLATE block.
+ * This function checks whether pageblock includes unmovable pages or not.
+ * If @count is not zero, it is okay to include less @count unmovable pages
+ *
+ * PageLRU check wihtout isolation or lru_lock could race so that
+ * MIGRATE_MOVABLE block might include unmovable pages. It means you can't
+ * expect this function should be exact.
  */
-
-static int
-__count_immobile_pages(struct zone *zone, struct page *page, int count)
+static bool
+__has_unmovable_pages(struct zone *zone, struct page *page, int count)
 {
 	unsigned long pfn, iter, found;
 	int mt;
 
 	/*
 	 * For avoiding noise data, lru_add_drain_all() should be called
-	 * If ZONE_MOVABLE, the zone never contains immobile pages
+	 * If ZONE_MOVABLE, the zone never contains unmovable pages
 	 */
 	if (zone_idx(zone) == ZONE_MOVABLE)
-		return true;
+		return false;
 	mt = get_pageblock_migratetype(page);
 	if (mt == MIGRATE_MOVABLE || is_migrate_cma(mt))
-		return true;
+		return false;
 
 	pfn = page_to_pfn(page);
 	for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
@@ -5621,11 +5641,18 @@
 			continue;
 
 		page = pfn_to_page(check);
-		if (!page_count(page)) {
+		/*
+		 * We can't use page_count without pin a page
+		 * because another CPU can free compound page.
+		 * This check already skips compound tails of THP
+		 * because their page->_count is zero at all time.
+		 */
+		if (!atomic_read(&page->_count)) {
 			if (PageBuddy(page))
 				iter += (1 << page_order(page)) - 1;
 			continue;
 		}
+
 		if (!PageLRU(page))
 			found++;
 		/*
@@ -5642,9 +5669,9 @@
 		 * page at boot.
 		 */
 		if (found > count)
-			return false;
+			return true;
 	}
-	return true;
+	return false;
 }
 
 bool is_pageblock_removable_nolock(struct page *page)
@@ -5668,7 +5695,7 @@
 			zone->zone_start_pfn + zone->spanned_pages <= pfn)
 		return false;
 
-	return __count_immobile_pages(zone, page, 0);
+	return !__has_unmovable_pages(zone, page, 0);
 }
 
 int set_migratetype_isolate(struct page *page)
@@ -5707,12 +5734,12 @@
 	 * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
 	 * We just check MOVABLE pages.
 	 */
-	if (__count_immobile_pages(zone, page, arg.pages_found))
+	if (!__has_unmovable_pages(zone, page, arg.pages_found))
 		ret = 0;
-
 	/*
-	 * immobile means "not-on-lru" paes. If immobile is larger than
-	 * removable-by-driver pages reported by notifier, we'll fail.
+	 * Unmovable means "not-on-lru" pages. If Unmovable pages are
+	 * larger than removable-by-driver pages reported by notifier,
+	 * we'll fail.
 	 */
 
 out:
@@ -5775,34 +5802,27 @@
 }
 
 /* [start, end) must belong to a single zone. */
-static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
+static int __alloc_contig_migrate_range(struct compact_control *cc,
+					unsigned long start, unsigned long end)
 {
 	/* This function is based on compact_zone() from compaction.c. */
-
+	unsigned long nr_reclaimed;
 	unsigned long pfn = start;
 	unsigned int tries = 0;
 	int ret = 0;
 
-	struct compact_control cc = {
-		.nr_migratepages = 0,
-		.order = -1,
-		.zone = page_zone(pfn_to_page(start)),
-		.sync = true,
-	};
-	INIT_LIST_HEAD(&cc.migratepages);
-
 	migrate_prep();
 
-	while (pfn < end || !list_empty(&cc.migratepages)) {
+	while (pfn < end || !list_empty(&cc->migratepages)) {
 		if (fatal_signal_pending(current)) {
 			ret = -EINTR;
 			break;
 		}
 
-		if (list_empty(&cc.migratepages)) {
-			cc.nr_migratepages = 0;
-			pfn = isolate_migratepages_range(cc.zone, &cc,
-							 pfn, end);
+		if (list_empty(&cc->migratepages)) {
+			cc->nr_migratepages = 0;
+			pfn = isolate_migratepages_range(cc->zone, cc,
+							 pfn, end, true);
 			if (!pfn) {
 				ret = -EINTR;
 				break;
@@ -5813,12 +5833,16 @@
 			break;
 		}
 
-		ret = migrate_pages(&cc.migratepages,
+		nr_reclaimed = reclaim_clean_pages_from_list(cc->zone, &cc->migratepages);
+
+		cc->nr_migratepages -= nr_reclaimed;
+
+		ret = migrate_pages(&cc->migratepages,
 				    __alloc_contig_migrate_alloc,
 				    0, false, MIGRATE_SYNC);
 	}
 
-	putback_lru_pages(&cc.migratepages);
+	putback_lru_pages(&cc->migratepages);
 	return ret > 0 ? 0 : ret;
 }
 
@@ -5849,6 +5873,15 @@
 	unsigned long outer_start, outer_end;
 	int ret = 0, order;
 
+	struct compact_control cc = {
+		.nr_migratepages = 0,
+		.order = -1,
+		.zone = page_zone(pfn_to_page(start)),
+		.sync = true,
+		.ignore_skip_hint = true,
+	};
+	INIT_LIST_HEAD(&cc.migratepages);
+
 	/*
 	 * What we do here is we mark all pageblocks in range as
 	 * MIGRATE_ISOLATE.  Because pageblock and max order pages may
@@ -5880,7 +5913,7 @@
 
 	zone->cma_alloc = 1;
 
-	ret = __alloc_contig_migrate_range(start, end);
+	ret = __alloc_contig_migrate_range(&cc, start, end);
 	if (ret)
 		goto done;
 
@@ -5924,7 +5957,7 @@
 
 
 	/* Grab isolated pages from freelists. */
-	outer_end = isolate_freepages_range(outer_start, end);
+	outer_end = isolate_freepages_range(&cc, outer_start, end);
 	if (!outer_end) {
 		ret = -EBUSY;
 		goto done;
@@ -5945,8 +5978,15 @@
 
 void free_contig_range(unsigned long pfn, unsigned nr_pages)
 {
-	for (; nr_pages--; ++pfn)
-		__free_page(pfn_to_page(pfn));
+	unsigned int count = 0;
+
+	for (; nr_pages--; pfn++) {
+		struct page *page = pfn_to_page(pfn);
+
+		count += page_count(page) != 1;
+		__free_page(page);
+	}
+	WARN(count != 0, "%d pages are still in use!\n", count);
 }
 #endif
 
diff --git a/mm/rmap.c b/mm/rmap.c
index 5b5ad58..0f3b7cd 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -755,12 +755,6 @@
 		pte_unmap_unlock(pte, ptl);
 	}
 
-	/* Pretend the page is referenced if the task has the
-	   swap token and is in the middle of a page fault. */
-	if (mm != current->mm && has_swap_token(mm) &&
-			rwsem_is_locked(&mm->mmap_sem))
-		referenced++;
-
 	(*mapcount)--;
 
 	if (referenced)
diff --git a/mm/thrash.c b/mm/thrash.c
deleted file mode 100644
index 57ad495..0000000
--- a/mm/thrash.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * mm/thrash.c
- *
- * Copyright (C) 2004, Red Hat, Inc.
- * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
- * Released under the GPL, see the file COPYING for details.
- *
- * Simple token based thrashing protection, using the algorithm
- * described in: http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/abs05-1.html
- *
- * Sep 2006, Ashwin Chaugule <ashwin.chaugule@celunite.com>
- * Improved algorithm to pass token:
- * Each task has a priority which is incremented if it contended
- * for the token in an interval less than its previous attempt.
- * If the token is acquired, that task's priority is boosted to prevent
- * the token from bouncing around too often and to let the task make
- * some progress in its execution.
- */
-
-#include <linux/jiffies.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/swap.h>
-#include <linux/memcontrol.h>
-
-#include <trace/events/vmscan.h>
-
-#define TOKEN_AGING_INTERVAL	(0xFF)
-
-static DEFINE_SPINLOCK(swap_token_lock);
-struct mm_struct *swap_token_mm;
-static struct mem_cgroup *swap_token_memcg;
-
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR
-static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
-{
-	struct mem_cgroup *memcg;
-
-	memcg = try_get_mem_cgroup_from_mm(mm);
-	if (memcg)
-		css_put(mem_cgroup_css(memcg));
-
-	return memcg;
-}
-#else
-static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
-{
-	return NULL;
-}
-#endif
-
-void grab_swap_token(struct mm_struct *mm)
-{
-	int current_interval;
-	unsigned int old_prio = mm->token_priority;
-	static unsigned int global_faults;
-	static unsigned int last_aging;
-
-	global_faults++;
-
-	current_interval = global_faults - mm->faultstamp;
-
-	if (!spin_trylock(&swap_token_lock))
-		return;
-
-	/* First come first served */
-	if (!swap_token_mm)
-		goto replace_token;
-
-	/*
-	 * Usually, we don't need priority aging because long interval faults
-	 * makes priority decrease quickly. But there is one exception. If the
-	 * token owner task is sleeping, it never make long interval faults.
-	 * Thus, we need a priority aging mechanism instead. The requirements
-	 * of priority aging are
-	 *  1) An aging interval is reasonable enough long. Too short aging
-	 *     interval makes quick swap token lost and decrease performance.
-	 *  2) The swap token owner task have to get priority aging even if
-	 *     it's under sleep.
-	 */
-	if ((global_faults - last_aging) > TOKEN_AGING_INTERVAL) {
-		swap_token_mm->token_priority /= 2;
-		last_aging = global_faults;
-	}
-
-	if (mm == swap_token_mm) {
-		mm->token_priority += 2;
-		goto update_priority;
-	}
-
-	if (current_interval < mm->last_interval)
-		mm->token_priority++;
-	else {
-		if (likely(mm->token_priority > 0))
-			mm->token_priority--;
-	}
-
-	/* Check if we deserve the token */
-	if (mm->token_priority > swap_token_mm->token_priority)
-		goto replace_token;
-
-update_priority:
-	trace_update_swap_token_priority(mm, old_prio, swap_token_mm);
-
-out:
-	mm->faultstamp = global_faults;
-	mm->last_interval = current_interval;
-	spin_unlock(&swap_token_lock);
-	return;
-
-replace_token:
-	mm->token_priority += 2;
-	trace_replace_swap_token(swap_token_mm, mm);
-	swap_token_mm = mm;
-	swap_token_memcg = swap_token_memcg_from_mm(mm);
-	last_aging = global_faults;
-	goto out;
-}
-
-/* Called on process exit. */
-void __put_swap_token(struct mm_struct *mm)
-{
-	spin_lock(&swap_token_lock);
-	if (likely(mm == swap_token_mm)) {
-		trace_put_swap_token(swap_token_mm);
-		swap_token_mm = NULL;
-		swap_token_memcg = NULL;
-	}
-	spin_unlock(&swap_token_lock);
-}
-
-static bool match_memcg(struct mem_cgroup *a, struct mem_cgroup *b)
-{
-	if (!a)
-		return true;
-	if (!b)
-		return true;
-	if (a == b)
-		return true;
-	return false;
-}
-
-void disable_swap_token(struct mem_cgroup *memcg)
-{
-	/* memcg reclaim don't disable unrelated mm token. */
-	if (match_memcg(memcg, swap_token_memcg)) {
-		spin_lock(&swap_token_lock);
-		if (match_memcg(memcg, swap_token_memcg)) {
-			trace_disable_swap_token(swap_token_mm);
-			swap_token_mm = NULL;
-			swap_token_memcg = NULL;
-		}
-		spin_unlock(&swap_token_lock);
-	}
-}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 33dc256..c69f5e2 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -53,24 +53,6 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/vmscan.h>
 
-/*
- * reclaim_mode determines how the inactive list is shrunk
- * RECLAIM_MODE_SINGLE: Reclaim only order-0 pages
- * RECLAIM_MODE_ASYNC:  Do not block
- * RECLAIM_MODE_SYNC:   Allow blocking e.g. call wait_on_page_writeback
- * RECLAIM_MODE_LUMPYRECLAIM: For high-order allocations, take a reference
- *			page from the LRU and reclaim all pages within a
- *			naturally aligned range
- * RECLAIM_MODE_COMPACTION: For high-order allocations, reclaim a number of
- *			order-0 pages and then compact the zone
- */
-typedef unsigned __bitwise__ reclaim_mode_t;
-#define RECLAIM_MODE_SINGLE		((__force reclaim_mode_t)0x01u)
-#define RECLAIM_MODE_ASYNC		((__force reclaim_mode_t)0x02u)
-#define RECLAIM_MODE_SYNC		((__force reclaim_mode_t)0x04u)
-#define RECLAIM_MODE_LUMPYRECLAIM	((__force reclaim_mode_t)0x08u)
-#define RECLAIM_MODE_COMPACTION		((__force reclaim_mode_t)0x10u)
-
 struct scan_control {
 	/* Incremented by the number of inactive pages that were scanned */
 	unsigned long nr_scanned;
@@ -96,11 +78,8 @@
 
 	int order;
 
-	/*
-	 * Intend to reclaim enough continuous memory rather than reclaim
-	 * enough amount of memory. i.e, mode for high order allocation.
-	 */
-	reclaim_mode_t reclaim_mode;
+	/* Scan (total_size >> priority) pages at once */
+	int priority;
 
 	/*
 	 * The memory cgroup that hit its limit and as a result is the
@@ -164,26 +143,16 @@
 {
 	return !sc->target_mem_cgroup;
 }
-
-static bool scanning_global_lru(struct mem_cgroup_zone *mz)
-{
-	return !mz->mem_cgroup;
-}
 #else
 static bool global_reclaim(struct scan_control *sc)
 {
 	return true;
 }
-
-static bool scanning_global_lru(struct mem_cgroup_zone *mz)
-{
-	return true;
-}
 #endif
 
 static struct zone_reclaim_stat *get_reclaim_stat(struct mem_cgroup_zone *mz)
 {
-	if (!scanning_global_lru(mz))
+	if (!mem_cgroup_disabled())
 		return mem_cgroup_get_reclaim_stat(mz->mem_cgroup, mz->zone);
 
 	return &mz->zone->reclaim_stat;
@@ -192,7 +161,7 @@
 static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
 				       enum lru_list lru)
 {
-	if (!scanning_global_lru(mz))
+	if (!mem_cgroup_disabled())
 		return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
 						    zone_to_nid(mz->zone),
 						    zone_idx(mz->zone),
@@ -364,39 +333,6 @@
 	return ret;
 }
 
-static void set_reclaim_mode(int priority, struct scan_control *sc,
-				   bool sync)
-{
-	reclaim_mode_t syncmode = sync ? RECLAIM_MODE_SYNC : RECLAIM_MODE_ASYNC;
-
-	/*
-	 * Initially assume we are entering either lumpy reclaim or
-	 * reclaim/compaction.Depending on the order, we will either set the
-	 * sync mode or just reclaim order-0 pages later.
-	 */
-	if (COMPACTION_BUILD)
-		sc->reclaim_mode = RECLAIM_MODE_COMPACTION;
-	else
-		sc->reclaim_mode = RECLAIM_MODE_LUMPYRECLAIM;
-
-	/*
-	 * Avoid using lumpy reclaim or reclaim/compaction if possible by
-	 * restricting when its set to either costly allocations or when
-	 * under memory pressure
-	 */
-	if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-		sc->reclaim_mode |= syncmode;
-	else if (sc->order && priority < DEF_PRIORITY - 2)
-		sc->reclaim_mode |= syncmode;
-	else
-		sc->reclaim_mode = RECLAIM_MODE_SINGLE | RECLAIM_MODE_ASYNC;
-}
-
-static void reset_reclaim_mode(struct scan_control *sc)
-{
-	sc->reclaim_mode = RECLAIM_MODE_SINGLE | RECLAIM_MODE_ASYNC;
-}
-
 static inline int is_page_cache_freeable(struct page *page)
 {
 	/*
@@ -416,10 +352,6 @@
 		return 1;
 	if (bdi == current->backing_dev_info)
 		return 1;
-
-	/* lumpy reclaim for hugepage often need a lot of write */
-	if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-		return 1;
 	return 0;
 }
 
@@ -523,8 +455,7 @@
 			/* synchronous write or broken a_ops? */
 			ClearPageReclaim(page);
 		}
-		trace_mm_vmscan_writepage(page,
-			trace_reclaim_flags(page, sc->reclaim_mode));
+		trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
 		inc_zone_page_state(page, NR_VMSCAN_WRITE);
 		return PAGE_SUCCESS;
 	}
@@ -701,19 +632,15 @@
 };
 
 static enum page_references page_check_references(struct page *page,
-						  struct mem_cgroup_zone *mz,
 						  struct scan_control *sc)
 {
 	int referenced_ptes, referenced_page;
 	unsigned long vm_flags;
 
-	referenced_ptes = page_referenced(page, 1, mz->mem_cgroup, &vm_flags);
+	referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup,
+					  &vm_flags);
 	referenced_page = TestClearPageReferenced(page);
 
-	/* Lumpy reclaim - ignore references */
-	if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
-		return PAGEREF_RECLAIM;
-
 	/*
 	 * Mlock lost the isolation race with us.  Let try_to_unmap()
 	 * move the page to the unevictable list.
@@ -763,11 +690,12 @@
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-				      struct mem_cgroup_zone *mz,
+				      struct zone *zone,
 				      struct scan_control *sc,
-				      int priority,
+				      enum ttu_flags ttu_flags,
 				      unsigned long *ret_nr_dirty,
-				      unsigned long *ret_nr_writeback)
+				      unsigned long *ret_nr_writeback,
+				      bool force_reclaim)
 {
 	LIST_HEAD(ret_pages);
 	LIST_HEAD(free_pages);
@@ -780,10 +708,10 @@
 	cond_resched();
 
 	while (!list_empty(page_list)) {
-		enum page_references references;
 		struct address_space *mapping;
 		struct page *page;
 		int may_enter_fs;
+		enum page_references references = PAGEREF_RECLAIM_CLEAN;
 
 		cond_resched();
 
@@ -794,7 +722,7 @@
 			goto keep;
 
 		VM_BUG_ON(PageActive(page));
-		VM_BUG_ON(page_zone(page) != mz->zone);
+		VM_BUG_ON(page_zone(page) != zone);
 
 		sc->nr_scanned++;
 
@@ -813,22 +741,13 @@
 
 		if (PageWriteback(page)) {
 			nr_writeback++;
-			/*
-			 * Synchronous reclaim cannot queue pages for
-			 * writeback due to the possibility of stack overflow
-			 * but if it encounters a page under writeback, wait
-			 * for the IO to complete.
-			 */
-			if ((sc->reclaim_mode & RECLAIM_MODE_SYNC) &&
-			    may_enter_fs)
-				wait_on_page_writeback(page);
-			else {
-				unlock_page(page);
-				goto keep_lumpy;
-			}
+			unlock_page(page);
+			goto keep;
 		}
 
-		references = page_check_references(page, mz, sc);
+		if (!force_reclaim)
+			references = page_check_references(page, sc);
+
 		switch (references) {
 		case PAGEREF_ACTIVATE:
 			goto activate_locked;
@@ -858,7 +777,7 @@
 		 * processes. Try to unmap it here.
 		 */
 		if (page_mapped(page) && mapping) {
-			switch (try_to_unmap(page, TTU_UNMAP)) {
+			switch (try_to_unmap(page, ttu_flags)) {
 			case SWAP_FAIL:
 				goto activate_locked;
 			case SWAP_AGAIN:
@@ -879,7 +798,8 @@
 			 * unless under significant pressure.
 			 */
 			if (page_is_file_cache(page) &&
-					(!current_is_kswapd() || priority >= DEF_PRIORITY - 2)) {
+					(!current_is_kswapd() ||
+					 sc->priority >= DEF_PRIORITY - 2)) {
 				/*
 				 * Immediately reclaim when written back.
 				 * Similar in principal to deactivate_page()
@@ -908,7 +828,7 @@
 				goto activate_locked;
 			case PAGE_SUCCESS:
 				if (PageWriteback(page))
-					goto keep_lumpy;
+					goto keep;
 				if (PageDirty(page))
 					goto keep;
 
@@ -994,7 +914,6 @@
 			try_to_free_swap(page);
 		unlock_page(page);
 		putback_lru_page(page);
-		reset_reclaim_mode(sc);
 		continue;
 
 activate_locked:
@@ -1007,8 +926,6 @@
 keep_locked:
 		unlock_page(page);
 keep:
-		reset_reclaim_mode(sc);
-keep_lumpy:
 		list_add(&page->lru, &ret_pages);
 		VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
 	}
@@ -1020,7 +937,7 @@
 	 * will encounter the same problem
 	 */
 	if (nr_dirty && nr_dirty == nr_congested && global_reclaim(sc))
-		zone_set_flag(mz->zone, ZONE_CONGESTED);
+		zone_set_flag(zone, ZONE_CONGESTED);
 
 	free_hot_cold_page_list(&free_pages, 1);
 
@@ -1031,6 +948,33 @@
 	return nr_reclaimed;
 }
 
+unsigned long reclaim_clean_pages_from_list(struct zone *zone,
+					    struct list_head *page_list)
+{
+	struct scan_control sc = {
+		.gfp_mask = GFP_KERNEL,
+		.priority = DEF_PRIORITY,
+		.may_unmap = 1,
+	};
+	unsigned long ret, dummy1, dummy2;
+	struct page *page, *next;
+	LIST_HEAD(clean_pages);
+
+	list_for_each_entry_safe(page, next, page_list, lru) {
+		if (page_is_file_cache(page) && !PageDirty(page)) {
+			ClearPageActive(page);
+			list_move(&page->lru, &clean_pages);
+		}
+	}
+
+	ret = shrink_page_list(&clean_pages, zone, &sc,
+				TTU_UNMAP|TTU_IGNORE_ACCESS,
+				&dummy1, &dummy2, true);
+	list_splice(&clean_pages, page_list);
+	__mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret);
+	return ret;
+}
+
 /*
  * Attempt to remove the specified page from its LRU.  Only take this page
  * if it is of the appropriate PageActive status.  Pages which are being
@@ -1041,35 +985,16 @@
  *
  * returns 0 on success, -ve errno on failure.
  */
-int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
+int __isolate_lru_page(struct page *page, isolate_mode_t mode)
 {
-	bool all_lru_mode;
 	int ret = -EINVAL;
 
 	/* Only take pages on the LRU. */
 	if (!PageLRU(page))
 		return ret;
 
-	all_lru_mode = (mode & (ISOLATE_ACTIVE|ISOLATE_INACTIVE)) ==
-		(ISOLATE_ACTIVE|ISOLATE_INACTIVE);
-
-	/*
-	 * When checking the active state, we need to be sure we are
-	 * dealing with comparible boolean values.  Take the logical not
-	 * of each.
-	 */
-	if (!all_lru_mode && !PageActive(page) != !(mode & ISOLATE_ACTIVE))
-		return ret;
-
-	if (!all_lru_mode && !!page_is_file_cache(page) != file)
-		return ret;
-
-	/*
-	 * When this function is being called for lumpy reclaim, we
-	 * initially look into all LRU pages, active, inactive and
-	 * unevictable; only give shrink_page_list evictable pages.
-	 */
-	if (PageUnevictable(page))
+	/* Compaction should not handle unevictable pages but CMA can do so */
+	if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE))
 		return ret;
 
 	ret = -EBUSY;
@@ -1135,52 +1060,38 @@
  * Appropriate locks must be held before calling this function.
  *
  * @nr_to_scan:	The number of pages to look through on the list.
- * @mz:		The mem_cgroup_zone to pull pages from.
+ * @lruvec:	The LRU vector to pull pages from.
  * @dst:	The temp list to put pages on to.
  * @nr_scanned:	The number of pages that were scanned.
  * @sc:		The scan_control struct for this reclaim session
  * @mode:	One of the LRU isolation modes
- * @active:	True [1] if isolating active pages
- * @file:	True [1] if isolating file [!anon] pages
+ * @lru:	LRU list id for isolating
  *
  * returns how many pages were moved onto *@dst.
  */
 static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
-		struct mem_cgroup_zone *mz, struct list_head *dst,
+		struct lruvec *lruvec, struct list_head *dst,
 		unsigned long *nr_scanned, struct scan_control *sc,
-		isolate_mode_t mode, int active, int file)
+		isolate_mode_t mode, enum lru_list lru)
 {
-	struct lruvec *lruvec;
 	struct list_head *src;
 	unsigned long nr_taken = 0;
-	unsigned long nr_lumpy_taken = 0;
-	unsigned long nr_lumpy_dirty = 0;
-	unsigned long nr_lumpy_failed = 0;
 	unsigned long scan;
-	int lru = LRU_BASE;
+	int file = is_file_lru(lru);
 
-	lruvec = mem_cgroup_zone_lruvec(mz->zone, mz->mem_cgroup);
-	if (active)
-		lru += LRU_ACTIVE;
-	if (file)
-		lru += LRU_FILE;
 	src = &lruvec->lists[lru];
 
 	for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) {
 		struct page *page;
-		unsigned long pfn;
-		unsigned long end_pfn;
-		unsigned long page_pfn;
-		int zone_id;
 
 		page = lru_to_page(src);
 		prefetchw_prev_lru_page(page, src, flags);
 
 		VM_BUG_ON(!PageLRU(page));
 
-		switch (__isolate_lru_page(page, mode, file)) {
+		switch (__isolate_lru_page(page, mode)) {
 		case 0:
-			mem_cgroup_lru_del(page);
+			mem_cgroup_lru_del_list(page, lru);
 			list_move(&page->lru, dst);
 			nr_taken += hpage_nr_pages(page);
 			break;
@@ -1193,84 +1104,6 @@
 		default:
 			BUG();
 		}
-
-		if (!sc->order || !(sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM))
-			continue;
-
-		/*
-		 * Attempt to take all pages in the order aligned region
-		 * surrounding the tag page.  Only take those pages of
-		 * the same active state as that tag page.  We may safely
-		 * round the target page pfn down to the requested order
-		 * as the mem_map is guaranteed valid out to MAX_ORDER,
-		 * where that page is in a different zone we will detect
-		 * it from its zone id and abort this block scan.
-		 */
-		zone_id = page_zone_id(page);
-		page_pfn = page_to_pfn(page);
-		pfn = page_pfn & ~((1 << sc->order) - 1);
-		end_pfn = pfn + (1 << sc->order);
-		for (; pfn < end_pfn; pfn++) {
-			struct page *cursor_page;
-
-			/* The target page is in the block, ignore it. */
-			if (unlikely(pfn == page_pfn))
-				continue;
-
-			/* Avoid holes within the zone. */
-			if (unlikely(!pfn_valid_within(pfn)))
-				break;
-
-			cursor_page = pfn_to_page(pfn);
-
-			/* Check that we have not crossed a zone boundary. */
-			if (unlikely(page_zone_id(cursor_page) != zone_id))
-				break;
-
-			/*
-			 * If we don't have enough swap space, reclaiming of
-			 * anon page which don't already have a swap slot is
-			 * pointless.
-			 */
-			if (nr_swap_pages <= 0 && PageSwapBacked(cursor_page) &&
-			    !PageSwapCache(cursor_page))
-				break;
-
-			if (__isolate_lru_page(cursor_page, mode, file) == 0) {
-				unsigned int isolated_pages;
-
-				mem_cgroup_lru_del(cursor_page);
-				list_move(&cursor_page->lru, dst);
-				isolated_pages = hpage_nr_pages(cursor_page);
-				nr_taken += isolated_pages;
-				nr_lumpy_taken += isolated_pages;
-				if (PageDirty(cursor_page))
-					nr_lumpy_dirty += isolated_pages;
-				scan++;
-				pfn += isolated_pages - 1;
-			} else {
-				/*
-				 * Check if the page is freed already.
-				 *
-				 * We can't use page_count() as that
-				 * requires compound_head and we don't
-				 * have a pin on the page here. If a
-				 * page is tail, we may or may not
-				 * have isolated the head, so assume
-				 * it's not free, it'd be tricky to
-				 * track the head status without a
-				 * page pin.
-				 */
-				if (!PageTail(cursor_page) &&
-				    !atomic_read(&cursor_page->_count))
-					continue;
-				break;
-			}
-		}
-
-		/* If we break out of the loop above, lumpy reclaim failed */
-		if (pfn < end_pfn)
-			nr_lumpy_failed++;
 	}
 
 	*nr_scanned = scan;
@@ -1278,7 +1111,6 @@
 	trace_mm_vmscan_lru_isolate(sc->order,
 			nr_to_scan, scan,
 			nr_taken,
-			nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed,
 			mode, file);
 	return nr_taken;
 }
@@ -1407,112 +1239,25 @@
 	list_splice(&pages_to_free, page_list);
 }
 
-static noinline_for_stack void
-update_isolated_counts(struct mem_cgroup_zone *mz,
-		       struct list_head *page_list,
-		       unsigned long *nr_anon,
-		       unsigned long *nr_file)
-{
-	struct zone *zone = mz->zone;
-	unsigned int count[NR_LRU_LISTS] = { 0, };
-	unsigned long nr_active = 0;
-	struct page *page;
-	int lru;
-
-	/*
-	 * Count pages and clear active flags
-	 */
-	list_for_each_entry(page, page_list, lru) {
-		int numpages = hpage_nr_pages(page);
-		lru = page_lru_base_type(page);
-		if (PageActive(page)) {
-			lru += LRU_ACTIVE;
-			ClearPageActive(page);
-			nr_active += numpages;
-		}
-		count[lru] += numpages;
-	}
-
-	preempt_disable();
-	__count_vm_events(PGDEACTIVATE, nr_active);
-
-	__mod_zone_page_state(zone, NR_ACTIVE_FILE,
-			      -count[LRU_ACTIVE_FILE]);
-	__mod_zone_page_state(zone, NR_INACTIVE_FILE,
-			      -count[LRU_INACTIVE_FILE]);
-	__mod_zone_page_state(zone, NR_ACTIVE_ANON,
-			      -count[LRU_ACTIVE_ANON]);
-	__mod_zone_page_state(zone, NR_INACTIVE_ANON,
-			      -count[LRU_INACTIVE_ANON]);
-
-	*nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
-	*nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
-
-	__mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
-	__mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
-	preempt_enable();
-}
-
-/*
- * Returns true if a direct reclaim should wait on pages under writeback.
- *
- * If we are direct reclaiming for contiguous pages and we do not reclaim
- * everything in the list, try again and wait for writeback IO to complete.
- * This will stall high-order allocations noticeably. Only do that when really
- * need to free the pages under high memory pressure.
- */
-static inline bool should_reclaim_stall(unsigned long nr_taken,
-					unsigned long nr_freed,
-					int priority,
-					struct scan_control *sc)
-{
-	int lumpy_stall_priority;
-
-	/* kswapd should not stall on sync IO */
-	if (current_is_kswapd())
-		return false;
-
-	/* Only stall on lumpy reclaim */
-	if (sc->reclaim_mode & RECLAIM_MODE_SINGLE)
-		return false;
-
-	/* If we have reclaimed everything on the isolated list, no stall */
-	if (nr_freed == nr_taken)
-		return false;
-
-	/*
-	 * For high-order allocations, there are two stall thresholds.
-	 * High-cost allocations stall immediately where as lower
-	 * order allocations such as stacks require the scanning
-	 * priority to be much higher before stalling.
-	 */
-	if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-		lumpy_stall_priority = DEF_PRIORITY;
-	else
-		lumpy_stall_priority = DEF_PRIORITY / 3;
-
-	return priority <= lumpy_stall_priority;
-}
-
 /*
  * shrink_inactive_list() is a helper for shrink_zone().  It returns the number
  * of reclaimed pages
  */
 static noinline_for_stack unsigned long
 shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
-		     struct scan_control *sc, int priority, int file)
+		     struct scan_control *sc, enum lru_list lru)
 {
 	LIST_HEAD(page_list);
 	unsigned long nr_scanned;
 	unsigned long nr_reclaimed = 0;
 	unsigned long nr_taken;
-	unsigned long nr_anon;
-	unsigned long nr_file;
 	unsigned long nr_dirty = 0;
 	unsigned long nr_writeback = 0;
-	isolate_mode_t isolate_mode = ISOLATE_INACTIVE;
+	isolate_mode_t isolate_mode = 0;
+	int file = is_file_lru(lru);
 	struct zone *zone = mz->zone;
 	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+	struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, mz->mem_cgroup);
 
 	while (unlikely(too_many_isolated(zone, file, sc))) {
 		congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1522,10 +1267,6 @@
 			return SWAP_CLUSTER_MAX;
 	}
 
-	set_reclaim_mode(priority, sc, false);
-	if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
-		isolate_mode |= ISOLATE_ACTIVE;
-
 	lru_add_drain();
 
 	if (!sc->may_unmap)
@@ -1535,8 +1276,12 @@
 
 	spin_lock_irq(&zone->lru_lock);
 
-	nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list, &nr_scanned,
-				     sc, isolate_mode, 0, file);
+	nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &page_list,
+				     &nr_scanned, sc, isolate_mode, lru);
+
+	__mod_zone_page_state(zone, NR_LRU_BASE + lru, -nr_taken);
+	__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+
 	if (global_reclaim(sc)) {
 		zone->pages_scanned += nr_scanned;
 		if (current_is_kswapd())
@@ -1551,22 +1296,12 @@
 	if (nr_taken == 0)
 		return 0;
 
-	update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
-
-	nr_reclaimed = shrink_page_list(&page_list, mz, sc, priority,
-						&nr_dirty, &nr_writeback);
-
-	/* Check if we should syncronously wait for writeback */
-	if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
-		set_reclaim_mode(priority, sc, true);
-		nr_reclaimed += shrink_page_list(&page_list, mz, sc,
-					priority, &nr_dirty, &nr_writeback);
-	}
+	nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP,
+					&nr_dirty, &nr_writeback, false);
 
 	spin_lock_irq(&zone->lru_lock);
 
-	reclaim_stat->recent_scanned[0] += nr_anon;
-	reclaim_stat->recent_scanned[1] += nr_file;
+	reclaim_stat->recent_scanned[file] += nr_taken;
 
 	if (global_reclaim(sc)) {
 		if (current_is_kswapd())
@@ -1579,8 +1314,7 @@
 
 	putback_inactive_pages(mz, &page_list);
 
-	__mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
-	__mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
+	__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
 
 	spin_unlock_irq(&zone->lru_lock);
 
@@ -1609,14 +1343,15 @@
 	 * DEF_PRIORITY-6 For SWAP_CLUSTER_MAX isolated pages, throttle if any
 	 *                     isolated page is PageWriteback
 	 */
-	if (nr_writeback && nr_writeback >= (nr_taken >> (DEF_PRIORITY-priority)))
+	if (nr_writeback && nr_writeback >=
+			(nr_taken >> (DEF_PRIORITY - sc->priority)))
 		wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
 
 	trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
 		zone_idx(zone),
 		nr_scanned, nr_reclaimed,
-		priority,
-		trace_shrink_flags(file, sc->reclaim_mode));
+		sc->priority,
+		trace_shrink_flags(file));
 	return nr_reclaimed;
 }
 
@@ -1679,7 +1414,7 @@
 static void shrink_active_list(unsigned long nr_to_scan,
 			       struct mem_cgroup_zone *mz,
 			       struct scan_control *sc,
-			       int priority, int file)
+			       enum lru_list lru)
 {
 	unsigned long nr_taken;
 	unsigned long nr_scanned;
@@ -1690,13 +1425,13 @@
 	struct page *page;
 	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
 	unsigned long nr_rotated = 0;
-	isolate_mode_t isolate_mode = ISOLATE_ACTIVE;
+	isolate_mode_t isolate_mode = 0;
+	int file = is_file_lru(lru);
 	struct zone *zone = mz->zone;
+	struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, mz->mem_cgroup);
 
 	lru_add_drain();
 
-	reset_reclaim_mode(sc);
-
 	if (!sc->may_unmap)
 		isolate_mode |= ISOLATE_UNMAPPED;
 	if (!sc->may_writepage)
@@ -1704,18 +1439,15 @@
 
 	spin_lock_irq(&zone->lru_lock);
 
-	nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold, &nr_scanned, sc,
-				     isolate_mode, 1, file);
+	nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &l_hold,
+				     &nr_scanned, sc, isolate_mode, lru);
 	if (global_reclaim(sc))
 		zone->pages_scanned += nr_scanned;
 
 	reclaim_stat->recent_scanned[file] += nr_taken;
 
 	__count_zone_vm_events(PGREFILL, zone, nr_scanned);
-	if (file)
-		__mod_zone_page_state(zone, NR_ACTIVE_FILE, -nr_taken);
-	else
-		__mod_zone_page_state(zone, NR_ACTIVE_ANON, -nr_taken);
+	__mod_zone_page_state(zone, NR_LRU_BASE + lru, -nr_taken);
 	__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
 	spin_unlock_irq(&zone->lru_lock);
 
@@ -1737,7 +1469,8 @@
 			}
 		}
 
-		if (page_referenced(page, 0, mz->mem_cgroup, &vm_flags)) {
+		if (page_referenced(page, 0, sc->target_mem_cgroup,
+				    &vm_flags)) {
 			nr_rotated += hpage_nr_pages(page);
 			/*
 			 * Identify referenced, file-backed active pages and
@@ -1770,10 +1503,8 @@
 	 */
 	reclaim_stat->recent_rotated[file] += nr_rotated;
 
-	move_active_pages_to_lru(zone, &l_active, &l_hold,
-						LRU_ACTIVE + file * LRU_FILE);
-	move_active_pages_to_lru(zone, &l_inactive, &l_hold,
-						LRU_BASE   + file * LRU_FILE);
+	move_active_pages_to_lru(zone, &l_active, &l_hold, lru);
+	move_active_pages_to_lru(zone, &l_inactive, &l_hold, lru - LRU_ACTIVE);
 	__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
 	spin_unlock_irq(&zone->lru_lock);
 
@@ -1811,7 +1542,7 @@
 	if (!total_swap_pages)
 		return 0;
 
-	if (!scanning_global_lru(mz))
+	if (!mem_cgroup_disabled())
 		return mem_cgroup_inactive_anon_is_low(mz->mem_cgroup,
 						       mz->zone);
 
@@ -1850,7 +1581,7 @@
  */
 static int inactive_file_is_low(struct mem_cgroup_zone *mz)
 {
-	if (!scanning_global_lru(mz))
+	if (!mem_cgroup_disabled())
 		return mem_cgroup_inactive_file_is_low(mz->mem_cgroup,
 						       mz->zone);
 
@@ -1867,25 +1598,24 @@
 
 static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
 				 struct mem_cgroup_zone *mz,
-				 struct scan_control *sc, int priority)
+				 struct scan_control *sc)
 {
 	int file = is_file_lru(lru);
 
 	if (is_active_lru(lru)) {
 		if (inactive_list_is_low(mz, file))
-			shrink_active_list(nr_to_scan, mz, sc, priority, file);
+			shrink_active_list(nr_to_scan, mz, sc, lru);
 		return 0;
 	}
 
-	return shrink_inactive_list(nr_to_scan, mz, sc, priority, file);
+	return shrink_inactive_list(nr_to_scan, mz, sc, lru);
 }
 
-static int vmscan_swappiness(struct mem_cgroup_zone *mz,
-			     struct scan_control *sc)
+static int vmscan_swappiness(struct scan_control *sc)
 {
 	if (global_reclaim(sc))
 		return vm_swappiness;
-	return mem_cgroup_swappiness(mz->mem_cgroup);
+	return mem_cgroup_swappiness(sc->target_mem_cgroup);
 }
 
 /*
@@ -1897,7 +1627,7 @@
  * nr[0] = anon pages to scan; nr[1] = file pages to scan
  */
 static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc,
-			   unsigned long *nr, int priority)
+			   unsigned long *nr)
 {
 	unsigned long anon, file, free;
 	unsigned long anon_prio, file_prio;
@@ -1953,8 +1683,8 @@
 	 * With swappiness at 100, anonymous and file have the same priority.
 	 * This scanning priority is essentially the inverse of IO cost.
 	 */
-	anon_prio = vmscan_swappiness(mz, sc);
-	file_prio = 200 - vmscan_swappiness(mz, sc);
+	anon_prio = vmscan_swappiness(sc);
+	file_prio = 200 - vmscan_swappiness(sc);
 
 	/*
 	 * OK, so we have swap space and a fair amount of page cache
@@ -1983,10 +1713,10 @@
 	 * proportional to the fraction of recently scanned pages on
 	 * each list that were recently referenced and in active use.
 	 */
-	ap = (anon_prio + 1) * (reclaim_stat->recent_scanned[0] + 1);
+	ap = anon_prio * (reclaim_stat->recent_scanned[0] + 1);
 	ap /= reclaim_stat->recent_rotated[0] + 1;
 
-	fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1);
+	fp = file_prio * (reclaim_stat->recent_scanned[1] + 1);
 	fp /= reclaim_stat->recent_rotated[1] + 1;
 	spin_unlock_irq(&mz->zone->lru_lock);
 
@@ -1999,8 +1729,8 @@
 		unsigned long scan;
 
 		scan = zone_nr_lru_pages(mz, lru);
-		if (priority || noswap) {
-			scan >>= priority;
+		if (sc->priority || noswap || !vmscan_swappiness(sc)) {
+			scan >>= sc->priority;
 			if (!scan && force_scan)
 				scan = SWAP_CLUSTER_MAX;
 			scan = div64_u64(scan * fraction[file], denominator);
@@ -2009,12 +1739,23 @@
 	}
 }
 
+/* Use reclaim/compaction for costly allocs or under memory pressure */
+static bool in_reclaim_compaction(struct scan_control *sc)
+{
+	if (COMPACTION_BUILD && sc->order &&
+			(sc->order > PAGE_ALLOC_COSTLY_ORDER ||
+			 sc->priority < DEF_PRIORITY - 2))
+		return true;
+
+	return false;
+}
+
 /*
- * Reclaim/compaction depends on a number of pages being freed. To avoid
- * disruption to the system, a small number of order-0 pages continue to be
- * rotated and reclaimed in the normal fashion. However, by the time we get
- * back to the allocator and call try_to_compact_zone(), we ensure that
- * there are enough free pages for it to be likely successful
+ * Reclaim/compaction is used for high-order allocation requests. It reclaims
+ * order-0 pages before compacting the zone. should_continue_reclaim() returns
+ * true if more pages should be reclaimed such that when the page allocator
+ * calls try_to_compact_zone() that it will have enough free pages to succeed.
+ * It will give up earlier than that if there is difficulty reclaiming pages.
  */
 static inline bool should_continue_reclaim(struct mem_cgroup_zone *mz,
 					unsigned long nr_reclaimed,
@@ -2025,7 +1766,7 @@
 	unsigned long inactive_lru_pages;
 
 	/* If not in reclaim/compaction mode, stop */
-	if (!(sc->reclaim_mode & RECLAIM_MODE_COMPACTION))
+	if (!in_reclaim_compaction(sc))
 		return false;
 
 	/* Consider stopping depending on scan and reclaim activity */
@@ -2076,7 +1817,7 @@
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
-static void shrink_mem_cgroup_zone(int priority, struct mem_cgroup_zone *mz,
+static void shrink_mem_cgroup_zone(struct mem_cgroup_zone *mz,
 				   struct scan_control *sc)
 {
 	unsigned long nr[NR_LRU_LISTS];
@@ -2089,7 +1830,7 @@
 restart:
 	nr_reclaimed = 0;
 	nr_scanned = sc->nr_scanned;
-	get_scan_count(mz, sc, nr, priority);
+	get_scan_count(mz, sc, nr);
 
 	blk_start_plug(&plug);
 	while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
@@ -2101,7 +1842,7 @@
 				nr[lru] -= nr_to_scan;
 
 				nr_reclaimed += shrink_list(lru, nr_to_scan,
-							    mz, sc, priority);
+							    mz, sc);
 			}
 		}
 		/*
@@ -2112,7 +1853,8 @@
 		 * with multiple processes reclaiming pages, the total
 		 * freeing target can get unreasonably large.
 		 */
-		if (nr_reclaimed >= nr_to_reclaim && priority < DEF_PRIORITY)
+		if (nr_reclaimed >= nr_to_reclaim &&
+		    sc->priority < DEF_PRIORITY)
 			break;
 	}
 	blk_finish_plug(&plug);
@@ -2123,23 +1865,23 @@
 	 * rebalance the anon lru active/inactive ratio.
 	 */
 	if (inactive_anon_is_low(mz))
-		shrink_active_list(SWAP_CLUSTER_MAX, mz, sc, priority, 0);
+		shrink_active_list(SWAP_CLUSTER_MAX, mz,
+				   sc, LRU_ACTIVE_ANON);
 
 	/* reclaim/compaction might need reclaim to continue */
 	if (should_continue_reclaim(mz, nr_reclaimed,
-					sc->nr_scanned - nr_scanned, sc))
+				    sc->nr_scanned - nr_scanned, sc))
 		goto restart;
 
 	throttle_vm_writeout(sc->gfp_mask);
 }
 
-static void shrink_zone(int priority, struct zone *zone,
-			struct scan_control *sc)
+static void shrink_zone(struct zone *zone, struct scan_control *sc)
 {
 	struct mem_cgroup *root = sc->target_mem_cgroup;
 	struct mem_cgroup_reclaim_cookie reclaim = {
 		.zone = zone,
-		.priority = priority,
+		.priority = sc->priority,
 	};
 	struct mem_cgroup *memcg;
 
@@ -2150,7 +1892,7 @@
 			.zone = zone,
 		};
 
-		shrink_mem_cgroup_zone(priority, &mz, sc);
+		shrink_mem_cgroup_zone(&mz, sc);
 		/*
 		 * Limit reclaim has historically picked one memcg and
 		 * scanned it with decreasing priority levels until
@@ -2226,8 +1968,7 @@
  * the caller that it should consider retrying the allocation instead of
  * further reclaim.
  */
-static bool shrink_zones(int priority, struct zonelist *zonelist,
-					struct scan_control *sc)
+static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
 {
 	struct zoneref *z;
 	struct zone *zone;
@@ -2254,7 +1995,8 @@
 		if (global_reclaim(sc)) {
 			if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
 				continue;
-			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+			if (zone->all_unreclaimable &&
+					sc->priority != DEF_PRIORITY)
 				continue;	/* Let kswapd poll it */
 			if (COMPACTION_BUILD) {
 				/*
@@ -2286,7 +2028,7 @@
 			/* need some check for avoid more shrink_zone() */
 		}
 
-		shrink_zone(priority, zone, sc);
+		shrink_zone(zone, sc);
 	}
 
 	return aborted_reclaim;
@@ -2337,7 +2079,6 @@
 					struct scan_control *sc,
 					struct shrink_control *shrink)
 {
-	int priority;
 	unsigned long total_scanned = 0;
 	struct reclaim_state *reclaim_state = current->reclaim_state;
 	struct zoneref *z;
@@ -2350,11 +2091,9 @@
 	if (global_reclaim(sc))
 		count_vm_event(ALLOCSTALL);
 
-	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
+	do {
 		sc->nr_scanned = 0;
-		if (!priority)
-			disable_swap_token(sc->target_mem_cgroup);
-		aborted_reclaim = shrink_zones(priority, zonelist, sc);
+		aborted_reclaim = shrink_zones(zonelist, sc);
 
 		/*
 		 * Don't shrink slabs when reclaiming memory from
@@ -2396,7 +2135,7 @@
 
 		/* Take a nap, wait for some writeback to complete */
 		if (!sc->hibernation_mode && sc->nr_scanned &&
-		    priority < DEF_PRIORITY - 2) {
+		    sc->priority < DEF_PRIORITY - 2) {
 			struct zone *preferred_zone;
 
 			first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
@@ -2404,7 +2143,7 @@
 						&preferred_zone);
 			wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
 		}
-	}
+	} while (--sc->priority >= 0);
 
 out:
 	delayacct_freepages_end();
@@ -2442,6 +2181,7 @@
 		.may_unmap = 1,
 		.may_swap = 1,
 		.order = order,
+		.priority = DEF_PRIORITY,
 		.target_mem_cgroup = NULL,
 		.nodemask = nodemask,
 	};
@@ -2474,6 +2214,7 @@
 		.may_unmap = 1,
 		.may_swap = !noswap,
 		.order = 0,
+		.priority = 0,
 		.target_mem_cgroup = memcg,
 	};
 	struct mem_cgroup_zone mz = {
@@ -2484,7 +2225,7 @@
 	sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
 			(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
 
-	trace_mm_vmscan_memcg_softlimit_reclaim_begin(0,
+	trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
 						      sc.may_writepage,
 						      sc.gfp_mask);
 
@@ -2495,7 +2236,7 @@
 	 * will pick up pages from other mem cgroup's as well. We hack
 	 * the priority and make it zero.
 	 */
-	shrink_mem_cgroup_zone(0, &mz, &sc);
+	shrink_mem_cgroup_zone(&mz, &sc);
 
 	trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -2516,6 +2257,7 @@
 		.may_swap = !noswap,
 		.nr_to_reclaim = SWAP_CLUSTER_MAX,
 		.order = 0,
+		.priority = DEF_PRIORITY,
 		.target_mem_cgroup = memcg,
 		.nodemask = NULL, /* we don't care the placement */
 		.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
@@ -2546,8 +2288,7 @@
 }
 #endif
 
-static void age_active_anon(struct zone *zone, struct scan_control *sc,
-			    int priority)
+static void age_active_anon(struct zone *zone, struct scan_control *sc)
 {
 	struct mem_cgroup *memcg;
 
@@ -2563,7 +2304,7 @@
 
 		if (inactive_anon_is_low(&mz))
 			shrink_active_list(SWAP_CLUSTER_MAX, &mz,
-					   sc, priority, 0);
+					   sc, LRU_ACTIVE_ANON);
 
 		memcg = mem_cgroup_iter(NULL, memcg, NULL);
 	} while (memcg);
@@ -2672,7 +2413,6 @@
 {
 	int all_zones_ok;
 	unsigned long balanced;
-	int priority;
 	int i;
 	int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
 	unsigned long total_scanned;
@@ -2696,18 +2436,15 @@
 	};
 loop_again:
 	total_scanned = 0;
+	sc.priority = DEF_PRIORITY;
 	sc.nr_reclaimed = 0;
 	sc.may_writepage = !laptop_mode;
 	count_vm_event(PAGEOUTRUN);
 
-	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
+	do {
 		unsigned long lru_pages = 0;
 		int has_under_min_watermark_zone = 0;
 
-		/* The swap token gets in the way of swapout... */
-		if (!priority)
-			disable_swap_token(NULL);
-
 		all_zones_ok = 1;
 		balanced = 0;
 
@@ -2721,14 +2458,15 @@
 			if (!populated_zone(zone))
 				continue;
 
-			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+			if (zone->all_unreclaimable &&
+			    sc.priority != DEF_PRIORITY)
 				continue;
 
 			/*
 			 * Do some background aging of the anon list, to give
 			 * pages a chance to be referenced before reclaiming.
 			 */
-			age_active_anon(zone, &sc, priority);
+			age_active_anon(zone, &sc);
 
 			/*
 			 * If the number of buffer_heads in the machine
@@ -2776,7 +2514,8 @@
 			if (!populated_zone(zone))
 				continue;
 
-			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+			if (zone->all_unreclaimable &&
+			    sc.priority != DEF_PRIORITY)
 				continue;
 
 			sc.nr_scanned = 0;
@@ -2820,7 +2559,7 @@
 				    !zone_watermark_ok_safe(zone, testorder,
 					high_wmark_pages(zone) + balance_gap,
 					end_zone, 0)) {
-				shrink_zone(priority, zone, &sc);
+				shrink_zone(zone, &sc);
 
 				reclaim_state->reclaimed_slab = 0;
 				nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
@@ -2877,7 +2616,7 @@
 		 * OK, kswapd is getting into trouble.  Take a nap, then take
 		 * another pass across the zones.
 		 */
-		if (total_scanned && (priority < DEF_PRIORITY - 2)) {
+		if (total_scanned && (sc.priority < DEF_PRIORITY - 2)) {
 			if (has_under_min_watermark_zone)
 				count_vm_event(KSWAPD_SKIP_CONGESTION_WAIT);
 			else
@@ -2892,7 +2631,7 @@
 		 */
 		if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX)
 			break;
-	}
+	} while (--sc.priority >= 0);
 out:
 
 	/*
@@ -2942,7 +2681,8 @@
 			if (!populated_zone(zone))
 				continue;
 
-			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+			if (zone->all_unreclaimable &&
+			    sc.priority != DEF_PRIORITY)
 				continue;
 
 			/* Would compaction fail due to lack of free memory? */
@@ -3013,7 +2753,18 @@
 		 * them before going back to sleep.
 		 */
 		set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold);
-		schedule();
+
+		/*
+		 * Compaction records what page blocks it recently failed to
+		 * isolate pages from and skips them in the future scanning.
+		 * When kswapd is going to sleep, it is reasonable to assume
+		 * that pages and compaction may succeed so reset the cache.
+		 */
+		reset_isolation_suitable(pgdat);
+
+		if (!kthread_should_stop())
+			schedule();
+
 		set_pgdat_percpu_threshold(pgdat, calculate_pressure_threshold);
 	} else {
 		if (remaining)
@@ -3209,6 +2960,7 @@
 		.nr_to_reclaim = nr_to_reclaim,
 		.hibernation_mode = 1,
 		.order = 0,
+		.priority = DEF_PRIORITY,
 	};
 	struct shrink_control shrink = {
 		.gfp_mask = sc.gfp_mask,
@@ -3386,7 +3138,6 @@
 	const unsigned long nr_pages = 1 << order;
 	struct task_struct *p = current;
 	struct reclaim_state reclaim_state;
-	int priority;
 	struct scan_control sc = {
 		.may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
 		.may_unmap = !!(zone_reclaim_mode & RECLAIM_SWAP),
@@ -3395,6 +3146,7 @@
 				       SWAP_CLUSTER_MAX),
 		.gfp_mask = gfp_mask,
 		.order = order,
+		.priority = ZONE_RECLAIM_PRIORITY,
 	};
 	struct shrink_control shrink = {
 		.gfp_mask = sc.gfp_mask,
@@ -3417,11 +3169,9 @@
 		 * Free memory by calling shrink zone with increasing
 		 * priorities until we have enough memory freed.
 		 */
-		priority = ZONE_RECLAIM_PRIORITY;
 		do {
-			shrink_zone(priority, zone, &sc);
-			priority--;
-		} while (priority >= 0 && sc.nr_reclaimed < nr_pages);
+			shrink_zone(zone, &sc);
+		} while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0);
 	}
 
 	nr_slab_pages0 = zone_page_state(zone, NR_SLAB_RECLAIMABLE);
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 8e18d6b..959a558 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -761,10 +761,14 @@
 
 	"pgrotated",
 
+#ifdef CONFIG_MIGRATION
+	"pgmigrate_success",
+	"pgmigrate_fail",
+#endif
 #ifdef CONFIG_COMPACTION
-	"compact_blocks_moved",
-	"compact_pages_moved",
-	"compact_pagemigrate_failed",
+	"compact_migrate_scanned",
+	"compact_free_scanned",
+	"compact_isolated",
 	"compact_stall",
 	"compact_fail",
 	"compact_success",
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index f3c6ef8..1260e1c 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1382,6 +1382,7 @@
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+		snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
@@ -1394,6 +1395,7 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
+		snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
 		break;
 	}
 	return 0;
@@ -1695,9 +1697,6 @@
 	{"I2S TX1", NULL, "TX_I2S_CLK"},
 	{"I2S TX2", NULL, "TX_I2S_CLK"},
 
-	{"DEC1 MUX", NULL, "TX CLK"},
-	{"DEC2 MUX", NULL, "TX CLK"},
-
 	{"I2S TX1", NULL, "DEC1 MUX"},
 	{"I2S TX2", NULL, "DEC2 MUX"},
 
@@ -2136,8 +2135,6 @@
 
 	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 
-	SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
-			4, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
 
 	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -2336,10 +2333,11 @@
 	/* Reduce LINE DAC bias to 70% */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
 
-	/* Disable TX7 internal biasing path which can cause leakage */
+	/* Disable internal biasing path which can cause leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+	/* Enable pulldown to reduce leakage */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
@@ -2350,6 +2348,9 @@
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
+
+	/* Always set TXD_CLK_EN bit to reduce the leakage */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
 };
 
 static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 8949e03..b31c7c9 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -73,6 +73,9 @@
 #define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
 #define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
 #define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
+
+#define TAPAN_IRQ_MBHC_JACK_SWITCH 21
+
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -303,18 +306,18 @@
 		return 0;
 	}
 
-	WCD9XXX_BCL_LOCK(&priv->resmgr);
+	codec = priv->codec;
+	mutex_lock(&codec->mutex);
 	old = spkr_drv_wrnd;
 	ret = param_set_int(val, kp);
 	if (ret) {
-		WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+		mutex_unlock(&codec->mutex);
 		return ret;
 	}
 
-	codec = priv->codec;
 	dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
 			__func__, old, spkr_drv_wrnd);
-	if (old == 0 && spkr_drv_wrnd == 1) {
+	if ((old == -1 || old == 0) && spkr_drv_wrnd == 1) {
 		WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
 		wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
@@ -329,8 +332,8 @@
 			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
 					    0x00);
 	}
+	mutex_unlock(&codec->mutex);
 
-	WCD9XXX_BCL_UNLOCK(&priv->resmgr);
 	return 0;
 }
 
@@ -1698,7 +1701,6 @@
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 
 	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
-	WCD9XXX_BCL_LOCK(&tapan->resmgr);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		tapan->spkr_pa_widget_on = true;
@@ -1709,7 +1711,6 @@
 		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
 		break;
 	}
-	WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 	return 0;
 }
 
@@ -4450,6 +4451,72 @@
 	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
 }
 
+
+static void tapan_enable_mux_bias_block(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+			    0x80, 0x00);
+}
+
+static void tapan_put_cfilt_fast_mode(struct snd_soc_codec *codec,
+				      struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+			    0x30, 0x30);
+}
+
+static void tapan_codec_specific_cal_setup(struct snd_soc_codec *codec,
+					   struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			    0x0C, 0x04);
+	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
+}
+
+static int tapan_get_jack_detect_irq(struct snd_soc_codec *codec)
+{
+	return TAPAN_IRQ_MBHC_JACK_SWITCH;
+}
+
+static struct wcd9xxx_cfilt_mode tapan_codec_switch_cfilt_mode(
+				 struct wcd9xxx_mbhc *mbhc,
+				 bool fast)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_cfilt_mode cfilt_mode;
+
+	if (fast)
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
+	else
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
+
+	cfilt_mode.cur_mode_val =
+		snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+	return cfilt_mode;
+}
+
+static void tapan_select_cfilt(struct snd_soc_codec *codec,
+			       struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
+}
+
+static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
+{
+	void *cdata = mbhc->codec->control_data;
+	wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+	.enable_mux_bias_block = tapan_enable_mux_bias_block,
+	.cfilt_fast_mode = tapan_put_cfilt_fast_mode,
+	.codec_specific_cal = tapan_codec_specific_cal_setup,
+	.jack_detect_irq = tapan_get_jack_detect_irq,
+	.switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
+	.select_cfilt = tapan_select_cfilt,
+	.free_irq = tapan_free_irq,
+};
+
 int tapan_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
@@ -4468,7 +4535,6 @@
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	tapan = snd_soc_codec_get_drvdata(codec);
 	mutex_lock(&codec->mutex);
-	WCD9XXX_BCL_LOCK(&tapan->resmgr);
 
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
@@ -4477,7 +4543,6 @@
 						codec->reg_size, GFP_KERNEL);
 		if (!codec->reg_cache) {
 			pr_err("%s: Cache update failed!\n", __func__);
-			WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 			mutex_unlock(&codec->mutex);
 			return -ENOMEM;
 		}
@@ -4486,7 +4551,6 @@
 	wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
 	if (spkr_drv_wrnd == 1)
 		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
-	WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 
 	tapan_update_reg_defaults(codec);
 	tapan_update_reg_mclk_rate(wcd9xxx);
@@ -4505,8 +4569,7 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				WCD9XXX_MBHC_VERSION_TAPAN,
-				rco_clk_rate);
+				&mbhc_cb, rco_clk_rate);
 	if (ret)
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 	else
@@ -4578,8 +4641,8 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				WCD9XXX_MBHC_VERSION_TAPAN,
-				rco_clk_rate);
+				&mbhc_cb, rco_clk_rate);
+
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		return ret;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 49894ca..516ac4f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -604,18 +604,17 @@
 		return 0;
 	}
 
-	WCD9XXX_BCL_LOCK(&priv->resmgr);
+	codec = priv->codec;
+	mutex_lock(&codec->mutex);
 	old = spkr_drv_wrnd;
 	ret = param_set_int(val, kp);
 	if (ret) {
-		WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+		mutex_unlock(&codec->mutex);
 		return ret;
 	}
-	WCD9XXX_BCL_UNLOCK(&priv->resmgr);
 
 	pr_debug("%s: spkr_drv_wrnd %d -> %d\n", __func__, old, spkr_drv_wrnd);
-	codec = priv->codec;
-	if (old == 0 && spkr_drv_wrnd == 1) {
+	if ((old == -1 || old == 0) && spkr_drv_wrnd == 1) {
 		WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
 		wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
@@ -630,6 +629,7 @@
 			snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80,
 					    0x00);
 	}
+	mutex_unlock(&codec->mutex);
 
 	return 0;
 }
@@ -2420,7 +2420,6 @@
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: %d %s\n", __func__, event, w->name);
-	WCD9XXX_BCL_LOCK(&taiko->resmgr);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		taiko->spkr_pa_widget_on = true;
@@ -2431,7 +2430,6 @@
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x00);
 		break;
 	}
-	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
 	return 0;
 }
 
@@ -4639,7 +4637,7 @@
 			.rate_max = 192000,
 			.rate_min = 8000,
 			.channels_min = 1,
-			.channels_max = 5,
+			.channels_max = 8,
 		},
 		.ops = &taiko_dai_ops,
 	},
@@ -6189,7 +6187,6 @@
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	taiko = snd_soc_codec_get_drvdata(codec);
 	mutex_lock(&codec->mutex);
-	WCD9XXX_BCL_LOCK(&taiko->resmgr);
 
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
@@ -6201,7 +6198,6 @@
 	wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
 	if (spkr_drv_wrnd == 1)
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
-	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
 
 	taiko_update_reg_defaults(codec);
 	taiko_codec_init_reg(codec);
@@ -6223,8 +6219,7 @@
 
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 					taiko_enable_mbhc_micbias,
-					WCD9XXX_MBHC_VERSION_TAIKO,
-					rco_clk_rate);
+					NULL, rco_clk_rate);
 		if (ret) {
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		} else {
@@ -6404,8 +6399,7 @@
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 				taiko_enable_mbhc_micbias,
-				WCD9XXX_MBHC_VERSION_TAIKO,
-				rco_clk_rate);
+				NULL, rco_clk_rate);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		goto err_init;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 618070b..cd11703 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -94,6 +94,8 @@
 
 #define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
 
+#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
+
 static bool detect_use_vddio_switch = true;
 
 struct wcd9xxx_mbhc_detect {
@@ -150,64 +152,6 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
 }
 
-static int wcd9xxx_enable_mux_bias_block(struct snd_soc_codec *codec,
-					 struct wcd9xxx_mbhc *mbhc)
-{
-	switch (mbhc->mbhc_version) {
-	case WCD9XXX_MBHC_VERSION_TAIKO:
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-		break;
-	case WCD9XXX_MBHC_VERSION_TAPAN:
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x00);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int wcd9xxx_put_cfilt_fast_mode(struct snd_soc_codec *codec,
-				       struct wcd9xxx_mbhc *mbhc)
-{
-	switch (mbhc->mbhc_version) {
-	case WCD9XXX_MBHC_VERSION_TAIKO:
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x70, 0x00);
-		break;
-	case WCD9XXX_MBHC_VERSION_TAPAN:
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x70, 0x70);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int wcd9xxx_codec_specific_cal_setup(struct snd_soc_codec *codec,
-					    struct wcd9xxx_mbhc *mbhc)
-{
-	switch (mbhc->mbhc_version) {
-	case WCD9XXX_MBHC_VERSION_TAIKO:
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				    0x04, 0x04);
-		break;
-	case WCD9XXX_MBHC_VERSION_TAPAN:
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				    0x0C, 0x04);
-		snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
-		/* Make sure the calibration is ON */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_val,
-				    0x02, 0x02);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_pause_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
@@ -229,20 +173,18 @@
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	int mbhc_state = mbhc->mbhc_state;
-	int ret;
 
 	pr_debug("%s: enter\n", __func__);
 	if (!mbhc->polling_active) {
 		pr_debug("Polling is not active, do not start polling\n");
 		return;
 	}
-
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret) {
-		pr_err("%s: Error returned, ret: %d\n", __func__, ret);
-		return;
-	}
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 
 	if (!mbhc->no_mic_headset_override &&
 	    mbhc_state == MBHC_STATE_POTENTIAL) {
@@ -481,14 +423,18 @@
 		      (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
 }
 
-static int wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
+static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
 					    bool fast)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_cfilt_mode cfilt_mode;
 	u8 reg_mode_val, cur_mode_val;
 
-	switch (mbhc->mbhc_version) {
-	case WCD9XXX_MBHC_VERSION_TAIKO:
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->switch_cfilt_mode) {
+		cfilt_mode = mbhc->mbhc_cb->switch_cfilt_mode(mbhc, fast);
+		reg_mode_val = cfilt_mode.reg_mode_val;
+		cur_mode_val = cfilt_mode.cur_mode_val;
+	} else {
 		if (fast)
 			reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
 		else
@@ -496,50 +442,21 @@
 
 		cur_mode_val =
 		    snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
-
-		if (cur_mode_val != reg_mode_val) {
-			if (mbhc->polling_active)
-				wcd9xxx_pause_hs_polling(mbhc);
-			snd_soc_update_bits(codec,
-					    mbhc->mbhc_bias_regs.cfilt_ctl,
-					    0x40, reg_mode_val);
-			if (mbhc->polling_active)
-				wcd9xxx_start_hs_polling(mbhc);
-			pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
-				cur_mode_val, reg_mode_val);
-		} else {
-			pr_debug("%s: CFILT Value is already %x\n",
-				 __func__, cur_mode_val);
-		}
-		break;
-	case WCD9XXX_MBHC_VERSION_TAPAN:
-		if (fast)
-			reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
-		else
-			reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
-
-		cur_mode_val =
-		    snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x70;
-
-		if (cur_mode_val != reg_mode_val) {
-			if (mbhc->polling_active)
-				wcd9xxx_pause_hs_polling(mbhc);
-			snd_soc_update_bits(codec,
-					    mbhc->mbhc_bias_regs.cfilt_ctl,
-					    0x70, reg_mode_val);
-			if (mbhc->polling_active)
-				wcd9xxx_start_hs_polling(mbhc);
-			pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
-				cur_mode_val, reg_mode_val);
-		} else {
-			pr_debug("%s: CFILT Value is already %x\n",
-				__func__, cur_mode_val);
-		}
-		break;
-	default:
-		return -EINVAL;
 	}
-	return 0;
+	if (cur_mode_val != reg_mode_val) {
+		if (mbhc->polling_active)
+			wcd9xxx_pause_hs_polling(mbhc);
+		snd_soc_update_bits(codec,
+				    mbhc->mbhc_bias_regs.cfilt_ctl,
+				    0x40, reg_mode_val);
+		if (mbhc->polling_active)
+			wcd9xxx_start_hs_polling(mbhc);
+		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
+			cur_mode_val, reg_mode_val);
+	} else {
+		pr_debug("%s: CFILT Value is already %x\n",
+			 __func__, cur_mode_val);
+	}
 }
 
 static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
@@ -1043,7 +960,6 @@
 	struct snd_soc_codec *codec = mbhc->codec;
 	short bias_value;
 	u8 cfilt_mode;
-	int ret;
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
@@ -1066,14 +982,19 @@
 
 	/* Make sure CFILT is in fast mode, save current mode */
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
-	ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
+		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
+	else
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+				    0x70, 0x00);
+
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 
 	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x80);
 	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x1F, 0x1C);
@@ -1094,10 +1015,6 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 
 	return bias_value;
-
-gen_err:
-	pr_err("%s: Error returned, ret: %d\n", __func__, ret);
-	return ret;
 }
 
 static void wcd9xxx_shutdown_hs_removal_detect(struct wcd9xxx_mbhc *mbhc)
@@ -2927,7 +2844,6 @@
 {
 	u8 cfilt_mode;
 	u16 reg0, reg1;
-	int ret;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2944,21 +2860,30 @@
 	 * Need to restore defaults once calculation is done.
 	 */
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
-	ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
+		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
+	else
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+				    0x40, 0x00);
+
 	/*
 	 * Micbias, CFILT, LDOH, MBHC MUX mode settings
 	 * to perform ADC calibration
 	 */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->select_cfilt)
+		mbhc->mbhc_cb->select_cfilt(codec, mbhc);
+	else
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60,
 			    mbhc->mbhc_cfg->micbias << 5);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 	snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1, 0x60, 0x60);
 	snd_soc_write(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x78);
-	ret = wcd9xxx_codec_specific_cal_setup(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_specific_cal)
+		mbhc->mbhc_cb->codec_specific_cal(codec, mbhc);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				    0x04, 0x04);
+
 	/* Pull down micbias to ground */
 	reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 1, 1);
@@ -2967,9 +2892,11 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
 	/* Connect the MUX to micbias */
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 	/*
 	 * Hardware that has external cap can delay mic bias ramping down up
 	 * to 50ms.
@@ -2991,9 +2918,11 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 	/*
 	 * Hardware that has external cap can delay mic bias ramping down up
 	 * to 50ms.
@@ -3008,9 +2937,11 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 	/*
 	 * Hardware that has external cap can delay mic bias ramping down up
 	 * to 50ms.
@@ -3024,19 +2955,17 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
-	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
-	if (ret)
-		goto gen_err;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+		mbhc->mbhc_cb->enable_mux_bias_block(codec);
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x80, 0x80);
 	usleep_range(100, 100);
 
 	wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
-	return;
-
-gen_err:
-	pr_err("%s: Error returned, ret: %d\n", __func__, ret);
 }
 
 static void wcd9xxx_mbhc_setup(struct wcd9xxx_mbhc *mbhc)
@@ -3095,8 +3024,14 @@
 {
 	int ret = 0;
 	void *core = mbhc->resmgr->core;
+	struct snd_soc_codec *codec = mbhc->codec;
 	int jack_irq;
 
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->jack_detect_irq)
+		jack_irq = mbhc->mbhc_cb->jack_detect_irq(codec);
+	else
+		jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT;
+
 	if (mbhc->mbhc_cfg->gpio) {
 		ret = request_threaded_irq(mbhc->mbhc_cfg->gpio_irq, NULL,
 					   wcd9xxx_mech_plug_detect_irq,
@@ -3118,17 +3053,6 @@
 		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 				    1 << 1, 1 << 1);
 
-		switch (mbhc->mbhc_version) {
-		case WCD9XXX_MBHC_VERSION_TAIKO:
-			jack_irq = WCD9320_IRQ_MBHC_JACK_SWITCH;
-			break;
-		case WCD9XXX_MBHC_VERSION_TAPAN:
-			jack_irq = WCD9306_IRQ_MBHC_JACK_SWITCH;
-			break;
-		default:
-			return -EINVAL;
-		}
-
 		ret = wcd9xxx_request_irq(core, jack_irq,
 					  wcd9xxx_mech_plug_detect_irq,
 					  "Jack Detect",
@@ -3357,7 +3281,7 @@
 int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
 		       struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
-	int rc;
+	int rc = 0;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
@@ -3381,10 +3305,13 @@
 	wcd9xxx_get_mbhc_micbias_regs(mbhc, &mbhc->mbhc_bias_regs);
 
 	/* Put CFILT in fast mode by default */
-	rc = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
-	if (rc)
-		pr_err("%s: Error returned, ret: %d\n", __func__, rc);
-	else if (!mbhc->mbhc_cfg->read_fw_bin)
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
+		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
+	else
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+		0x40, WCD9XXX_CFILT_FAST_MODE);
+
+	if (!mbhc->mbhc_cfg->read_fw_bin)
 		rc = wcd9xxx_init_and_calibrate(mbhc);
 	else
 		schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
@@ -3612,7 +3539,7 @@
 			 * Switch CFILT to slow mode if MBHC CFILT is being
 			 * used.
 			 */
-			ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, false);
+			wcd9xxx_codec_switch_cfilt_mode(mbhc, false);
 		break;
 	case WCD9XXX_EVENT_POST_CFILT_1_OFF:
 	case WCD9XXX_EVENT_POST_CFILT_2_OFF:
@@ -3623,7 +3550,7 @@
 			 * Switch CFILT to fast mode if MBHC CFILT is not
 			 * used anymore.
 			 */
-			ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, true);
+			wcd9xxx_codec_switch_cfilt_mode(mbhc, true);
 		break;
 	/* System resume */
 	case WCD9XXX_EVENT_POST_RESUME:
@@ -3656,8 +3583,7 @@
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
-		      int version,
-		      int rco_clk_rate)
+		      const struct wcd9xxx_mbhc_cb *mbhc_cb, int rco_clk_rate)
 {
 	int ret;
 	void *core;
@@ -3681,8 +3607,8 @@
 	mbhc->resmgr = resmgr;
 	mbhc->resmgr->mbhc = mbhc;
 	mbhc->micbias_enable_cb = micbias_enable_cb;
-	mbhc->mbhc_version = version;
 	mbhc->rco_clk_rate = rco_clk_rate;
+	mbhc->mbhc_cb = mbhc_cb;
 
 	if (mbhc->headset_jack.jack == NULL) {
 		ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
@@ -3805,17 +3731,11 @@
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 
-	switch (mbhc->mbhc_version) {
-	case WCD9XXX_MBHC_VERSION_TAIKO:
-		wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH, mbhc);
-		break;
-	case WCD9XXX_MBHC_VERSION_TAPAN:
-		wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
-		break;
-	default:
-		pr_err("%s: irq free failed! Invalid MBHC version %d\n",
-			__func__, mbhc->mbhc_version);
-	}
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->free_irq)
+		mbhc->mbhc_cb->free_irq(mbhc);
+	else
+		wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH,
+				 mbhc);
 
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 71a62b2..02ecced 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -16,8 +16,8 @@
 
 #define WCD9XXX_CFILT_FAST_MODE 0x00
 #define WCD9XXX_CFILT_SLOW_MODE 0x40
-#define WCD9XXX_CFILT_EXT_PRCHG_EN 0x70
-#define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x40
+#define WCD9XXX_CFILT_EXT_PRCHG_EN 0x30
+#define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x00
 
 struct mbhc_micbias_regs {
 	u16 cfilt_val;
@@ -61,12 +61,6 @@
 	s16 v_inval_ins_high;
 };
 
-enum wcd9xxx_mbhc_version {
-	WCD9XXX_MBHC_VERSION_UNKNOWN = 0,
-	WCD9XXX_MBHC_VERSION_TAIKO,
-	WCD9XXX_MBHC_VERSION_TAPAN,
-};
-
 enum wcd9xxx_mbhc_plug_type {
 	PLUG_TYPE_INVALID = -1,
 	PLUG_TYPE_NONE,
@@ -218,6 +212,23 @@
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 };
 
+struct wcd9xxx_cfilt_mode {
+	u8 reg_mode_val;
+	u8 cur_mode_val;
+};
+
+struct wcd9xxx_mbhc_cb {
+	void (*enable_mux_bias_block) (struct snd_soc_codec *);
+	void (*cfilt_fast_mode) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
+	void (*codec_specific_cal) (struct snd_soc_codec *,
+				    struct wcd9xxx_mbhc *);
+	int (*jack_detect_irq) (struct snd_soc_codec *);
+	struct wcd9xxx_cfilt_mode (*switch_cfilt_mode) (struct wcd9xxx_mbhc *,
+							bool);
+	void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
+	void (*free_irq) (struct wcd9xxx_mbhc *);
+};
+
 struct wcd9xxx_mbhc {
 	bool polling_active;
 	/* Delayed work to report long button press */
@@ -225,6 +236,7 @@
 	int buttons_pressed;
 	enum wcd9xxx_mbhc_state mbhc_state;
 	struct wcd9xxx_mbhc_config *mbhc_cfg;
+	const struct wcd9xxx_mbhc_cb *mbhc_cb;
 
 	struct mbhc_internal_cal_data mbhc_data;
 
@@ -279,8 +291,6 @@
 	bool micbias_enable;
 	int (*micbias_enable_cb) (struct snd_soc_codec*,  bool);
 
-	enum wcd9xxx_mbhc_version mbhc_version;
-
 	u32 rco_clk_rate;
 
 #ifdef CONFIG_DEBUG_FS
@@ -349,7 +359,7 @@
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
-		      int version,
+		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
 		      int rco_clk_rate);
 void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
 void *wcd9xxx_mbhc_cal_btn_det_mp(
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 84f236e..be11e53 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -209,8 +209,8 @@
 	int old_clk_rco_users, old_clk_mclk_users;
 
 	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
 
+	WCD9XXX_BG_CLK_LOCK(resmgr);
 	old_bg_audio_users = resmgr->bg_audio_users;
 	old_bg_mbhc_users = resmgr->bg_mbhc_users;
 	old_clk_rco_users = resmgr->clk_rco_users;
@@ -243,6 +243,7 @@
 		while (old_clk_rco_users--)
 			wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_RCO);
 	}
+	WCD9XXX_BG_CLK_UNLOCK(resmgr);
 	pr_debug("%s: leave\n", __func__);
 }
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index d973c17..171db0a 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1805,7 +1805,7 @@
 		SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 5,
+		.channels_max = 8,
 		.rate_min =     8000,
 		.rate_max =	192000,
 	},
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index a39a18b..0a86221 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -711,7 +711,8 @@
 static const char *const spk_function[] = {"Off", "On"};
 static const char *const slim0_rx_ch_text[] = {"One", "Two"};
 static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
-						"Five"};
+						"Five", "Six", "Seven",
+						"Eight"};
 static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
 					"Six", "Seven", "Eight"};
 static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
@@ -1319,7 +1320,7 @@
 static const struct soc_enum msm_snd_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text),
 	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
 	SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index a076246..4d9632c 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -34,11 +34,19 @@
 #define BTSCO_RATE_8KHZ 8000
 #define BTSCO_RATE_16KHZ 16000
 
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
 
 static int msm_proxy_rx_ch = 2;
 static struct snd_soc_jack hs_jack;
+static struct platform_device *spdev;
+static int ext_spk_amp_gpio = -1;
 
 
 /*
@@ -86,15 +94,69 @@
 
 static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event);
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event);
+static void msm8x10_enable_ext_spk_power_amp(u32 on);
 
 static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
 
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
 	msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SPK("Lineout amp", msm_ext_spkramp_event),
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 
 };
+static int msm8x10_ext_spk_power_amp_init(void)
+{
+	int ret = 0;
+
+	ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+		"qcom,ext-spk-amp-gpio", 0);
+	if (ext_spk_amp_gpio >= 0) {
+		ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+		if (ret) {
+			pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+				__func__);
+			return -EINVAL;
+		}
+		gpio_direction_output(ext_spk_amp_gpio, 0);
+	}
+	return 0;
+}
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s()\n", __func__);
+
+	if (ext_spk_amp_gpio >= 0) {
+		if (SND_SOC_DAPM_EVENT_ON(event))
+			msm8x10_enable_ext_spk_power_amp(1);
+		else
+			msm8x10_enable_ext_spk_power_amp(0);
+	}
+	return 0;
+
+}
+
+static void msm8x10_enable_ext_spk_power_amp(u32 on)
+{
+	if (on) {
+		gpio_direction_output(ext_spk_amp_gpio, on);
+		/*time takes enable the external power amplifier*/
+		usleep_range(EXT_CLASS_D_EN_DELAY,
+			     EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+	} else {
+		gpio_direction_output(ext_spk_amp_gpio, on);
+		/*time takes disable the external power amplifier*/
+		usleep_range(EXT_CLASS_D_DIS_DELAY,
+			     EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+	}
+
+	pr_debug("%s: %s external speaker PAs.\n", __func__,
+			on ? "Enable" : "Disable");
+}
 
 static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
 {
@@ -265,10 +327,11 @@
 	int ret = 0;
 
 	pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
-
+	msm8x10_ext_spk_power_amp_init();
 	snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
 				ARRAY_SIZE(msm8x10_dapm_widgets));
 
+	snd_soc_dapm_enable_pin(dapm, "Lineout amp");
 	snd_soc_dapm_sync(dapm);
 
 	ret = snd_soc_jack_new(codec, "Headset Jack",
@@ -686,11 +749,16 @@
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret)
+		goto err;
+
 	ret = snd_soc_of_parse_audio_routing(card,
 			"qcom,audio-routing");
 	if (ret)
 		goto err;
 
+	spdev = pdev;
 	ret = snd_soc_register_card(card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
@@ -708,6 +776,8 @@
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		gpio_free(ext_spk_amp_gpio);
 	snd_soc_unregister_card(card);
 	mutex_destroy(&cdc_mclk_mutex);
 	return 0;