Merge "msm8937: Enable config flag for File based Encryption"
diff --git a/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt
new file mode 100644
index 0000000..ba61a2f
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt
@@ -0,0 +1,99 @@
+Goodix GT9xx series touch controller
+
+Required properties:
+
+ - compatible		: Should be "goodix,gt9xx"
+ - reg			: I2C slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: Configuration of touch panel controller interrupt
+				GPIO.
+ - goodix,product-id	: Product identification of the controller.
+ - interrupt-gpios	: Interrupt gpio which is to provide interrupts to
+				host, same as "interrupts" node.
+ - reset-gpios		: Reset gpio to control the reset of chip.
+ - goodix,display-coords	: Display coordinates in pixels. It is a four
+				tuple consisting of min x, min y, max x and
+				max y values.
+
+Optional properties:
+
+ - avdd-supply		: Power supply needed to power up the device, this is
+				for fixed voltage external regulator.
+ - vdd-supply		: Power supply needed to power up the device, when use
+				external regulator, do not add this property.
+ - vcc-i2c-supply	: Power source required to power up i2c bus.
+				GT9xx series can provide 1.8V from internal
+				LDO, add this properties base on hardware
+				design.
+ - goodix,panel-coords	: Panel coordinates for the chip in pixels.
+				It is a four tuple consisting of min x,
+				min y, max x and max y values.
+ - goodix,i2c-pull-up	: To specify pull up is required.
+ - goodix,force-update	: To specify force update is allowed.
+ - goodix,enable-power-off	: Power off touchscreen during suspend.
+ - goodix,button-map	: Button map of key codes. The number of key codes
+				depend on panel.
+ - goodix,cfg-data0	: Touch screen controller config data group 0. Ask vendor
+				to provide that.
+				Driver supports maximum six config groups. If more than one
+				groups are defined, driver will select config group depending
+				on hardware configuration. If only config group 0 is defined,
+				it will be used for all hardware configurations.
+				Touch screen controller will use its onchip default config data
+				if this property is not present.
+ - goodix,cfg-data1	: Touch screen controller config data group 1. Ask vendor
+				to provide that.
+ - goodix,cfg-data2	: Touch screen controller config data group 2. Ask vendor
+				to provide that.
+ - goodix,cfg-data3	: Touch screen controller config data group 3. Ask vendor
+				to provide that.
+ - goodix,cfg-data4	: Touch screen controller config data group 4. Ask vendor
+				to provide that.
+ - goodix,cfg-data5	: Touch screen controller config data group 5. Ask vendor
+				to provide that.
+ - goodix,fw-name	: Touch screen controller firmware file name.
+ - goodix,slide-wakeup	: To specify slide-wakeup property is enabled or not.
+ - goodix,dbl-clk-wakeup	: To specify dbl-clk-wakeup property is enabled or not.
+ - goodix,change-x2y	: To specify change-x2y property is enabled or not.
+ - goodix,driver-send-cfg	: To specify driver-send-cfg property is enabled or not.
+ - goodix,have-touch-key	: To specify have-touch-key property is enabled or not.
+ - goodix,with-pen	: To specify with-pen property is enabled or not.
+Example:
+i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,product-id = "915";
+			goodix,cfg-data0 = [
+				41 D0 02 00 05 0A 05 01 01 08
+				12 58 50 41 03 05 00 00 00 00
+				00 00 00 00 00 00 00 8C 2E 0E
+				28 24 73 13 00 00 00 83 03 1D
+				40 02 00 00 00 03 64 32 00 00
+				00 1A 38 94 C0 02 00 00 00 04
+				9E 1C 00 8D 20 00 7A 26 00 6D
+				2C 00 60 34 00 60 10 38 68 00
+				F0 50 35 FF FF 27 00 00 00 00
+				00 01 1B 14 0C 14 00 00 01 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 02 04 06 08 0A 0C 0E 10
+				12 14 16 18 1A 1C FF FF FF FF
+				FF FF FF FF FF FF FF FF FF FF
+				FF FF 00 02 04 06 08 0A 0C 0F
+				10 12 13 14 16 18 1C 1D 1E 1F
+				20 21 22 24 26 28 29 2A FF FF
+				FF FF FF FF FF FF FF 22 22 22
+				22 22 22 FF 07 01];
+			goodix,fw_name = "gtp_fw.bin";
+			goodix,have-touch-key;
+			goodix,driver-send-cfg;
+		};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
index 04f11ce..fa858c3 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
@@ -20,3 +20,7 @@
 		"qcom,sdxpoorwills", "qcom,cdp";
 	qcom,board-id = <1 0x0>;
 };
+
+&blsp1_uart2b_hs {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
index 0f9c8bc..fc56a50 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
@@ -11,6 +11,7 @@
  */
 
 #include "sdxpoorwills-cdp.dtsi"
+#include "sdxpoorwills-memory-256.dtsi"
 
 &soc {
 	vreg_sd_mmc: vreg_sd_mmc {
@@ -21,3 +22,11 @@
 &sdhc_1 {
 	cd-gpios = <&tlmm 21 0x1>;
 };
+
+&soc {
+	bluetooth: bt_qca6174 {
+		compatible = "qca,qca6174";
+		qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */
+		qca,bt-vdd-pa-supply = <&vreg_wlan>;
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi
new file mode 100644
index 0000000..0c21814
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi
@@ -0,0 +1,19 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&peripheral2_mem {
+	reg = <0x8fe00000 0x200000>;
+};
+
+&mss_mem {
+	reg = <0x87000000 0x8300000>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
index 2377d79c..a774c8b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
@@ -20,3 +20,7 @@
 		"qcom,sdxpoorwills", "qcom,mtp";
 	qcom,board-id = <8 0x0>;
 };
+
+&blsp1_uart2b_hs {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
index 7412031..297af52 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
@@ -11,6 +11,7 @@
  */
 
 #include "sdxpoorwills-mtp.dtsi"
+#include "sdxpoorwills-memory-256.dtsi"
 
 &soc {
 	vreg_sd_mmc: vreg_sd_mmc {
@@ -21,3 +22,11 @@
 &sdhc_1 {
 	cd-gpios = <&tlmm 21 0x1>;
 };
+
+&soc {
+	bluetooth: bt_qca6174 {
+		compatible = "qca,qca6174";
+		qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */
+		qca,bt-vdd-pa-supply = <&vreg_wlan>;
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 2014885..ef001fb 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -36,7 +36,7 @@
 		peripheral2_mem: peripheral2_region@8fe00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x8fe00000 0x200000>;
+			reg = <0x8fe00000 0xe00000>;
 			label = "peripheral2_mem";
 		};
 
@@ -65,7 +65,7 @@
 		mss_mem: mss_region@87400000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0x87400000 0x8300000>;
+			reg = <0x87000000 0x8700000>;
 			label = "mss_mem";
 		};
 
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi
new file mode 100644
index 0000000..e065f00
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi
@@ -0,0 +1,157 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&mdss_mdp {
+	dsi_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video {
+		qcom,mdss-dsi-panel-name =
+			"hx83112a video mode dsi truly panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+
+		qcom,mdss-dsi-display-timings {
+			timing@0 {
+				qcom,mdss-dsi-panel-width = <1080>;
+				qcom,mdss-dsi-panel-height = <2160>;
+				qcom,mdss-dsi-h-front-porch = <42>;
+				qcom,mdss-dsi-h-back-porch = <42>;
+				qcom,mdss-dsi-h-pulse-width = <10>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <15>;
+				qcom,mdss-dsi-v-front-porch = <10>;
+				qcom,mdss-dsi-v-pulse-width = <3>;
+				qcom,mdss-dsi-panel-framerate = <60>;
+				qcom,mdss-dsi-on-command = [
+				  39 01 00 00 00 00 04 B9 83 11 2A
+				  39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54
+				     33
+				  39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08
+				     26 FC 01 00 03 15 A3 87 09
+				  39 01 00 00 00 00 02 BD 02
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 03 D2 2C 2C
+				  39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A
+				     CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00
+				     28 0A 13 14 00 8A
+				  39 01 00 00 00 00 02 BD 02
+				  39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12
+				     00 53
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 04 B6 82 82 E3
+				  39 01 00 00 00 00 02 CC 08
+				  39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01
+				     0A 0A 07 07 00 08 09 09 09 09 32 10 09 00
+				     09 32 21 0A 00 0A 32 10 08 00 00 00 00 00
+				     00 00 00 00 0B 08 82
+				  39 01 00 00 00 00 02 BD 01
+				  39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00
+				     81
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18
+				     18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0
+				     18 40 40 01 00 07 06 05 04 03 02 21 20 18
+				     18 19 19 18 18 03 03 18 18 18 18 18 18
+				  39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18
+				     18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0
+				     18 40 40 02 03 04 05 06 07 00 01 20 21 18
+				     18 18 18 19 19 20 20 18 18 18 18 18 18
+				  39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00
+				     00 00 00 00 00 00 00 00 00 00 00 00 00 00
+				     00 00 00
+				  39 01 00 00 00 00 02 BD 01
+				  39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA
+				     AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+				     AA AA AA
+				  39 01 00 00 00 00 02 BD 02
+				  39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA
+				     FF FA AA BA AA
+				  39 01 00 00 00 00 02 BD 03
+				  39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA
+				     AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+				     AA AA AA
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00
+				     32 02 02 00 00 02 02 02 05 14 14 32 B9 23
+				     B9 08
+				  39 01 00 00 00 00 02 BD 01
+				  39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8
+				     0E 01
+				  39 01 00 00 00 00 02 BD 02
+				  39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00
+				     00 00 00 00 00 00 00 00 00 00 00 00 00 00
+				     00 04 00 00 00 00 02 00
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 02 C1 01
+				  39 01 00 00 00 00 02 BD 01
+				  39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+				     C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+				     6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+				     1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+				     C6 B8 9C 37 43 3D E5 00
+				  39 01 00 00 00 00 02 BD 02
+				  39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+				     C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+				     6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+				     1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+				     C6 B8 9C 37 43 3D E5 00
+				  39 01 00 00 00 00 02 BD 03
+				  39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+				     C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+				     6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+				     1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+				     C6 B8 9C 37 43 3D E5 00
+				  39 01 00 00 00 00 02 BD 00
+				  39 01 00 00 00 00 02 E9 C3
+				  39 01 00 00 00 00 03 CB 92 01
+				  39 01 00 00 00 00 02 E9 3F
+				  39 01 00 00 00 00 07 C7 70 00 04 E0 33 00
+				  39 01 00 00 00 00 03 51 0F FF
+				  39 01 00 00 00 00 02 53 24
+				  39 01 00 00 00 00 02 55 00
+				  15 01 00 00 00 00 02 35 00
+				  05 01 00 00 96 00 02 11 00
+				  05 01 00 00 32 00 02 29 00];
+				qcom,mdss-dsi-off-command = [
+				  05 01 00 00 32 00 02 28 00
+				  05 01 00 00 96 00 02 10 00];
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..23c0987
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	actuator1: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vdig-supply = <&pm8937_l23>;
+		cam_vana-supply = <&pm8937_l22>;
+		cam_vio-supply = <&pm8937_l6>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 36 0>,
+			<&tlmm 35 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_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom1: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		qcom,eeprom-name = "sunny_8865";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <8>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0x0 1 0>;
+		qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page1 = <1 0x5002 2 0x00 1 0>;
+		qcom,poll1 = <0 0x0 2 0x0 1 0>;
+		qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+		qcom,poll2 = <0 0x0 2 0x0 1 0>;
+		qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+		qcom,poll3 = <0 0x0 2 0x0 1 0>;
+		qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+		qcom,poll4 = <0 0x0 2 0x0 1 0>;
+		qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+		qcom,poll5 = <0 0x0 2 0x0 1 0>;
+		qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+		qcom,poll6 = <0 0x0 2 0x0 1 0>;
+		qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0x0 1 1>;
+		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8937_l23>;
+		cam_vana-supply = <&pm8937_l22>;
+		cam_vio-supply = <&pm8937_l6>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+			&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 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_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+			"sensor_vreg",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+			"sensor_gpio_reset", "sensor_gpio_standby",
+			"sensor_cam_mclk";
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vana-supply = <&pm8937_l22>;
+		cam_vio-supply = <&pm8937_l6>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vdig>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vdig_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 36 0>,
+			<&tlmm 35 0>,
+			<&tlmm 62 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VDIG";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8937_l23>;
+		cam_vana-supply = <&pm8937_l22>;
+		cam_vio-supply = <&pm8937_l6>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 38 0>,
+			<&tlmm 50 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_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <0x100>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <1>;
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8937_l23>;
+		cam_vana-supply = <&pm8937_l22>;
+		cam_vio-supply = <&pm8937_l6>;
+		cam_vaf-supply = <&pm8937_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 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_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
index d2e100e9..7f35e1e 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -11,6 +11,7 @@
  * GNU General Public License for more details.
  */
 
+#include "msm8917-camera-sensor-mtp.dtsi"
 
 &blsp1_uart2 {
 	status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
index 91a290f..55e8e21 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
@@ -22,3 +22,14 @@
 &usb_otg {
 	extcon = <&qpnp_smbcharger>;
 };
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8937_flash0 &pmi8937_flash1>;
+		qcom,torch-source = <&pmi8937_torch0 &pmi8937_torch1>;
+		qcom,switch-source = <&pmi8937_switch>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
index 90226da..9b9cd47 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
@@ -22,3 +22,14 @@
 &usb_otg {
 	extcon = <&qpnp_smbcharger>;
 };
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8940_flash0 &pmi8940_flash1>;
+		qcom,torch-source = <&pmi8940_torch0 &pmi8940_torch1>;
+		qcom,switch-source = <&pmi8940_switch>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index 3552055..65b2397 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -1400,6 +1400,66 @@
 			};
 		};
 
+		spi6 {
+			spi6_default: spi6_default {
+				/* active state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio20", "gpio21", "gpio23";
+					function = "blsp_spi6";
+				};
+
+				config {
+					pins = "gpio20", "gpio21", "gpio23";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable = <0>; /* No PULL */
+				};
+			};
+
+			spi6_sleep: spi6_sleep {
+				/* suspended state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio20", "gpio21", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio20", "gpio21", "gpio23";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+
+			spi6_cs0_active: cs0_active {
+				/* CS */
+				mux {
+					pins = "gpio22";
+					function = "blsp_spi6";
+				};
+
+				config {
+					pins = "gpio22";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi6_cs0_sleep: cs0_sleep {
+				/* CS */
+				mux {
+					pins = "gpio22";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+		};
+
 		/* add pingrp for touchscreen */
 		pmx_ts_int_active {
 			ts_int_active: ts_int_active {
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index d12e04a..3ab3b2b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -179,6 +179,7 @@
 		i2c3 = &i2c_3;
 		i2c5 = &i2c_5;
 		spi3 = &spi_3;
+		spi6 = &spi_6;
 	};
 
 	soc: soc {
@@ -700,6 +701,33 @@
 		qcom,master-id = <86>;
 		status = "disabled";
 	};
+
+	spi_6: spi@7af6000 { /* BLSP2 QUP2 */
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0x7af6000 0x600>,
+			<0x7ac4000 0x1f000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 300 0>, <0 239 0>;
+		spi-max-frequency = <19200000>;
+		pinctrl-names = "spi_default", "spi_sleep";
+		pinctrl-0 = <&spi6_default &spi6_cs0_active>;
+		pinctrl-1 = <&spi6_sleep &spi6_cs0_sleep>;
+		clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp2_qup2_spi_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,use-pinctrl;
+		qcom,ver-reg-exists;
+		qcom,bam-consumer-pipe-index = <6>;
+		qcom,bam-producer-pipe-index = <7>;
+		qcom,master-id = <84>;
+		status = "disabled";
+	};
+
 	i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
 		compatible = "qcom,i2c-msm-v2";
 		#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
index 44fae6a..76088af 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,3 +32,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
index abc3f2d..47ea8f3 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -26,3 +26,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
index 414e8fe..42c3e83 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -477,17 +477,22 @@
 
 		qcom,cpr-quotient-adjustment =
 			<66      77      66>, /* SVSP/NOM/TUR:30/35/30 mV */
-			<(-74) (-57)  (-30)>, /* SVSP/NOM/TUR:-34/-26/-14 mV */
+			<(-74)    0   (-30)>, /* SVSP/NOM/TUR:-34/0/-14 mV */
 			<0        0       0>;
 
 		qcom,cpr-floor-to-ceiling-max-range =
-			<50000 50000 50000 65000 65000>,
-			<50000 50000 50000 65000 65000>,
-			<50000 50000 50000 65000 65000>;
+			<50000 50000 65000 65000 65000>,
+			<50000 50000 65000 65000 65000>,
+			<50000 50000 65000 65000 65000>;
 
 		qcom,cpr-voltage-ceiling-override =
 			<(-1) (-1) 810000 845000 885000 960000 960000>;
 
+		qcom,cpr-virtual-corner-quotient-adjustment =
+			<0  0    0   0   0>,
+			<0  0  (-22) 0   0>, /* NOMP: -10 mV */
+			<0  0    0   0   0>;
+
 		qcom,cpr-enable;
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 348ba6f..237152d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -338,17 +338,17 @@
 				iova-mem-region-io {
 					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd911000>;
-					iova-region-len = <0xd26ef000>;
+					iova-region-start = <0xda00000>;
+					iova-region-len = <0xd2500000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
 
 				iova-mem-qdss-region {
-					/* qdss region is approximately 64K */
+					/* qdss region is approximately 1MB */
 					iova-region-name = "qdss";
 					iova-region-start = <0xd900000>;
-					iova-region-len = <0x10000>;
+					iova-region-len = <0x100000>;
 					iova-region-id = <0x5>;
 					qdss-phy-addr = <0x16790000>;
 					status = "ok";
@@ -911,6 +911,9 @@
 	cam_ipe0: qcom,ipe0 {
 		cell-index = <0>;
 		compatible = "qcom,cam-ipe";
+		reg = <0xac87000 0x3000>;
+		reg-names = "ipe0_top";
+		reg-cam-base = <0x87000>;
 		regulator-names = "ipe0-vdd";
 		ipe0-vdd-supply = <&ipe_0_gdsc>;
 		clock-names = "ipe_0_ahb_clk",
@@ -938,6 +941,9 @@
 	cam_ipe1: qcom,ipe1 {
 		cell-index = <1>;
 		compatible = "qcom,cam-ipe";
+		reg = <0xac91000 0x3000>;
+		reg-names = "ipe1_top";
+		reg-cam-base = <0x91000>;
 		regulator-names = "ipe1-vdd";
 		ipe1-vdd-supply = <&ipe_1_gdsc>;
 		clock-names = "ipe_1_ahb_clk",
@@ -965,6 +971,9 @@
 	cam_bps: qcom,bps {
 		cell-index = <0>;
 		compatible = "qcom,cam-bps";
+		reg = <0xac6f000 0x3000>;
+		reg-names = "bps_top";
+		reg-cam-base = <0x6f000>;
 		regulator-names = "bps-vdd";
 		bps-vdd-supply = <&bps_gdsc>;
 		clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index a743373..5d62c5a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -27,6 +27,7 @@
 #include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi"
 #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
 #include "dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi"
+#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
 &soc {
@@ -489,7 +490,30 @@
 		ibb-supply = <&lcdb_ncp_vreg>;
 	};
 
-	ext_dsi_bridge_display: qcom,dsi-display@17 {
+	dsi_hx83112a_truly_video_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_hx83112a_truly_video_display";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0>;
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		pinctrl-names = "panel_active", "panel_suspend";
+		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+		qcom,platform-te-gpio = <&tlmm 10 0>;
+		qcom,platform-reset-gpio = <&tlmm 75 0>;
+
+		qcom,dsi-panel = <&dsi_hx83112a_truly_video>;
+		vddio-supply = <&pm660_l11>;
+		lab-supply = <&lcdb_ldo_vreg>;
+		ibb-supply = <&lcdb_ncp_vreg>;
+	};
+
+	ext_dsi_bridge_display: qcom,dsi-display@18 {
 		compatible = "qcom,dsi-display";
 		label = "ext_dsi_bridge_display";
 		qcom,display-type = "primary";
@@ -561,7 +585,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -583,7 +607,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -607,7 +631,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
-				05 03 03 04 00];
+				05 03 02 04 00];
 			qcom,display-topology = <1 1 1>,
 						<2 2 1>, /* dsc merge */
 						<2 1 1>; /* 3d mux */
@@ -634,7 +658,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
-				04 03 03 04 00];
+				04 03 02 04 00];
 			qcom,display-topology = <1 1 1>,
 						<2 2 1>, /* dsc merge */
 						<2 1 1>; /* 3d mux */
@@ -649,7 +673,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <1 0 1>,
 						<2 0 1>;
 			qcom,default-topology-index = <0>;
@@ -663,7 +687,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -682,7 +706,7 @@
 			qcom,panel-roi-alignment = <720 40 720 40 720 40>;
 			qcom,partial-update-enabled = "single_roi";
 			qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
-				07 04 03 04 00];
+				07 04 02 04 00];
 		};
 		timing@1{
 			qcom,display-topology = <1 0 1>,
@@ -691,7 +715,7 @@
 			qcom,panel-roi-alignment = <540 40 540 40 540 40>;
 			qcom,partial-update-enabled = "single_roi";
 			qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
-				07 04 03 04 00];
+				07 04 02 04 00];
 		};
 		timing@2{
 			qcom,display-topology = <1 0 1>,
@@ -700,7 +724,7 @@
 			qcom,panel-roi-alignment = <360 40 360 40 360 40>;
 			qcom,partial-update-enabled = "single_roi";
 			qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
-				07 04 03 04 00];
+				07 04 02 04 00];
 		};
 	};
 };
@@ -711,20 +735,20 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
-				09 06 03 04 00];
+				09 06 02 04 00];
 			qcom,display-topology = <2 0 2>;
 			qcom,default-topology-index = <0>;
 		};
 		timing@1{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
 		};
 		timing@2{
 			qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
-				06 04 03 04 00];
+				06 04 02 04 00];
 			qcom,display-topology = <2 0 2>;
 			qcom,default-topology-index = <0>;
 		};
@@ -737,13 +761,13 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 { /* 1080p */
 			qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
-				07 04 03 04 00];
+				07 04 02 04 00];
 			qcom,display-topology = <1 1 1>;
 			qcom,default-topology-index = <0>;
 		};
 		timing@1 { /* qhd */
 			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
-				05 03 03 04 00];
+				05 03 02 04 00];
 			qcom,display-topology = <1 1 1>,
 						<2 2 1>, /* dsc merge */
 						<2 1 1>; /* 3d mux */
@@ -758,13 +782,13 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 { /* qhd */
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 2 2>;
 			qcom,default-topology-index = <0>;
 		};
 		timing@1 { /* 4k */
 			qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
-				06 04 03 04 00];
+				06 04 02 04 00];
 			qcom,display-topology = <2 2 2>;
 			qcom,default-topology-index = <0>;
 		};
@@ -777,7 +801,7 @@
 	qcom,mdss-dsi-display-timings {
 		 timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -792,7 +816,7 @@
 	qcom,mdss-dsi-display-timings {
 		 timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
-				07 05 03 04 00];
+				07 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -808,7 +832,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c
-				05 07 05 03 04 00];
+				05 07 05 02 04 00];
 			qcom,display-topology = <1 0 1>;
 			qcom,default-topology-index = <0>;
 		};
@@ -826,7 +850,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c
-				05 07 05 03 04 00];
+				05 07 05 02 04 00];
 			qcom,display-topology = <1 0 1>;
 			qcom,default-topology-index = <0>;
 		};
@@ -841,7 +865,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22
-				07 07 05 03 04 00];
+				07 07 05 02 04 00];
 			qcom,display-topology = <1 0 1>;
 			qcom,default-topology-index = <0>;
 		};
@@ -862,7 +886,7 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08
-				08 05 03 04 00];
+				08 05 02 04 00];
 			qcom,display-topology = <2 0 2>,
 				<1 0 2>;
 			qcom,default-topology-index = <0>;
@@ -888,7 +912,32 @@
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
-				08 05 03 04 00];
+				08 05 02 04 00];
+			qcom,display-topology = <1 0 1>;
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
+
+&dsi_hx83112a_truly_video {
+	qcom,mdss-dsi-t-clk-post = <0x0E>;
+	qcom,mdss-dsi-t-clk-pre = <0x30>;
+
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
+
+	qcom,mdss-dsi-display-timings {
+		timing@0 {
+			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
+				08 05 02 04 00];
 			qcom,display-topology = <1 0 1>;
 			qcom,default-topology-index = <0>;
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 2e2de74..e77dcc3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -311,17 +311,17 @@
 				iova-mem-region-io {
 					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd911000>;
-					iova-region-len = <0xd26ef000>;
+					iova-region-start = <0xda00000>;
+					iova-region-len = <0xd2500000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
 
 				iova-mem-qdss-region {
-					/* qdss region is approximately 64K */
+					/* qdss region is approximately 1MB */
 					iova-region-name = "qdss";
 					iova-region-start = <0xd900000>;
-					iova-region-len = <0x10000>;
+					iova-region-len = <0x100000>;
 					iova-region-id = <0x5>;
 					qdss-phy-addr = <0x16790000>;
 					status = "ok";
@@ -881,6 +881,9 @@
 	cam_ipe0: qcom,ipe0 {
 		cell-index = <0>;
 		compatible = "qcom,cam-ipe";
+		reg = <0xac87000 0x3000>;
+		reg-names = "ipe0_top";
+		reg-cam-base = <0x87000>;
 		regulator-names = "ipe0-vdd";
 		ipe0-vdd-supply = <&ipe_0_gdsc>;
 		clock-names = "ipe_0_ahb_clk",
@@ -908,6 +911,9 @@
 	cam_ipe1: qcom,ipe1 {
 		cell-index = <1>;
 		compatible = "qcom,cam-ipe";
+		reg = <0xac91000 0x3000>;
+		reg-names = "ipe1_top";
+		reg-cam-base = <0x91000>;
 		regulator-names = "ipe1-vdd";
 		ipe1-vdd-supply = <&ipe_1_gdsc>;
 		clock-names = "ipe_1_ahb_clk",
@@ -935,6 +941,9 @@
 	cam_bps: qcom,bps {
 		cell-index = <0>;
 		compatible = "qcom,cam-bps";
+		reg = <0xac6f000 0x3000>;
+		reg-names = "bps_top";
+		reg-cam-base = <0x6f000>;
 		regulator-names = "bps-vdd";
 		bps-vdd-supply = <&bps_gdsc>;
 		clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 97cb981..c9669d9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -248,17 +248,17 @@
 				iova-mem-region-io {
 					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd911000>;
-					iova-region-len = <0xd26ef000>;
+					iova-region-start = <0xda00000>;
+					iova-region-len = <0xd2500000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
 
 				iova-mem-qdss-region {
-					/* qdss region is approximately 64K */
+					/* qdss region is approximately 1MB */
 					iova-region-name = "qdss";
 					iova-region-start = <0xd900000>;
-					iova-region-len = <0x10000>;
+					iova-region-len = <0x100000>;
 					iova-region-id = <0x5>;
 					qdss-phy-addr = <0x16790000>;
 					status = "ok";
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
index be3fae7..bf35544 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -591,6 +591,9 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
 CONFIG_F2FS_FS=y
 CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
@@ -622,12 +625,12 @@
 CONFIG_CORESIGHT_CTI=y
 CONFIG_CORESIGHT_EVENT=y
 CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
index ebcc83e..ba390c4 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -610,6 +610,9 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
 CONFIG_F2FS_FS=y
 CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
@@ -688,12 +691,12 @@
 CONFIG_CORESIGHT_CTI=y
 CONFIG_CORESIGHT_EVENT=y
 CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index fca320e..eeb1d74 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -604,6 +604,9 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
 CONFIG_F2FS_FS=y
 CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
@@ -635,12 +638,12 @@
 CONFIG_CORESIGHT_CTI=y
 CONFIG_CORESIGHT_EVENT=y
 CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index a3547be..d0783cd 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -623,6 +623,9 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
 CONFIG_F2FS_FS=y
 CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
@@ -702,12 +705,12 @@
 CONFIG_CORESIGHT_CTI=y
 CONFIG_CORESIGHT_EVENT=y
 CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index e35e571..0c54182 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -520,6 +520,7 @@
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_MINIDUMP=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_QCOM_SECURE_BUFFER=y
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 065b765..fff2ae9 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -2564,22 +2564,6 @@
 	return arm_iommu_create_mapping(&platform_bus_type, base, size);
 }
 
-static int gpi_dma_mask(struct gpi_dev *gpi_dev)
-{
-	int mask = 64;
-
-	if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) {
-		unsigned long addr;
-
-		addr = gpi_dev->iova_base + gpi_dev->iova_size + 1;
-		mask = find_last_bit(&addr, 64);
-	}
-
-	GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask);
-
-	return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask));
-}
-
 static int gpi_smmu_init(struct gpi_dev *gpi_dev)
 {
 	struct dma_iommu_mapping *mapping = NULL;
@@ -2643,9 +2627,10 @@
 		}
 	}
 
-	ret = gpi_dma_mask(gpi_dev);
+	GPI_LOG(gpi_dev, "Setting dma mask to 64\n");
+	ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64));
 	if (ret) {
-		GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret);
+		GPI_ERR(gpi_dev, "Error setting dma_mask to 64, ret:%d\n", ret);
 		goto error_set_mask;
 	}
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index f0ea211..1880ad1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -377,7 +377,7 @@
 
 		if (r_config->sequence[i].sleep_ms)
 			usleep_range(r_config->sequence[i].sleep_ms * 1000,
-				     r_config->sequence[i].sleep_ms * 1000);
+				(r_config->sequence[i].sleep_ms * 1000) + 100);
 	}
 
 	if (gpio_is_valid(panel->bl_config.en_gpio)) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
index 3da0fc3..45f7577 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
@@ -113,7 +113,7 @@
 		else
 			timing->lane[i][4] = desc->hs_rqst.reg_value;
 
-		timing->lane[i][5] = 0x3;
+		timing->lane[i][5] = 0x2;
 		timing->lane[i][6] = 0x4;
 		timing->lane[i][7] = 0xA0;
 		pr_debug("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0],
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
index 4392c60..c0e9d44 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
@@ -92,7 +92,7 @@
 	timing->lane_v3[6] = desc->hs_prepare.reg_value;
 	timing->lane_v3[7] = desc->hs_trail.reg_value;
 	timing->lane_v3[8] = desc->hs_rqst.reg_value;
-	timing->lane_v3[9] = 0x03;
+	timing->lane_v3[9] = 0x02;
 	timing->lane_v3[10] = 0x04;
 	timing->lane_v3[11] = 0x00;
 
diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c
index d5a438e..f830010 100644
--- a/drivers/gpu/drm/msm/sde_io_util.c
+++ b/drivers/gpu/drm/msm/sde_io_util.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 2017, 2018, 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
@@ -230,7 +231,7 @@
 			need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
 			if (in_vreg[i].pre_on_sleep && need_sleep)
 				usleep_range(in_vreg[i].pre_on_sleep * 1000,
-					in_vreg[i].pre_on_sleep * 1000);
+					(in_vreg[i].pre_on_sleep * 1000) + 10);
 			rc = regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].enable_load);
 			if (rc < 0) {
@@ -242,7 +243,7 @@
 			rc = regulator_enable(in_vreg[i].vreg);
 			if (in_vreg[i].post_on_sleep && need_sleep)
 				usleep_range(in_vreg[i].post_on_sleep * 1000,
-					in_vreg[i].post_on_sleep * 1000);
+					(in_vreg[i].post_on_sleep * 1000) + 10);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s enable failed\n",
 					__builtin_return_address(0), __func__,
@@ -254,13 +255,13 @@
 		for (i = num_vreg-1; i >= 0; i--) {
 			if (in_vreg[i].pre_off_sleep)
 				usleep_range(in_vreg[i].pre_off_sleep * 1000,
-					in_vreg[i].pre_off_sleep * 1000);
+					(in_vreg[i].pre_off_sleep * 1000) + 10);
 			regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].disable_load);
 			regulator_disable(in_vreg[i].vreg);
 			if (in_vreg[i].post_off_sleep)
 				usleep_range(in_vreg[i].post_off_sleep * 1000,
-					in_vreg[i].post_off_sleep * 1000);
+				(in_vreg[i].post_off_sleep * 1000) + 10);
 		}
 	}
 	return rc;
@@ -272,13 +273,13 @@
 	for (i--; i >= 0; i--) {
 		if (in_vreg[i].pre_off_sleep)
 			usleep_range(in_vreg[i].pre_off_sleep * 1000,
-				in_vreg[i].pre_off_sleep * 1000);
+				(in_vreg[i].pre_off_sleep * 1000) + 10);
 		regulator_set_load(in_vreg[i].vreg,
 			in_vreg[i].disable_load);
 		regulator_disable(in_vreg[i].vreg);
 		if (in_vreg[i].post_off_sleep)
 			usleep_range(in_vreg[i].post_off_sleep * 1000,
-				in_vreg[i].post_off_sleep * 1000);
+				(in_vreg[i].post_off_sleep * 1000) + 10);
 	}
 
 	return rc;
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
index 26cee2e..34508b2 100644
--- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
@@ -963,6 +963,8 @@
 	struct vl_data *data = dev_get_drvdata(dev);
 	struct VL_RangingMeasurementData_t Measure;
 
+	if (data->enable_ps_sensor == 0)
+		return -ENODEV;
 	papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
 	return snprintf(buf, 7, "%d\n", Measure.RangeMilliMeter);
 }
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6c4156a..e9c1d69 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1279,6 +1279,18 @@
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_GT9XX_v28
+	bool "Goodix touchpanel GT9xx_v28 series"
+	depends on I2C
+	help
+	  Say Y here if you have a Goodix GT9xx_v28 touchscreen.
+	  Gt9xx controllers are multi touch controllers which can
+	  report 5 touches at a time.
+
+          If unsure, say N.
+
+source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig"
+
 config TOUCHSCREEN_HIMAX_CHIPSET
 	bool "Himax touchpanel CHIPSET"
 	depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index a5952ca..c8e0104 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -105,3 +105,4 @@
 obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023)	+= rohm_bu21023.o
 obj-$(CONFIG_TOUCHSCREEN_FTS)		+= focaltech_touch/
 obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET)	+= hxchipset/
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28)		+= gt9xx_v2.8/
\ No newline at end of file
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Kconfig b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig
new file mode 100644
index 0000000..7046cc9
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig
@@ -0,0 +1,36 @@
+#
+# Goodix GT9xx Touchscreen driver
+#
+config TOUCHSCREEN_GT9XX_v28
+	bool "Goodix touchpanel GT9xx series"
+	depends on I2C
+	help
+	  Enable this for support Goodix GT9xx_v28 driver.
+
+	  Say Y here if you have a Goodix GT9xx touchscreen
+	  controller.
+
+          If unsure, say N.
+
+config TOUCHSCREEN_GT9XX_UPDATE
+	tristate "Goodix GT9xx touch controller auto update support"
+	depends on TOUCHSCREEN_GT9XX_v28
+	help
+	  Enable this for support firmware update.
+
+	  Say Y here if you want update touch controller
+	  firmware.
+
+	  If unsure, say N.
+
+config TOUCHSCREEN_GT9XX_TOOL
+	tristate "Goodix GT9xx Tools for debuging"
+	depends on TOUCHSCREEN_GT9XX_v28
+	help
+	  This implement interface support for Goodix GT9xx
+	  touchscreen debug.
+
+	  Say Y here if you want to have a Android app debug interface
+	  to your system.
+
+	  If unsure, say N.
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Makefile b/drivers/input/touchscreen/gt9xx_v2.8/Makefile
new file mode 100644
index 0000000..6c1c404
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Goodix gt9xx touchscreen driver.
+#
+#subdir-ccflags-y += -DDEBUG
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28)	+= gt9xx.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_UPDATE)	+= gt9xx_update.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_TOOL)	+= goodix_tool.o
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c
new file mode 100644
index 0000000..7db5ae2
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c
@@ -0,0 +1,529 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright  (C)  2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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 "gt9xx.h"
+
+#define DATA_LENGTH_UINT	512
+#define CMD_HEAD_LENGTH		(sizeof(struct st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#pragma pack(1)
+struct st_cmd_head {
+	u8	wr;		/*write read flag 0:R 1:W 2:PID 3:*/
+	u8	flag;		/*0:no need flag/int 1: need flag 2:need int*/
+	u8	flag_addr[2];	/*flag address*/
+	u8	flag_val;	/*flag val*/
+	u8	flag_relation;	/*flag_val:flag 0:not equal 1:equal 2:> 3:<*/
+	u16	circle;		/*polling cycle*/
+	u8	times;		/*plling times*/
+	u8	retry;		/*I2C retry times*/
+	u16	delay;		/*delay before read or after write*/
+	u16	data_len;	/*data length*/
+	u8	addr_len;	/*address length*/
+	u8	addr[2];	/*address*/
+	u8	res[3];		/*reserved*/
+	u8	*data; };	/*data pointer*/
+#pragma pack()
+struct st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+static struct proc_dir_entry *goodix_proc_entry;
+
+static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t goodix_tool_write(struct file *, const char __user *,
+						size_t, loff_t *);
+static const struct file_operations gtp_proc_ops = {
+	.owner = THIS_MODULE,
+	.read = goodix_tool_read,
+	.write = goodix_tool_write,
+};
+
+/* static s32 goodix_tool_write(struct file *filp,
+ * const char __user *buff, unsigned long len, void *data);
+ */
+/*static s32 goodix_tool_read( char *page, char
+ **start, off_t off, int count, int *eof, void *data );
+ */
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+static s32 DATA_LENGTH = (s32)0;
+static s8 IC_TYPE[16] = "GT9XX";
+
+static void tool_set_proc_name(char *procname)
+{
+	snprintf(procname, 20, "gmnode"); /* modify for moto */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH);
+		if (ret > 0)
+			break;
+	}
+	return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = gtp_i2c_write(ts->client, buf, len);
+		if (ret > 0)
+			break;
+	}
+
+	return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_read_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_write_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static void register_i2c_func(void)
+{
+	/* if (!strcmp(IC_TYPE, "GT818", 5)
+	 *  || !strcmp(IC_TYPE, "GT816", 5)
+	 *  || !strcmp(IC_TYPE, "GT811", 5)
+	 *  || !strcmp(IC_TYPE, "GT818F", 6)
+	 *  || !strcmp(IC_TYPE, "GT827", 5)
+	 *  || !strcmp(IC_TYPE,"GT828", 5)
+	 *  || !strcmp(IC_TYPE, "GT813", 5))
+	 */
+	if (strcmp(IC_TYPE, "GT8110") &&
+	    strcmp(IC_TYPE, "GT8105") &&
+	    strcmp(IC_TYPE, "GT801") &&
+	    strcmp(IC_TYPE, "GT800") &&
+	    strcmp(IC_TYPE, "GT801PLUS") &&
+	    strcmp(IC_TYPE, "GT811") &&
+	    strcmp(IC_TYPE, "GTxxx") &&
+	    strcmp(IC_TYPE, "GT9XX")) {
+		tool_i2c_read = tool_i2c_read_with_extra;
+		tool_i2c_write = tool_i2c_write_with_extra;
+		dev_dbg(&gt_client->dev, "I2C function: with pre and end cmd!");
+	} else {
+		tool_i2c_read = tool_i2c_read_no_extra;
+		tool_i2c_write = tool_i2c_write_no_extra;
+		dev_info(&gt_client->dev, "I2C function: without pre and end cmd!");
+	}
+}
+
+static void unregister_i2c_func(void)
+{
+	tool_i2c_read = NULL;
+	tool_i2c_write = NULL;
+	dev_info(&gt_client->dev, "I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+	s32 i;
+
+	gt_client = client;
+	memset(&cmd_head, 0, sizeof(cmd_head));
+	cmd_head.data = NULL;
+
+	i = 6;
+	while ((!cmd_head.data) && i) {
+		cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+		if (cmd_head.data)
+			break;
+		i--;
+	}
+	if (i) {
+		DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH;
+		dev_info(&gt_client->dev,
+			 "Alloc memory size:%d.", DATA_LENGTH);
+	} else {
+		dev_err(&gt_client->dev, "Apply for memory failed.");
+		return FAIL;
+	}
+
+	cmd_head.addr_len = 2;
+	cmd_head.retry = 5;
+
+	register_i2c_func();
+
+	tool_set_proc_name(procname);
+	goodix_proc_entry = proc_create(procname, 0664, NULL, &gtp_proc_ops);
+	if (!goodix_proc_entry) {
+		dev_err(&gt_client->dev, "Couldn't create proc entry!");
+		return FAIL;
+	}
+
+	dev_info(&gt_client->dev, "Create proc entry success!");
+	return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+	kfree(cmd_head.data);
+	cmd_head.data = NULL;
+	unregister_i2c_func();
+	remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+	u8 ret = 0;
+
+	switch (rlt) {
+	case 0:
+		ret = (src != dst) ? true : false;
+		break;
+
+	case 1:
+		ret = (src == dst) ? true : false;
+		dev_dbg(&gt_client->dev,
+			"equal:src:0x%02x  dst:0x%02x  ret:%d.",
+			src, dst, (s32)ret);
+		break;
+
+	case 2:
+		ret = (src > dst) ? true : false;
+		break;
+
+	case 3:
+		ret = (src < dst) ? true : false;
+		break;
+
+	case 4:
+		ret = (src & dst) ? true : false;
+		break;
+
+	case 5:
+		ret = (!(src | dst)) ? true : false;
+		break;
+
+	default:
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+/*******************************************************
+ * Function:
+ *	Comfirm function.
+ * Input:
+ *	None.
+ * Output:
+ *	Return write length.
+ ********************************************************/
+static u8 comfirm(void)
+{
+	s32 i = 0;
+	u8 buf[32];
+
+	memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+	for (i = 0; i < cmd_head.times; i++) {
+		if (tool_i2c_read(buf, 1) <= 0) {
+			dev_err(&gt_client->dev, "Read flag data failed!");
+			return FAIL;
+		}
+		if (true == relation(buf[GTP_ADDR_LENGTH],
+		 cmd_head.flag_val, cmd_head.flag_relation)) {
+			dev_dbg(&gt_client->dev, "value at flag addr:0x%02x.",
+				buf[GTP_ADDR_LENGTH]);
+			dev_dbg(&gt_client->dev, "flag value:0x%02x.",
+				cmd_head.flag_val);
+			break;
+		}
+
+		msleep(cmd_head.circle);
+	}
+
+	if (i >= cmd_head.times) {
+		dev_err(&gt_client->dev, "Can't get the continue flag!");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+ssize_t goodix_tool_write(struct file *filp, const char __user *buff,
+			  size_t len, loff_t *off)
+{
+	s32 ret = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+
+	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+	if (ret) {
+		dev_err(&gt_client->dev, "copy_from_user failed.");
+		return -EPERM;
+	}
+
+	dev_dbg(&gt_client->dev, "[Operation]wr: %02X", cmd_head.wr);
+	dev_dbg(&gt_client->dev,
+		"[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X",
+		cmd_head.flag, cmd_head.flag_addr[0],
+		cmd_head.flag_addr[1], cmd_head.flag_val,
+		cmd_head.flag_relation);
+	dev_dbg(&gt_client->dev,
+		"[Retry]circle: %d,times: %d,retry: %d, delay: %d",
+		(s32)cmd_head.circle,
+		(s32)cmd_head.times, (s32)cmd_head.retry,
+		(s32)cmd_head.delay);
+
+	if (cmd_head.wr == 1) {
+		if (cmd_head.data_len > DATA_LENGTH) {
+			dev_err(&gt_client->dev,
+				"Tool write failed data too long");
+			return -EPERM;
+		}
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				     &buff[CMD_HEAD_LENGTH],
+				     cmd_head.data_len);
+		if (ret) {
+			dev_err(&gt_client->dev, "copy_from_user failed.");
+			return -EPERM;
+		}
+		memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+		       cmd_head.addr, cmd_head.addr_len);
+
+		GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len +
+				cmd_head.addr_len);
+
+		if (cmd_head.flag == 1) {
+			if (comfirm() == FAIL) {
+				dev_err(&gt_client->dev,
+					"[WRITE]Comfirm fail!");
+				return -EPERM;
+			}
+		} else if (cmd_head.flag == 2) {
+			/*Need interrupt!*/
+		}
+		if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH -
+				   cmd_head.addr_len], cmd_head.data_len +
+				   cmd_head.addr_len) <= 0) {
+			dev_err(&gt_client->dev, "[WRITE]Write data failed!");
+			return -EPERM;
+		}
+
+		GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH -
+				cmd_head.addr_len],
+				cmd_head.data_len + cmd_head.addr_len);
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+	} else if (cmd_head.wr == 3) {
+		if (cmd_head.data_len > DATA_LENGTH) {
+			dev_err(&gt_client->dev,
+				"Tool write failed data too long");
+			return -EPERM;
+		}
+		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+				     cmd_head.data_len);
+		if (ret) {
+			dev_err(&gt_client->dev, "copy_from_user failed.");
+			return -EPERM;
+		}
+		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+		register_i2c_func();
+	} else if (cmd_head.wr == 5) {
+		/*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/
+	} else if (cmd_head.wr == 7) {/*disable irq!*/
+		gtp_work_control_enable(i2c_get_clientdata(gt_client), false);
+
+		if (ts->pdata->esd_protect)
+			gtp_esd_off(ts);
+	} else if (cmd_head.wr == 9) {/*enable irq!*/
+		gtp_work_control_enable(i2c_get_clientdata(gt_client), true);
+
+		if (ts->pdata->esd_protect)
+			gtp_esd_on(ts);
+	} else if (cmd_head.wr == 17) {
+		if (cmd_head.data_len > DATA_LENGTH) {
+			dev_err(&gt_client->dev,
+				"Tool write failed data too long");
+			return -EPERM;
+		}
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				     &buff[CMD_HEAD_LENGTH],
+				     cmd_head.data_len);
+		if (ret) {
+			dev_dbg(&gt_client->dev, "copy_from_user failed.");
+			return -EPERM;
+		}
+		if (cmd_head.data[GTP_ADDR_LENGTH]) {
+			dev_info(&gt_client->dev, "gtp enter rawdiff.");
+			set_bit(RAW_DATA_MODE, &ts->flags);
+		} else {
+			clear_bit(RAW_DATA_MODE, &ts->flags);
+			dev_info(&gt_client->dev, "gtp leave rawdiff.");
+		}
+	} else if (cmd_head.wr == 19) {
+		/* add new command: reset guitar */
+		gtp_reset_guitar(gt_client, 20);
+	}
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+	else if (cmd_head.wr == 11) {/*Enter update mode!*/
+		if (gup_enter_update_mode(gt_client) == FAIL)
+			return -EPERM;
+	} else if (cmd_head.wr == 13) {/*Leave update mode!*/
+		gup_leave_update_mode(gt_client);
+	} else if (cmd_head.wr == 15) {/*Update firmware!*/
+		show_len = 0;
+		total_len = 0;
+		if (cmd_head.data_len > DATA_LENGTH) {
+			dev_err(&gt_client->dev,
+				"Tool write failed data too long");
+			return -EPERM;
+		}
+		memset(cmd_head.data, 0, DATA_LENGTH);
+		ret = copy_from_user(cmd_head.data,
+				     &buff[CMD_HEAD_LENGTH],
+				     cmd_head.data_len);
+		if (ret) {
+			dev_dbg(&gt_client->dev, "copy_from_user failed.");
+			return -EPERM;
+		}
+
+		if (gup_update_proc((void *)cmd_head.data) == FAIL)
+			return -EPERM;
+	}
+#endif
+
+	return len;
+}
+
+/*******************************************************
+ * Function:
+ *	Goodix tool read function.
+ * Input:
+ *	standard proc read function param.
+ * Output:
+ *	Return read length.
+ ********************************************************/
+ssize_t goodix_tool_read(struct file *file, char __user *page,
+			 size_t size, loff_t *ppos)
+{
+	s32 ret = 0;
+
+	if (*ppos) {
+		/* ADB call again
+		 * dev_dbg(&gt_client->dev, "[HEAD]wr: %d", cmd_head.wr);
+		 * dev_dbg(&gt_client->dev,
+		 * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos);
+		 * dev_dbg(&gt_client->dev,
+		 * "[TOOL_READ]ADB call again, return it.");
+		 */
+		*ppos = 0;
+		return 0;
+	}
+
+	if (cmd_head.wr % 2) {
+		return -EPERM;
+	} else if (!cmd_head.wr) {
+		u16 len, data_len, loc, addr;
+
+		if (cmd_head.flag == 1) {
+			if (comfirm() == FAIL) {
+				dev_err(&gt_client->dev, "[READ]Comfirm fail!");
+				return -EPERM;
+			}
+		} else if (cmd_head.flag == 2) {
+			/*Need interrupt!*/
+		}
+
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+
+		data_len = cmd_head.data_len;
+		addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1];
+		loc = 0;
+
+		while (data_len > 0) {
+			len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len;
+			cmd_head.data[0] = (addr >> 8) & 0xFF;
+			cmd_head.data[1] = (addr & 0xFF);
+			if (tool_i2c_read(cmd_head.data, len) <= 0) {
+				dev_err(&gt_client->dev, "[READ]Read data failed!");
+				return -EPERM;
+			}
+			ret = simple_read_from_buffer(&page[loc], size, ppos,
+					&cmd_head.data[GTP_ADDR_LENGTH], len);
+			if (ret < 0)
+				return ret;
+			loc += len;
+			addr += len;
+			data_len -= len;
+		}
+		return cmd_head.data_len;
+	} else if (cmd_head.wr == 2) {
+		ret = simple_read_from_buffer(page, size, ppos,
+					      IC_TYPE, sizeof(IC_TYPE));
+		return ret;
+	}
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+	else if (cmd_head.wr == 4) {
+		u8 progress_buf[4];
+
+		progress_buf[0] = show_len >> 8;
+		progress_buf[1] = show_len & 0xff;
+		progress_buf[2] = total_len >> 8;
+		progress_buf[3] = total_len & 0xff;
+
+		ret = simple_read_from_buffer(page, size, ppos,
+					      progress_buf, 4);
+		return ret;
+	}
+#endif
+	else if (cmd_head.wr == 6) {
+		/*Read error code!*/
+	} else if (cmd_head.wr == 8) {	/*Read driver version*/
+		ret = simple_read_from_buffer(page, size, ppos,
+					      GTP_DRIVER_VERSION,
+					      strlen(GTP_DRIVER_VERSION));
+		return ret;
+	}
+
+	return -EPERM;
+}
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c
new file mode 100644
index 0000000..03328d0
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c
@@ -0,0 +1,2678 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright  (C)  2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/input/mt.h>
+#include "gt9xx.h"
+
+#define GOODIX_VTG_MIN_UV	2600000
+#define GOODIX_VTG_MAX_UV	3300000
+#define GOODIX_I2C_VTG_MIN_UV	1800000
+#define GOODIX_I2C_VTG_MAX_UV	1800000
+
+#define DELAY_FOR_DISCHARGING		35
+#define GOODIX_COORDS_ARR_SIZE	4
+#define PROP_NAME_SIZE		24
+#define I2C_MAX_TRANSFER_SIZE   255
+#define GTP_PEN_BUTTON1		BTN_STYLUS
+#define GTP_PEN_BUTTON2		BTN_STYLUS2
+
+static const char *goodix_ts_name = "goodix-ts";
+static const char *goodix_input_phys = "input/ts";
+struct i2c_client *i2c_connect_client;
+static struct proc_dir_entry *gtp_config_proc;
+
+enum doze {
+	DOZE_DISABLED = 0,
+	DOZE_ENABLED = 1,
+	DOZE_WAKEUP = 2,
+};
+
+static enum doze doze_status = DOZE_DISABLED;
+
+static int gtp_i2c_test(struct i2c_client *client);
+static int gtp_enter_doze(struct goodix_ts_data *ts);
+
+static int gtp_unregister_powermanager(struct goodix_ts_data *ts);
+static int gtp_register_powermanager(struct goodix_ts_data *ts);
+
+static int gtp_esd_init(struct goodix_ts_data *ts);
+static void gtp_esd_check_func(struct work_struct *);
+static int gtp_init_ext_watchdog(struct i2c_client *client);
+
+/*
+ * return: 2 - ok, < 0 - i2c transfer error
+ */
+int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
+{
+	unsigned int transfer_length = 0;
+	unsigned int pos = 0, address = (buf[0] << 8) + buf[1];
+	unsigned char get_buf[64], addr_buf[2];
+	int retry, r = 2;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = !I2C_M_RD,
+			.buf = &addr_buf[0],
+			.len = GTP_ADDR_LENGTH,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+		}
+	};
+
+	len -= GTP_ADDR_LENGTH;
+	if (likely(len < sizeof(get_buf))) {
+		/* code optimize, use stack memory */
+		msgs[1].buf = &get_buf[0];
+	} else {
+		msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE
+				? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
+		if (!msgs[1].buf)
+			return -ENOMEM;
+	}
+
+	while (pos != len) {
+		if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE))
+			transfer_length = I2C_MAX_TRANSFER_SIZE;
+		else
+			transfer_length = len - pos;
+		msgs[0].buf[0] = (address >> 8) & 0xFF;
+		msgs[0].buf[1] = address & 0xFF;
+		msgs[1].len = transfer_length;
+		for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+			if (likely(i2c_transfer(client->adapter,
+					msgs, 2) == 2)) {
+				memcpy(&buf[2 + pos], msgs[1].buf,
+					transfer_length);
+				pos += transfer_length;
+				address += transfer_length;
+				break;
+			}
+			dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n",
+				retry + 1, address);
+			usleep_range(2000, 2100);
+		}
+		if (unlikely(retry == RETRY_MAX_TIMES)) {
+			dev_err(&client->dev,
+				"I2c read failed,dev:%02x,reg:%04x,size:%u\n",
+				client->addr, address, len);
+			r = -EAGAIN;
+			goto read_exit;
+		}
+	}
+read_exit:
+	if (len >= sizeof(get_buf))
+		kfree(msgs[1].buf);
+	return r;
+}
+
+/*******************************************************
+ * Function:
+ *	Write data to the i2c slave device.
+ * Input:
+ *	client: i2c device.
+ *	buf[0~1]: write start address.
+ *	buf[2~len-1]: data buffer
+ *	len: GTP_ADDR_LENGTH + write bytes count
+ * Output:
+ *	numbers of i2c_msgs to transfer:
+ *		1: succeed, otherwise: failed
+ *********************************************************/
+int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
+
+{
+	unsigned int pos = 0, transfer_length = 0;
+	unsigned int address = (buf[0] << 8) + buf[1];
+	unsigned char put_buf[64];
+	int retry, r = 1;
+	struct i2c_msg msg = {
+			.addr = client->addr,
+			.flags = !I2C_M_RD,
+	};
+
+	if (likely(len < sizeof(put_buf))) {
+		/* code optimize,use stack memory*/
+		msg.buf = &put_buf[0];
+	} else {
+		msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE
+				  ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
+		if (!msg.buf)
+			return -ENOMEM;
+	}
+
+	len -= GTP_ADDR_LENGTH;
+	while (pos != len) {
+		if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE
+						- GTP_ADDR_LENGTH))
+			transfer_length = I2C_MAX_TRANSFER_SIZE
+						- GTP_ADDR_LENGTH;
+		else
+			transfer_length = len - pos;
+		msg.buf[0] = (unsigned char)((address >> 8) & 0xFF);
+		msg.buf[1] = (unsigned char)(address & 0xFF);
+		msg.len = transfer_length + 2;
+		memcpy(&msg.buf[2], &buf[2 + pos], transfer_length);
+		for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+			if (likely(i2c_transfer(client->adapter,
+					&msg, 1) == 1)) {
+				pos += transfer_length;
+				address += transfer_length;
+				break;
+			}
+			dev_dbg(&client->dev, "I2C write retry[%d]\n",
+					retry + 1);
+			usleep_range(2000, 2100);
+		}
+		if (unlikely(retry == RETRY_MAX_TIMES)) {
+			dev_err(&client->dev,
+				"I2c write failed,dev:%02x,reg:%04x,size:%u\n",
+				client->addr, address, len);
+			r = -EAGAIN;
+			goto write_exit;
+		}
+	}
+write_exit:
+	if (len + GTP_ADDR_LENGTH >= sizeof(put_buf))
+		kfree(msg.buf);
+	return r;
+}
+
+/*******************************************************
+ * Function:
+ *	i2c read twice, compare the results
+ * Input:
+ *	client:	i2c device
+ *	addr: operate address
+ *	rxbuf: read data to store, if compare successful
+ *	len: bytes to read
+ * Output:
+ *	FAIL: read failed
+ *	SUCCESS: read successful
+ *********************************************************/
+s32 gtp_i2c_read_dbl_check(struct i2c_client *client,
+			   u16 addr, u8 *rxbuf, int len)
+{
+	u8 buf[16] = {0};
+	u8 confirm_buf[16] = {0};
+	u8 retry = 0;
+
+	if (len + 2 > sizeof(buf)) {
+		dev_warn(&client->dev,
+			 "%s, only support length less then %zu\n",
+			 __func__, sizeof(buf) - 2);
+		return FAIL;
+	}
+	while (retry++ < 3) {
+		memset(buf, 0xAA, 16);
+		buf[0] = (u8)(addr >> 8);
+		buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, buf, len + 2);
+
+		memset(confirm_buf, 0xAB, 16);
+		confirm_buf[0] = (u8)(addr >> 8);
+		confirm_buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, confirm_buf, len + 2);
+
+		if (!memcmp(buf, confirm_buf, len + 2)) {
+			memcpy(rxbuf, confirm_buf + 2, len);
+			return SUCCESS;
+		}
+	}
+	dev_err(&client->dev,
+		"I2C read 0x%04X, %d bytes, double check failed!\n",
+		addr, len);
+
+	return FAIL;
+}
+
+/*******************************************************
+ * Function:
+ *      Send config.
+ * Input:
+ *      client: i2c device.
+ * Output:
+ *      result of i2c write operation.
+ *              1: succeed, otherwise
+ *              0: Not executed
+ *		< 0: failed
+ *********************************************************/
+s32 gtp_send_cfg(struct i2c_client *client)
+{
+	s32 ret, i;
+	u8 check_sum;
+	s32 retry = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	struct goodix_config_data *cfg = &ts->pdata->config;
+
+	if (!cfg->length || !ts->pdata->driver_send_cfg) {
+		dev_info(&ts->client->dev,
+			 "No config data or error occurred in panel_init\n");
+		return 0;
+	}
+
+	check_sum = 0;
+	for (i = GTP_ADDR_LENGTH; i < cfg->length; i++)
+		check_sum += cfg->data[i];
+	cfg->data[cfg->length] = (~check_sum) + 1;
+
+	dev_info(&ts->client->dev, "Driver send config\n");
+	for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+		ret = gtp_i2c_write(client, cfg->data,
+			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+		if (ret > 0)
+			break;
+	}
+
+	return ret;
+}
+
+/*******************************************************
+ * Function:
+ *	Control enable or disable of work thread.
+ * Input:
+ *      ts: goodix i2c_client private data
+ *	enable: enable var.
+ *********************************************************/
+void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable)
+{
+	if (enable) {
+		set_bit(REPORT_THREAD_ENABLED, &ts->flags);
+		dev_dbg(&ts->client->dev, "Input report thread enabled!\n");
+	} else {
+		clear_bit(REPORT_THREAD_ENABLED, &ts->flags);
+		dev_dbg(&ts->client->dev, "Input report thread disabled!\n");
+	}
+}
+
+static int gtp_gesture_handler(struct goodix_ts_data *ts)
+{
+	u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF};
+	int ret;
+
+	ret = gtp_i2c_read(ts->client, doze_buf, 3);
+	if (ret < 0) {
+		dev_err(&ts->client->dev, "Failed read doze buf");
+		return -EINVAL;
+	}
+
+	dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]);
+	if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') ||
+	    (doze_buf[2] == 'c') || (doze_buf[2] == 'd') ||
+	    (doze_buf[2] == 'e') || (doze_buf[2] == 'g') ||
+	    (doze_buf[2] == 'h') || (doze_buf[2] == 'm') ||
+	    (doze_buf[2] == 'o') || (doze_buf[2] == 'q') ||
+	    (doze_buf[2] == 's') || (doze_buf[2] == 'v') ||
+	    (doze_buf[2] == 'w') || (doze_buf[2] == 'y') ||
+	    (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) ||
+	    (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) ||
+	    (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) ||
+	    (doze_buf[2] == 0xCC)) {
+		doze_status = DOZE_WAKEUP;
+		input_report_key(ts->input_dev, KEY_POWER, 1);
+		input_sync(ts->input_dev);
+		input_report_key(ts->input_dev, KEY_POWER, 0);
+		input_sync(ts->input_dev);
+		/*  clear 0x814B */
+		doze_buf[2] = 0x00;
+		gtp_i2c_write(ts->client, doze_buf, 3);
+	} else {
+		/*  clear 0x814B */
+		doze_buf[2] = 0x00;
+		gtp_i2c_write(ts->client, doze_buf, 3);
+		gtp_enter_doze(ts);
+	}
+	return 0;
+}
+
+/*
+ * return touch state register value
+ * pen event id fixed with 9 and set tool type TOOL_PEN
+ *
+ */
+static u8 gtp_get_points(struct goodix_ts_data *ts,
+			 struct goodix_point_t *points,
+			 u8 *key_value)
+{
+	int ret;
+	int i;
+	u8 *coor_data = NULL;
+	u8 finger_state = 0;
+	u8 touch_num = 0;
+	u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
+			  GTP_READ_COOR_ADDR & 0xFF, 0 };
+	u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = {
+			GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF };
+
+	ret = gtp_i2c_read(ts->client, point_data, 12);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+			"I2C transfer error. errno:%d\n ", ret);
+		return 0;
+	}
+	finger_state = point_data[GTP_ADDR_LENGTH];
+	if (finger_state == 0x00)
+		return 0;
+
+	touch_num = finger_state & 0x0f;
+	if ((finger_state & MASK_BIT_8) == 0 ||
+	    touch_num > ts->pdata->max_touch_id) {
+		dev_err(&ts->client->dev,
+			"Invalid touch state: 0x%x", finger_state);
+		finger_state = 0;
+		goto exit_get_point;
+	}
+
+	if (touch_num > 1) {
+		u8 buf[8 * GTP_MAX_TOUCH_ID] = {
+					  (GTP_READ_COOR_ADDR + 10) >> 8,
+					  (GTP_READ_COOR_ADDR + 10) & 0xff };
+
+		ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
+		if (ret < 0) {
+			dev_err(&ts->client->dev, "I2C error. %d\n", ret);
+			finger_state = 0;
+			goto exit_get_point;
+		}
+		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+	}
+
+	/* panel have touch key */
+	/* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */
+	*key_value = point_data[3 + 8 * touch_num];
+
+	memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID);
+	for (i = 0; i < touch_num; i++) {
+		coor_data = &point_data[i * 8 + 3];
+		points[i].id = coor_data[0];
+		points[i].x = coor_data[1] | (coor_data[2] << 8);
+		points[i].y = coor_data[3] | (coor_data[4] << 8);
+		points[i].w = coor_data[5] | (coor_data[6] << 8);
+		/* if pen hover points[].p must set to zero */
+		points[i].p = coor_data[5] | (coor_data[6] << 8);
+
+		if (ts->pdata->swap_x2y)
+			GTP_SWAP(points[i].x, points[i].y);
+
+		dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n",
+			points[i].id, points[i].x, points[i].y, points[i].p);
+
+		/* pen device coordinate */
+		if (points[i].id & 0x80) {
+			points[i].tool_type = GTP_TOOL_PEN;
+			points[i].id = 10;
+			if (ts->pdata->pen_suppress_finger) {
+				points[0] = points[i];
+				memset(++points, 0, sizeof(*points) *
+					(GTP_MAX_TOUCH_ID - 1));
+				finger_state &= 0xf0;
+				finger_state |= 0x01;
+				break;
+			}
+		} else {
+			points[i].tool_type = GTP_TOOL_FINGER;
+		}
+	}
+
+exit_get_point:
+	if (!test_bit(RAW_DATA_MODE, &ts->flags)) {
+		ret = gtp_i2c_write(ts->client, end_cmd, 3);
+		if (ret < 0)
+			dev_info(&ts->client->dev, "I2C write end_cmd error!");
+	}
+	return finger_state;
+}
+
+static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num,
+			      struct goodix_point_t *points)
+{
+	int i;
+	u16 cur_touch = 0;
+	static u16 pre_touch;
+	static u8 pre_pen_id;
+
+	if (touch_num)
+		input_report_key(ts->input_dev, BTN_TOUCH, 1);
+
+	for (i = 0; i < ts->pdata->max_touch_id; i++) {
+		if (touch_num && i == points->id) {
+			input_report_abs(ts->input_dev,
+					ABS_MT_TRACKING_ID, points->id);
+
+			if (points->tool_type == GTP_TOOL_PEN) {
+				input_report_key(ts->input_dev,
+							BTN_TOOL_PEN, true);
+				pre_pen_id = points->id;
+			} else {
+				input_report_key(ts->input_dev,
+							BTN_TOOL_FINGER, true);
+			}
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					 points->x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					 points->y);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					 points->w);
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					 points->p);
+			input_mt_sync(ts->input_dev);
+
+			cur_touch |= 0x01 << points->id;
+			points++;
+		} else if (pre_touch & 0x01 << i) {
+			if (pre_pen_id == i) {
+				input_report_key(ts->input_dev,
+							BTN_TOOL_PEN, false);
+/* valid id will < 10, so id to 0xff to indicate a invalid state */
+				pre_pen_id = 0xff;
+			} else {
+				input_report_key(ts->input_dev,
+					BTN_TOOL_FINGER, false);
+			}
+		}
+	}
+
+	pre_touch = cur_touch;
+	if (!pre_touch) {
+		input_mt_sync(ts->input_dev);
+		input_report_key(ts->input_dev, BTN_TOUCH, 0);
+	}
+	input_sync(ts->input_dev);
+}
+
+static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num,
+			       struct goodix_point_t *points)
+{
+	int i;
+	u16 cur_touch = 0;
+	static u16 pre_touch;
+	static u8 pre_pen_id;
+
+	for (i = 0; i < ts->pdata->max_touch_id; i++) {
+		if (touch_num && i == points->id) {
+			input_mt_slot(ts->input_dev, points->id);
+
+			if (points->tool_type == GTP_TOOL_PEN) {
+				input_mt_report_slot_state(ts->input_dev,
+							   MT_TOOL_PEN, true);
+				pre_pen_id = points->id;
+			} else {
+				input_mt_report_slot_state(ts->input_dev,
+						MT_TOOL_FINGER, true);
+			}
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					 points->x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					 points->y);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					 points->w);
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					 points->p);
+
+			cur_touch |= 0x01 << points->id;
+			points++;
+		} else if (pre_touch & 0x01 << i) {
+			input_mt_slot(ts->input_dev, i);
+			if (pre_pen_id == i) {
+				input_mt_report_slot_state(ts->input_dev,
+							   MT_TOOL_PEN, false);
+				/* valid id will < 10, so set id to 0xff to
+				 * indicate a invalid state
+				 */
+				pre_pen_id = 0xff;
+			} else {
+				input_mt_report_slot_state(ts->input_dev,
+						MT_TOOL_FINGER, false);
+			}
+		}
+	}
+
+	pre_touch = cur_touch;
+	/* report BTN_TOUCH event */
+	input_mt_sync_frame(ts->input_dev);
+	input_sync(ts->input_dev);
+}
+
+/*******************************************************
+ * Function:
+ *	Goodix touchscreen sensor report function
+ * Input:
+ *	ts: goodix tp private data
+ * Output:
+ *	None.
+ *********************************************************/
+static void gtp_work_func(struct goodix_ts_data *ts)
+{
+	u8 point_state = 0;
+	u8 key_value = 0;
+	s32 i = 0;
+	s32 ret = -1;
+	static u8 pre_key;
+	struct goodix_point_t points[GTP_MAX_TOUCH_ID];
+
+	if (test_bit(PANEL_RESETTING, &ts->flags))
+		return;
+	if (!test_bit(REPORT_THREAD_ENABLED, &ts->flags))
+		return;
+
+	/* gesture event */
+	if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
+		ret =  gtp_gesture_handler(ts);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Failed handler gesture event %d\n", ret);
+		return;
+	}
+
+	point_state = gtp_get_points(ts, points, &key_value);
+	if (!point_state) {
+		dev_dbg(&ts->client->dev, "Invalid finger points\n");
+		return;
+	}
+
+	/* touch key event */
+	if (key_value & 0xf0 || pre_key & 0xf0) {
+		/* pen button */
+		switch (key_value) {
+		case 0x40:
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
+			break;
+		case 0x10:
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
+			dev_dbg(&ts->client->dev, "pen button1 down\n");
+			break;
+		case 0x20:
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
+			break;
+		default:
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
+			input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
+			dev_dbg(&ts->client->dev, "button1 up\n");
+			break;
+		}
+		input_sync(ts->input_dev);
+		pre_key = key_value;
+	} else if (key_value & 0x0f || pre_key & 0x0f) {
+		/* panel key */
+		for (i = 0; i < ts->pdata->key_nums; i++) {
+			if ((pre_key | key_value) & (0x01 << i))
+				input_report_key(ts->input_dev,
+						 ts->pdata->key_map[i],
+						 key_value & (0x01 << i));
+		}
+		input_sync(ts->input_dev);
+		pre_key = key_value;
+	}
+
+	if (!ts->pdata->type_a_report)
+		gtp_mt_slot_report(ts, point_state & 0x0f, points);
+	else
+		gtp_type_a_report(ts, point_state & 0x0f, points);
+}
+
+/*******************************************************
+ * Function:
+ *	Timer interrupt service routine for polling mode.
+ * Input:
+ *	timer: timer struct pointer
+ * Output:
+ *	Timer work mode.
+ * HRTIMER_NORESTART:
+ *	no restart mode
+ *********************************************************/
+static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer)
+{
+	struct goodix_ts_data *ts =
+		container_of(timer, struct goodix_ts_data, timer);
+
+	gtp_work_func(ts);
+	hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+		      HRTIMER_MODE_REL);
+
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t gtp_irq_handler(int irq, void *dev_id)
+{
+	struct goodix_ts_data *ts = dev_id;
+
+	gtp_work_func(ts);
+	return IRQ_HANDLED;
+}
+
+void gtp_int_output(struct goodix_ts_data *ts, int level)
+{
+	if (!ts->pdata->int_sync)
+		return;
+
+	if (level == 0) {
+		if (ts->pinctrl.pinctrl)
+			pinctrl_select_state(ts->pinctrl.pinctrl,
+					     ts->pinctrl.int_out_low);
+		else if (gpio_is_valid(ts->pdata->irq_gpio))
+			gpio_direction_output(ts->pdata->irq_gpio, 0);
+		else
+			dev_err(&ts->client->dev,
+				"Failed set int pin output low\n");
+	} else {
+		if (ts->pinctrl.pinctrl)
+			pinctrl_select_state(ts->pinctrl.pinctrl,
+					     ts->pinctrl.int_out_high);
+		else if (gpio_is_valid(ts->pdata->irq_gpio))
+			gpio_direction_output(ts->pdata->irq_gpio, 1);
+		else
+			dev_err(&ts->client->dev,
+				"Failed set int pin output high\n");
+	}
+}
+
+void gtp_int_sync(struct goodix_ts_data *ts, s32 ms)
+{
+	if (!ts->pdata->int_sync)
+		return;
+
+	if (ts->pinctrl.pinctrl) {
+		gtp_int_output(ts, 0);
+		msleep(ms);
+		pinctrl_select_state(ts->pinctrl.pinctrl,
+				     ts->pinctrl.int_input);
+	} else if (gpio_is_valid(ts->pdata->irq_gpio)) {
+		gpio_direction_output(ts->pdata->irq_gpio, 0);
+		msleep(ms);
+		gpio_direction_input(ts->pdata->irq_gpio);
+	} else {
+		dev_err(&ts->client->dev, "Failed sync int pin\n");
+	}
+}
+
+void gtp_rst_output(struct goodix_ts_data *ts, int level)
+{
+	if (level == 0) {
+		if (ts->pinctrl.pinctrl)
+			pinctrl_select_state(ts->pinctrl.pinctrl,
+					     ts->pinctrl.rst_out_low);
+		else if (gpio_is_valid(ts->pdata->rst_gpio))
+			gpio_direction_output(ts->pdata->rst_gpio, 0);
+		else
+			dev_err(&ts->client->dev,
+				"Failed set rst pin output low\n");
+	} else {
+		if (ts->pinctrl.pinctrl)
+			pinctrl_select_state(ts->pinctrl.pinctrl,
+					     ts->pinctrl.rst_out_high);
+		else if (gpio_is_valid(ts->pdata->rst_gpio))
+			gpio_direction_output(ts->pdata->rst_gpio, 1);
+		else
+			dev_err(&ts->client->dev,
+				"Failed set rst pin output high\n");
+	}
+}
+
+void gtp_rst_input(struct goodix_ts_data *ts)
+{
+	if (ts->pinctrl.pinctrl)
+		pinctrl_select_state(ts->pinctrl.pinctrl,
+					 ts->pinctrl.rst_input);
+	else if (gpio_is_valid(ts->pdata->rst_gpio))
+		gpio_direction_input(ts->pdata->rst_gpio);
+	else
+		dev_err(&ts->client->dev,
+			"Failed set rst pin input\n");
+}
+
+/*******************************************************
+ * Function:
+ *	Reset chip. Control the reset pin and int-pin(if
+ *	defined),
+ * Input:
+ *	client:	i2c device.
+ *	ms: reset time in millisecond
+ * Output:
+ *	None.
+ *******************************************************/
+void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	dev_info(&client->dev, "Guitar reset");
+	set_bit(PANEL_RESETTING, &ts->flags);
+	if (!gpio_is_valid(ts->pdata->rst_gpio)) {
+		dev_warn(&client->dev, "reset failed no valid reset gpio");
+		return;
+	}
+
+	gtp_rst_output(ts, 0);
+	usleep_range(ms * 1000, ms * 1000 + 100);	/*  T2: > 10ms */
+
+	gtp_int_output(ts, client->addr == 0x14);
+
+	usleep_range(2000, 3000);		/*  T3: > 100us (2ms)*/
+	gtp_rst_output(ts, 1);
+
+	usleep_range(6000, 7000);		/*  T4: > 5ms */
+	gtp_rst_input(ts);
+
+	gtp_int_sync(ts, 50);
+	if (ts->pdata->esd_protect)
+		gtp_init_ext_watchdog(client);
+
+	clear_bit(PANEL_RESETTING, &ts->flags);
+}
+
+/*******************************************************
+ * Function:
+ *	Enter doze mode for sliding wakeup.
+ * Input:
+ *	ts: goodix tp private data
+ * Output:
+ *	1: succeed, otherwise failed
+ *******************************************************/
+static int gtp_enter_doze(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+	int retry = 0;
+	u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
+				  (u8)GTP_REG_COMMAND, 8 };
+
+	/*  resend doze command
+	 * if (test_and_set_bit(DOZE_MODE, &ts->flags)) {
+	 *	dev_info(&ts->client->dev, "Already in doze mode\n");
+	 *	return SUCCESS;
+	 * }
+	 */
+	set_bit(DOZE_MODE, &ts->flags);
+	dev_dbg(&ts->client->dev, "Entering gesture mode.");
+	while (retry++ < 5) {
+		i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8);
+		i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret < 0) {
+			dev_dbg(&ts->client->dev,
+				"failed to set doze flag into 0x8046, %d\n",
+				retry);
+			continue;
+		}
+		i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8);
+		i2c_control_buf[1] = (u8)GTP_REG_COMMAND;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			dev_dbg(&ts->client->dev, "Gesture mode enabled\n");
+			return ret;
+		}
+		usleep_range(10000, 11000);
+	}
+
+	dev_err(&ts->client->dev, "Failed enter doze mode\n");
+	clear_bit(DOZE_MODE, &ts->flags);
+	return ret;
+}
+
+static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
+{
+	s8 ret = -1;
+	s8 retry = 0;
+	u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
+				  (u8)GTP_REG_COMMAND, 5 };
+
+	gtp_int_output(ts, 0);
+	usleep_range(5000, 6000);
+
+	while (retry++ < 5) {
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			dev_info(&ts->client->dev, "Enter sleep mode\n");
+
+			return ret;
+		}
+		usleep_range(10000, 11000);
+	}
+	dev_err(&ts->client->dev, "Failed send sleep cmd\n");
+
+	return ret;
+}
+
+static int gtp_wakeup_sleep(struct goodix_ts_data *ts)
+{
+	u8 retry = 0;
+	int ret = -1;
+
+	while (retry++ < 10) {
+		gtp_int_output(ts, 1);
+		usleep_range(5000, 6000);
+
+		ret = gtp_i2c_test(ts->client);
+		if (!ret) {
+			dev_dbg(&ts->client->dev, "Success wakeup sleep\n");
+
+			gtp_int_sync(ts, 25);
+			if (ts->pdata->esd_protect)
+				gtp_init_ext_watchdog(ts->client);
+
+			return ret;
+		}
+		gtp_reset_guitar(ts->client, 20);
+	}
+
+	dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n");
+	return -EINVAL;
+}
+
+static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+	u8 sensor_id = 0;
+	struct goodix_config_data *cfg = &ts->pdata->config;
+
+	/* if defined CONFIG_OF, parse config data from dtsi
+	 * else parse config data form header file.
+	 */
+	cfg->length = 0;
+
+#ifndef	CONFIG_OF
+	u8 cfg_info_group0[] = CTP_CFG_GROUP0;
+	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+
+	u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1,
+			       cfg_info_group2, cfg_info_group3,
+			       cfg_info_group4, cfg_info_group5 };
+	u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0),
+			      CFG_GROUP_LEN(cfg_info_group1),
+			      CFG_GROUP_LEN(cfg_info_group2),
+			      CFG_GROUP_LEN(cfg_info_group3),
+			      CFG_GROUP_LEN(cfg_info_group4),
+			      CFG_GROUP_LEN(cfg_info_group5)};
+
+	dev_dbg(&ts->client->dev,
+		"Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+		cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
+		cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
+#endif
+
+	/* read sensor id */
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+				     &sensor_id, 1);
+	if (ret != SUCCESS || sensor_id >= 0x06) {
+		dev_err(&ts->client->dev,
+			"Failed get valid sensor_id(0x%02X), No Config Sent\n",
+			sensor_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id);
+	/* parse config data */
+#ifdef CONFIG_OF
+	dev_dbg(&ts->client->dev, "Get config data from device tree\n");
+	ret = gtp_parse_dt_cfg(&ts->client->dev,
+			       &cfg->data[GTP_ADDR_LENGTH],
+			       &cfg->length, sensor_id);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+			"Failed to parse config data form device tree\n");
+		cfg->length = 0;
+		return -EPERM;
+	}
+#else
+	dev_dbg(&ts->client->dev, "Get config data from header file\n");
+	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+	    (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+	    (!cfg_info_len[5])) {
+		sensor_id = 0;
+	}
+	cfg->length = cfg_info_len[sensor_id];
+	memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+	memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+	       cfg->length);
+#endif
+
+	if (cfg->length < GTP_CONFIG_MIN_LENGTH) {
+		dev_err(&ts->client->dev,
+			"Failed get valid config data with sensor id %d\n",
+			sensor_id);
+		cfg->length = 0;
+		return -EPERM;
+	}
+
+	dev_info(&ts->client->dev, "Config group%d used,length: %d\n",
+		 sensor_id, cfg->length);
+
+	return 0;
+}
+
+/*******************************************************
+ * Function:
+ *	Get valid config data from dts or .h file.
+ *	Read firmware version info and judge firmware
+ *	working state
+ * Input:
+ *	ts: goodix private data
+ * Output:
+ *	Executive outcomes.
+ *		0: succeed, otherwise: failed
+ *******************************************************/
+static s32 gtp_init_panel(struct goodix_ts_data *ts)
+{
+	s32 ret = -1;
+	u8 opr_buf[16] = {0};
+	u8 drv_cfg_version = 0;
+	u8 flash_cfg_version = 0;
+	struct goodix_config_data *cfg = &ts->pdata->config;
+
+	if (!ts->pdata->driver_send_cfg) {
+		dev_info(&ts->client->dev, "Driver set not send config\n");
+		cfg->length = GTP_CONFIG_MAX_LENGTH;
+		ret = gtp_i2c_read(ts->client,
+				   cfg->data, cfg->length +
+				   GTP_ADDR_LENGTH);
+		if (ret < 0)
+			dev_err(&ts->client->dev, "Read origin Config Failed\n");
+
+		return 0;
+	}
+
+	gtp_find_valid_cfg_data(ts);
+
+	/* check firmware */
+	ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+	if (ret == SUCCESS) {
+		if (opr_buf[0] != 0xBE) {
+			set_bit(FW_ERROR, &ts->flags);
+			dev_err(&ts->client->dev,
+				"Firmware error, no config sent!\n");
+			return -EINVAL;
+		}
+	}
+
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+				     &opr_buf[0], 1);
+	if (ret == SUCCESS) {
+		dev_dbg(&ts->client->dev,
+			"Config Version: %d; IC Config Version: %d\n",
+			cfg->data[GTP_ADDR_LENGTH], opr_buf[0]);
+		flash_cfg_version = opr_buf[0];
+		drv_cfg_version = cfg->data[GTP_ADDR_LENGTH];
+
+		if (flash_cfg_version < 120 &&
+		    flash_cfg_version > drv_cfg_version)
+			cfg->data[GTP_ADDR_LENGTH] = 0x00;
+	} else {
+		dev_err(&ts->client->dev,
+			"Failed to get ic config version!No config sent\n");
+		return -EPERM;
+	}
+
+	ret = gtp_send_cfg(ts->client);
+	if (ret < 0)
+		dev_err(&ts->client->dev, "Send config error\n");
+	else
+		usleep_range(10000, 11000); /* 10 ms */
+
+	/* restore config version */
+	cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version;
+
+	return 0;
+}
+
+static ssize_t gtp_config_read_proc(struct file *file, char __user *page,
+				    size_t size, loff_t *ppos)
+{
+	int i, ret;
+	char *ptr;
+	size_t data_len = 0;
+	char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = {
+					(u8)(GTP_REG_CONFIG_DATA >> 8),
+					(u8)GTP_REG_CONFIG_DATA };
+	struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+	struct goodix_config_data *cfg = &ts->pdata->config;
+
+	ptr = kzalloc(4096, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	data_len += snprintf(ptr + data_len, 4096 - data_len,
+			     "====init value====\n");
+	for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) {
+		data_len += snprintf(ptr + data_len, 4096 - data_len,
+				     "0x%02X ", cfg->data[i + 2]);
+
+		if (i % 8 == 7)
+			data_len += snprintf(ptr + data_len,
+					     4096 - data_len, "\n");
+	}
+	data_len += snprintf(ptr + data_len, 4096 - data_len, "\n");
+
+	data_len += snprintf(ptr + data_len, 4096 - data_len,
+			     "====real value====\n");
+	ret = gtp_i2c_read(i2c_connect_client, temp_data,
+			   GTP_CONFIG_MAX_LENGTH + 2);
+	if (ret < 0) {
+		data_len += snprintf(ptr + data_len, 4096 - data_len,
+				     "Failed read real config data\n");
+	} else {
+		for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) {
+			data_len += snprintf(ptr + data_len, 4096 - data_len,
+					     "0x%02X ", temp_data[i + 2]);
+
+			if (i % 8 == 7)
+				data_len += snprintf(ptr + data_len,
+						     4096 - data_len, "\n");
+		}
+	}
+
+	data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len);
+	kfree(ptr);
+	ptr = NULL;
+	return data_len;
+}
+
+int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf)
+{
+	int i, ret;
+	int cfg_len = 0;
+	long val;
+	char temp_buf[5];
+
+	for (i = 0; i < src_len;) {
+		if (src_buf[i] == ' ' || src_buf[i] == '\r' ||
+		    src_buf[i] == '\n') {
+			i++;
+			continue;
+		}
+
+		temp_buf[0] = src_buf[i];
+		temp_buf[1] = src_buf[i + 1];
+		temp_buf[2] = src_buf[i + 2];
+		temp_buf[3] = src_buf[i + 3];
+		temp_buf[4] = '\0';
+		if (!kstrtol(temp_buf, 16, &val)) {
+			if (cfg_len < GTP_CONFIG_MAX_LENGTH) {
+				dst_buf[cfg_len++] = val & 0xFF;
+				i += 5;
+			} else {
+				ret = -2;
+				goto convert_failed;
+			}
+		} else {
+			ret = -3;
+			goto convert_failed;
+		}
+	}
+	return cfg_len;
+
+convert_failed:
+	return ret;
+}
+
+static ssize_t gtp_config_write_proc(struct file *filp,
+				     const char __user *buffer,
+				     size_t count, loff_t *off)
+{
+	u8 *temp_buf;
+	u8 *file_config;
+	int file_cfg_len;
+	s32 ret = 0, i;
+	struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+	dev_dbg(&ts->client->dev, "write count %zu\n", count);
+
+	if (count > PAGE_SIZE) {
+		dev_err(&ts->client->dev, "config to long %zu\n", count);
+		return -EFAULT;
+	}
+
+	temp_buf = kzalloc(count, GFP_KERNEL);
+	if (!temp_buf)
+		return -ENOMEM;
+
+	file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+			      GFP_KERNEL);
+	if (!file_config) {
+		kfree(temp_buf);
+		return -ENOMEM;
+	}
+	file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+	file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+
+	if (copy_from_user(temp_buf, buffer, count)) {
+		dev_err(&ts->client->dev, "Failed copy from user\n");
+		ret = -EFAULT;
+		goto send_cfg_err;
+	}
+
+	file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count,
+					  &file_config[GTP_ADDR_LENGTH]);
+	if (file_cfg_len < 0) {
+		dev_err(&ts->client->dev, "failed covert ascii to hex");
+		ret = -EFAULT;
+		goto send_cfg_err;
+	}
+
+	GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len);
+
+	i = 0;
+	while (i++ < 5) {
+		ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2);
+		if (ret > 0) {
+			dev_info(&ts->client->dev, "Send config SUCCESS.");
+			break;
+		}
+		dev_err(&ts->client->dev, "Send config i2c error.");
+		ret = -EFAULT;
+		goto send_cfg_err;
+	}
+
+	ret = count;
+send_cfg_err:
+	kfree(temp_buf);
+	kfree(file_config);
+	return ret;
+}
+
+static const struct file_operations config_proc_ops = {
+	.owner = THIS_MODULE,
+	.read = gtp_config_read_proc,
+	.write = gtp_config_write_proc,
+};
+
+static ssize_t gtp_workmode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	size_t data_len = 0;
+	struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+	if (test_bit(DOZE_MODE, &data->flags))
+		data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+				     "doze_mode");
+	else if (test_bit(SLEEP_MODE, &data->flags))
+		data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+				     "sleep_mode");
+	else
+		data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+				     "normal_mode");
+
+	return data_len;
+}
+static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+#define FW_NAME_MAX_LEN	80
+static ssize_t gtp_dofwupdate_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	char update_file_name[FW_NAME_MAX_LEN];
+	int retval;
+
+	if (count > FW_NAME_MAX_LEN) {
+		dev_info(&ts->client->dev, "FW filename is too long\n");
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	strlcpy(update_file_name, buf, count);
+
+	ts->force_update = true;
+	retval = gup_update_proc(update_file_name);
+	if (retval == FAIL)
+		dev_err(&ts->client->dev, "Fail to update GTP firmware.\n");
+	else
+		dev_info(&ts->client->dev, "Update success\n");
+
+	return count;
+
+exit:
+	return retval;
+}
+static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store);
+#endif
+
+static ssize_t gtp_productinfo_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct goodix_ts_data *data = dev_get_drvdata(dev);
+	struct goodix_fw_info *fw_info = &data->fw_info;
+
+	return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n",
+			 fw_info->pid, fw_info->version, fw_info->sensor_id);
+}
+static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL);
+
+static ssize_t gtp_drv_irq_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	unsigned long value = 0;
+	int err = 0;
+	struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+	err = kstrtoul(buf, 10, &value);
+	if (err < 0) {
+		dev_err(dev, "Failed to convert value\n");
+		return -EINVAL;
+	}
+
+	switch (value) {
+	case 0:
+		/* Disable irq */
+		gtp_work_control_enable(data, false);
+		break;
+	case 1:
+		/* Enable irq */
+		gtp_work_control_enable(data, true);
+		break;
+	default:
+		dev_err(dev, "Invalid value\n");
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static ssize_t gtp_drv_irq_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+			 test_bit(REPORT_THREAD_ENABLED, &data->flags)
+			 ? "enabled" : "disabled");
+}
+static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store);
+
+static ssize_t gtp_reset_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+	if ('1' != buf[0]) {
+		dev_err(dev, "Invalid argument for reset\n");
+		return -EINVAL;
+	}
+
+	gtp_reset_guitar(data->client, 20);
+
+	return count;
+}
+static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store);
+
+static struct attribute *gtp_attrs[] = {
+	&dev_attr_workmode.attr,
+	&dev_attr_productinfo.attr,
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+	&dev_attr_dofwupdate.attr,
+#endif
+
+	&dev_attr_drv_irq.attr,
+	&dev_attr_reset.attr,
+	NULL
+};
+
+static const struct attribute_group gtp_attr_group = {
+	.attrs = gtp_attrs,
+};
+
+static int gtp_create_file(struct goodix_ts_data *ts)
+{
+	int ret;
+	struct i2c_client *client = ts->client;
+
+	/*  Create proc file system */
+	gtp_config_proc = NULL;
+	gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664,
+				      NULL, &config_proc_ops);
+	if (!gtp_config_proc)
+		dev_err(&client->dev, "create_proc_entry %s failed\n",
+			GT91XX_CONFIG_PROC_FILE);
+	else
+		dev_info(&client->dev, "create proc entry %s success\n",
+			 GT91XX_CONFIG_PROC_FILE);
+
+	ret = sysfs_create_group(&client->dev.kobj, &gtp_attr_group);
+	if (ret) {
+		dev_err(&client->dev, "Failure create sysfs group %d\n", ret);
+		/*TODO: debug change */
+		goto exit_free_config_proc;
+	}
+	return 0;
+
+exit_free_config_proc:
+	remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
+	return -ENODEV;
+}
+
+s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info)
+{
+	s32 ret = -1;
+	u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+
+	ret = gtp_i2c_read(client, buf, sizeof(buf));
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed read fw_info\n");
+		return ret;
+	}
+
+	/* product id */
+	memset(fw_info, 0, sizeof(*fw_info));
+
+	if (buf[5] == 0x00) {
+		memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3);
+		dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n",
+			 buf[2], buf[3], buf[4], buf[7], buf[6]);
+	} else {
+		memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4);
+		dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n",
+			 buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
+	}
+
+	/* current firmware version */
+	fw_info->version = (buf[7] << 8) | buf[6];
+
+	/* read sensor id */
+	fw_info->sensor_id = 0xff;
+	ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID,
+				     &fw_info->sensor_id, 1);
+	if (ret != SUCCESS || fw_info->sensor_id >= 0x06) {
+		dev_err(&client->dev,
+			"Failed get valid sensor_id(0x%02X), No Config Sent\n",
+			fw_info->sensor_id);
+
+		fw_info->sensor_id = 0xff;
+	}
+
+	return ret;
+}
+
+static int gtp_i2c_test(struct i2c_client *client)
+{
+	u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+	u8 retry = 0;
+	int ret = -1;
+
+	while (retry++ < 3) {
+		ret = gtp_i2c_read(client, test, 3);
+		if (ret == 2)
+			return 0;
+
+		dev_err(&client->dev, "GTP i2c test failed time %d\n", retry);
+		usleep_range(10000, 11000); /* 10 ms */
+	}
+
+	return -EAGAIN;
+}
+
+static int gtp_pinctrl_init(struct goodix_ts_data *ts)
+{
+	struct goodix_pinctrl *pinctrl = &ts->pinctrl;
+
+	pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev);
+	if (IS_ERR_OR_NULL(pinctrl->pinctrl)) {
+		dev_info(&ts->client->dev, "No pinctrl found\n");
+		pinctrl->pinctrl = NULL;
+		return 0;
+	}
+
+	/* INT pinctrl */
+	pinctrl->int_default = pinctrl_lookup_state(pinctrl->pinctrl,
+						    "gdix_ts_int_default");
+	if (IS_ERR_OR_NULL(pinctrl->int_default)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:INT default state\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
+						     "gdix_ts_int_output_high");
+	if (IS_ERR_OR_NULL(pinctrl->int_out_high)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:INT output_high\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
+						    "gdix_ts_int_output_low");
+	if (IS_ERR_OR_NULL(pinctrl->int_out_low)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:INT output_low\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl,
+						  "gdix_ts_int_input");
+	if (IS_ERR_OR_NULL(pinctrl->int_input)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:int-input\n");
+		goto exit_pinctrl_init;
+	}
+	dev_info(&ts->client->dev, "Success init INT pinctrl\n");
+
+	/* RST pinctrl */
+	pinctrl->rst_default = pinctrl_lookup_state(pinctrl->pinctrl,
+						    "gdix_ts_rst_default");
+	if (IS_ERR_OR_NULL(pinctrl->rst_default)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:RST default state\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->rst_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
+						     "gdix_ts_rst_output_high");
+	if (IS_ERR_OR_NULL(pinctrl->rst_out_high)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:RST output_high\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->rst_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
+						    "gdix_ts_rst_output_low");
+	if (IS_ERR_OR_NULL(pinctrl->rst_out_low)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:RST output_low\n");
+		goto exit_pinctrl_init;
+	}
+
+	pinctrl->rst_input = pinctrl_lookup_state(pinctrl->pinctrl,
+						  "gdix_ts_rst_input");
+	if (IS_ERR_OR_NULL(pinctrl->rst_input)) {
+		dev_info(&ts->client->dev,
+			 "Failed get pinctrl state:rst-input\n");
+		goto exit_pinctrl_init;
+	}
+	dev_info(&ts->client->dev, "Success init RST pinctrl\n");
+
+	return 0;
+exit_pinctrl_init:
+	devm_pinctrl_put(pinctrl->pinctrl);
+	pinctrl->pinctrl = NULL;
+	pinctrl->int_default = NULL;
+	pinctrl->int_out_high = NULL;
+	pinctrl->int_out_low = NULL;
+	pinctrl->int_input = NULL;
+	pinctrl->rst_default = NULL;
+	pinctrl->rst_out_high = NULL;
+	pinctrl->rst_out_low = NULL;
+	pinctrl->rst_input = NULL;
+	return -EINVAL;
+}
+
+static void gtp_pinctrl_deinit(struct goodix_ts_data *ts)
+{
+	if (ts->pinctrl.pinctrl)
+		devm_pinctrl_put(ts->pinctrl.pinctrl);
+}
+
+static int gtp_request_io_port(struct goodix_ts_data *ts)
+{
+	int ret = 0;
+
+	if (gpio_is_valid(ts->pdata->irq_gpio)) {
+		ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int");
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Failed to request GPIO:%d, ERRNO:%d\n",
+				(s32)ts->pdata->irq_gpio, ret);
+			return -ENODEV;
+		}
+
+		gpio_direction_input(ts->pdata->irq_gpio);
+		dev_info(&ts->client->dev, "Success request irq-gpio\n");
+	}
+
+	if (gpio_is_valid(ts->pdata->rst_gpio)) {
+		ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst");
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Failed to request GPIO:%d, ERRNO:%d\n",
+				(s32)ts->pdata->rst_gpio, ret);
+
+			if (gpio_is_valid(ts->pdata->irq_gpio))
+				gpio_free(ts->pdata->irq_gpio);
+
+			return -ENODEV;
+		}
+
+		gpio_direction_input(ts->pdata->rst_gpio);
+		dev_info(&ts->client->dev,  "Success request rst-gpio\n");
+	}
+
+	return 0;
+}
+
+/*******************************************************
+ * Function:
+ *	Request interrupt if define irq pin, else use hrtimer
+ *	as interrupt source
+ * Input:
+ *	ts: private data.
+ * Output:
+ *	Executive outcomes.
+ *		0: succeed, -1: failed.
+ *******************************************************/
+static int gtp_request_irq(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+
+	/* use irq */
+	if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) {
+		if (gpio_is_valid(ts->pdata->irq_gpio))
+			ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio);
+
+		dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n",
+			 ts->client->irq, ts->pdata->irq_flags);
+		ret = request_threaded_irq(ts->client->irq, NULL,
+				gtp_irq_handler,
+				ts->pdata->irq_flags | IRQF_ONESHOT,
+				ts->client->name,
+				ts);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Failed to request irq %d\n", ts->client->irq);
+			return ret;
+		}
+	} else { /* use hrtimer */
+		dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n");
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ts->timer.function = gtp_timer_handler;
+		hrtimer_start(&ts->timer,
+			      ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+			      HRTIMER_MODE_REL);
+		set_bit(HRTIMER_USED, &ts->flags);
+		ret = 0;
+	}
+	return ret;
+}
+
+static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+	s8 ret = -1;
+	u8 index = 0;
+
+	ts->input_dev = input_allocate_device();
+	if (!ts->input_dev) {
+		dev_err(&ts->client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY)
+		| BIT_MASK(EV_ABS);
+	if (!ts->pdata->type_a_report) {
+		input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT);
+		dev_info(&ts->client->dev, "Use slot report protocol\n");
+	} else {
+		__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+		__set_bit(BTN_TOUCH, ts->input_dev->keybit);
+		dev_info(&ts->client->dev, "Use type A report protocol\n");
+	}
+
+	input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1);
+	input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2);
+
+	/* touch key register */
+	for (index = 0; index < ts->pdata->key_nums; index++)
+		input_set_capability(ts->input_dev, EV_KEY,
+				     ts->pdata->key_map[index]);
+
+	if (ts->pdata->slide_wakeup)
+		input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+
+	if (ts->pdata->swap_x2y)
+		GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y);
+
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
+			     ts->pdata->abs_size_x, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
+			     ts->pdata->abs_size_y, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+			     ts->pdata->max_touch_width, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0,
+			     ts->pdata->max_touch_pressure, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
+			     ts->pdata->max_touch_id, 0, 0);
+	if (!ts->pdata->type_a_report) {
+		input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
+				     0, MT_TOOL_MAX, 0, 0);
+	} else {
+		__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+		__set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
+	}
+
+	ts->input_dev->name = goodix_ts_name;
+	ts->input_dev->phys = goodix_input_phys;
+	ts->input_dev->id.bustype = BUS_I2C;
+	ts->input_dev->id.vendor = 0xDEAD;
+	ts->input_dev->id.product = 0xBEEF;
+	ts->input_dev->id.version = 10427;
+
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		dev_err(&ts->client->dev, "Register %s input device failed\n",
+			ts->input_dev->name);
+		input_free_device(ts->input_dev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Devices Tree support
+ */
+#ifdef CONFIG_OF
+static void gtp_parse_dt_coords(struct device *dev,
+				struct goodix_ts_platform_data *pdata)
+{
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	ret = of_property_read_u32(np, "touchscreen-max-id",
+				   &pdata->max_touch_id);
+	if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) {
+		dev_info(dev, "Unset touchscreen-max-id, use default\n");
+		pdata->max_touch_id = GTP_MAX_TOUCH_ID;
+	}
+
+	ret = of_property_read_u32(np, "touchscreen-size-x",
+				   &pdata->abs_size_x);
+	if (ret) {
+		dev_info(dev, "Unset touchscreen-size-x, use default\n");
+		pdata->abs_size_x = GTP_DEFAULT_MAX_X;
+	}
+
+	ret = of_property_read_u32(np, "touchscreen-size-y",
+				   &pdata->abs_size_y);
+	if (ret) {
+		dev_info(dev, "Unset touchscreen-size-y, use default\n");
+		pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
+	}
+
+	ret = of_property_read_u32(np, "touchscreen-max-w",
+				   &pdata->max_touch_width);
+	if (ret) {
+		dev_info(dev, "Unset touchscreen-max-w, use default\n");
+		pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
+	}
+
+	ret = of_property_read_u32(np, "touchscreen-max-p",
+				   &pdata->max_touch_pressure);
+	if (ret) {
+		dev_info(dev, "Unset touchscreen-max-p, use default\n");
+		pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
+	}
+	dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n",
+		 pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y,
+		 pdata->max_touch_width, pdata->max_touch_pressure);
+}
+
+static int gtp_parse_dt(struct device *dev,
+			struct goodix_ts_platform_data *pdata)
+{
+	int ret;
+	u32  key_nums;
+	struct property *prop;
+	u32 key_map[MAX_KEY_NUMS];
+	struct device_node *np = dev->of_node;
+
+	gtp_parse_dt_coords(dev, pdata);
+
+	ret = of_property_read_u32(np, "irq-flags",
+				   &pdata->irq_flags);
+	if (ret) {
+		dev_info(dev,
+			 "Failed get int-trigger-type from dts,set default\n");
+		pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER;
+	}
+	of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync);
+	if (pdata->int_sync)
+		dev_info(dev, "int-sync enabled\n");
+
+	of_property_read_u32(np, "goodix,driver-send-cfg",
+			     &pdata->driver_send_cfg);
+	if (pdata->driver_send_cfg)
+		dev_info(dev, "driver-send-cfg enabled\n");
+
+	of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y);
+	if (pdata->swap_x2y)
+		dev_info(dev, "swap-x2y enabled\n");
+
+	of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup);
+	if (pdata->slide_wakeup)
+		dev_info(dev, "slide-wakeup enabled\n");
+
+	of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update);
+	if (pdata->auto_update)
+		dev_info(dev, "auto-update enabled\n");
+
+	of_property_read_u32(np, "goodix,auto-update-cfg",
+			     &pdata->auto_update_cfg);
+	if (pdata->auto_update_cfg)
+		dev_info(dev, "auto-update-cfg enabled\n");
+
+	of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect);
+	if (pdata->esd_protect)
+		dev_info(dev, "esd-protect enabled\n");
+
+	of_property_read_u32(np, "goodix,type-a-report",
+			     &pdata->type_a_report);
+	if (pdata->type_a_report)
+		dev_info(dev, "type-a-report enabled\n");
+
+	of_property_read_u32(np, "goodix,resume-in-workqueue",
+			     &pdata->resume_in_workqueue);
+	if (pdata->resume_in_workqueue)
+		dev_info(dev, "resume-in-workqueue enabled\n");
+
+	of_property_read_u32(np, "goodix,power-off-sleep",
+			     &pdata->power_off_sleep);
+	if (pdata->power_off_sleep)
+		dev_info(dev, "power-off-sleep enabled\n");
+
+	of_property_read_u32(np, "goodix,pen-suppress-finger",
+			     &pdata->pen_suppress_finger);
+	if (pdata->pen_suppress_finger)
+		dev_info(dev, "pen-suppress-finger enabled\n");
+
+	prop = of_find_property(np, "touchscreen-key-map", NULL);
+	if (prop) {
+		key_nums = prop->length / sizeof(key_map[0]);
+		key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums;
+
+		dev_dbg(dev, "key nums %d\n", key_nums);
+		ret = of_property_read_u32_array(np,
+				"touchscreen-key-map", key_map,
+				key_nums);
+		if (ret) {
+			dev_err(dev, "Unable to read key codes\n");
+			pdata->key_nums = 0;
+			memset(pdata->key_map, 0,
+			       MAX_KEY_NUMS * sizeof(pdata->key_map[0]));
+		}
+		pdata->key_nums = key_nums;
+		memcpy(pdata->key_map, key_map,
+		       key_nums * sizeof(pdata->key_map[0]));
+		dev_info(dev, "key-map is [%x %x %x %x]\n",
+			 pdata->key_map[0], pdata->key_map[1],
+			 pdata->key_map[2], pdata->key_map[3]);
+	}
+
+	pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0);
+	if (!gpio_is_valid(pdata->irq_gpio))
+		dev_err(dev, "No valid irq gpio");
+
+	pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+	if (!gpio_is_valid(pdata->rst_gpio))
+		dev_err(dev, "No valid rst gpio");
+
+	return 0;
+}
+
+/*******************************************************
+ * Function:
+ *	parse config data from devices tree.
+ * Input:
+ *	dev: device that this driver attached.
+ *	cfg: pointer of the config array.
+ *	cfg_len: pointer of the config length.
+ *	sid: sensor id.
+ * Output:
+ *	Executive outcomes.
+ *		0-succeed, -1-faileds.
+ *******************************************************/
+int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid)
+{
+	struct device_node *np = dev->of_node;
+	struct property *prop;
+	char cfg_name[18];
+	int ret;
+
+	snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid);
+	prop = of_find_property(np, cfg_name, cfg_len);
+	if (!prop || !prop->value || *cfg_len == 0 ||
+	    *cfg_len > GTP_CONFIG_MAX_LENGTH) {
+		*cfg_len = 0;
+		ret = -EPERM;/* failed */
+	} else {
+		memcpy(cfg, prop->value, *cfg_len);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+#endif
+
+static int gtp_power_on(struct goodix_ts_data *ts)
+{
+	int ret = 0;
+
+	if (ts->vdd_ana) {
+		ret = regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
+					    GOODIX_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vdd ret=%d\n",
+				ret);
+			goto err_set_vtg_vdd_ana;
+		}
+		ret = regulator_enable(ts->vdd_ana);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vdd enable failed ret=%d\n",
+				ret);
+			goto err_enable_vdd_ana;
+		}
+	}
+
+	if (ts->vcc_i2c) {
+		ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+					    GOODIX_I2C_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vcc_i2c ret=%d\n",
+				ret);
+			goto err_set_vtg_vcc_i2c;
+		}
+		ret = regulator_enable(ts->vcc_i2c);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c enable failed ret=%d\n",
+				ret);
+			goto err_enable_vcc_i2c;
+		}
+	}
+	clear_bit(POWER_OFF_MODE, &ts->flags);
+	return 0;
+
+err_enable_vcc_i2c:
+	if (ts->vcc_i2c)
+		regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+	if (ts->vdd_ana)
+		regulator_disable(ts->vdd_ana);
+err_enable_vdd_ana:
+	if (ts->vdd_ana)
+		regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd_ana:
+	set_bit(POWER_OFF_MODE, &ts->flags);
+	return ret;
+}
+
+static int gtp_power_off(struct goodix_ts_data *ts)
+{
+	int ret = 0;
+
+	if (ts->vcc_i2c) {
+		set_bit(POWER_OFF_MODE, &ts->flags);
+		ret = regulator_set_voltage(ts->vcc_i2c, 0,
+					    GOODIX_I2C_VTG_MAX_UV);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c set_vtg failed ret=%d\n",
+				ret);
+			goto err_set_vtg_vcc_i2c;
+		}
+		ret = regulator_disable(ts->vcc_i2c);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c disable failed ret=%d\n",
+				ret);
+			goto err_disable_vcc_i2c;
+		}
+		dev_info(&ts->client->dev,
+			 "Regulator vcc_i2c disabled\n");
+	}
+
+	if (ts->vdd_ana) {
+		set_bit(POWER_OFF_MODE, &ts->flags);
+		ret = regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+					"Regulator vdd set_vtg failed ret=%d\n",
+					ret);
+			goto err_set_vtg_vdd_ana;
+		}
+		ret = regulator_disable(ts->vdd_ana);
+		if (ret) {
+			dev_err(&ts->client->dev,
+					"Regulator vdd disable failed ret=%d\n",
+					ret);
+			goto err_disable_vdd_ana;
+		}
+		dev_info(&ts->client->dev,
+			 "Regulator vdd_ana disabled\n");
+	}
+	return ret;
+
+err_disable_vdd_ana:
+	if (ts->vdd_ana)
+		regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
+				      GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd_ana:
+	if (ts->vcc_i2c)
+		ret = regulator_enable(ts->vcc_i2c);
+err_disable_vcc_i2c:
+	if (ts->vcc_i2c)
+		regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+				      GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+	clear_bit(POWER_OFF_MODE, &ts->flags);
+	return ret;
+}
+
+static int gtp_power_init(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana");
+	if (IS_ERR(ts->vdd_ana)) {
+		ts->vdd_ana = NULL;
+		ret = PTR_ERR(ts->vdd_ana);
+		dev_info(&ts->client->dev,
+			 "Regulator get failed vdd ret=%d\n", ret);
+	}
+
+	ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c");
+	if (IS_ERR(ts->vcc_i2c)) {
+		ts->vcc_i2c = NULL;
+		ret = PTR_ERR(ts->vcc_i2c);
+		dev_info(&ts->client->dev,
+			 "Regulator get failed vcc_i2c ret=%d\n", ret);
+	}
+	return 0;
+}
+
+static int gtp_power_deinit(struct goodix_ts_data *ts)
+{
+	if (ts->vdd_ana)
+		regulator_put(ts->vdd_ana);
+	if (ts->vcc_i2c)
+		regulator_put(ts->vcc_i2c);
+
+	return 0;
+}
+
+static void gtp_shutdown(struct i2c_client *client)
+{
+	struct goodix_ts_data *data = i2c_get_clientdata(client);
+
+	if (!data->init_done)
+		return;
+
+	gtp_work_control_enable(data, false);
+	gtp_power_off(data);
+}
+
+static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = -1;
+	struct goodix_ts_data *ts;
+	struct goodix_ts_platform_data *pdata;
+
+	/* do NOT remove these logs */
+	dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION);
+	dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
+
+	i2c_connect_client = client;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "Failed check I2C functionality");
+		return -ENODEV;
+	}
+
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		devm_kfree(&client->dev, ts);
+		return -EINVAL;
+	}
+
+	ts->init_done = false;
+
+#ifdef CONFIG_OF
+	if (client->dev.of_node) {
+		ret = gtp_parse_dt(&client->dev, pdata);
+		if (ret) {
+			dev_err(&client->dev, "Failed parse dts\n");
+			goto exit_free_client_data;
+		}
+	}
+#else
+	/* set parameters at here if you platform doesn't DTS */
+	pdata->rst_gpio = GTP_RST_PORT;
+	pdata->irq_gpio = GTP_INT_PORT;
+	pdata->slide_wakeup = false;
+	pdata->auto_update = true;
+	pdata->auto_update_cfg = false;
+	pdata->type_a_report = false;
+	pdata->esd_protect = false;
+	pdata->max_touch_id = GTP_MAX_TOUCH_ID;
+	pdata->abs_size_x = GTP_DEFAULT_MAX_X;
+	pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
+	pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
+	pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
+#endif
+
+	ts->client = client;
+	ts->pdata = pdata;
+
+	i2c_set_clientdata(client, ts);
+
+	ret = gtp_power_init(ts);
+	if (ret) {
+		dev_err(&client->dev, "Failed get regulator\n");
+		ret = -EINVAL;
+		goto exit_free_client_data;
+	}
+
+	ret = gtp_pinctrl_init(ts);
+	if (ret < 0) {
+		/* if define pinctrl must define the following state
+		 * to let int-pin work normally: default, int_output_high,
+		 * int_output_low, int_input
+		 */
+		dev_err(&client->dev, "Failed get wanted pinctrl state\n");
+		goto exit_deinit_power;
+	}
+
+	ret = gtp_request_io_port(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed request IO port\n");
+		goto exit_pinctrl;
+	}
+
+	/*wait for discharging power, which from i2c pull-up flow backward*/
+	gtp_rst_output(ts, 0);
+	msleep(DELAY_FOR_DISCHARGING);
+
+	ret = gtp_power_on(ts);
+	if (ret) {
+		dev_err(&client->dev, "Failed power on device\n");
+		ret = -EINVAL;
+		goto exit_free_io_port;
+	}
+
+	gtp_reset_guitar(ts->client, 20);
+
+	ret = gtp_i2c_test(client);
+	if (ret) {
+		dev_err(&client->dev, "Failed communicate with IC use I2C\n");
+		goto exit_power_off;
+	}
+
+	dev_info(&client->dev, "I2C Addr is %x\n", client->addr);
+
+	ret = gtp_get_fw_info(client, &ts->fw_info);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed read FW version\n");
+		goto exit_power_off;
+	}
+
+	pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8;
+	pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff;
+	ret = gtp_init_panel(ts);
+	if (ret < 0)
+		dev_info(&client->dev, "Panel un-initialize\n");
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+	if (ts->pdata->auto_update) {
+		ret = gup_init_update_proc(ts);
+		if (ret < 0)
+			dev_err(&client->dev, "Failed create update thread\n");
+	}
+#endif
+
+	ret = gtp_request_input_dev(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed request input device\n");
+		goto exit_power_off;
+	}
+
+	mutex_init(&ts->lock);
+
+	ret = gtp_request_irq(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed create work thread");
+		goto exit_unreg_input_dev;
+	}
+	gtp_work_control_enable(ts, false);
+	if (ts->pdata->slide_wakeup) {
+		dev_info(&client->dev, "slide wakeup enabled\n");
+		ret = enable_irq_wake(client->irq);
+		if (ret < 0)
+			dev_err(&client->dev, "Failed set irq wake\n");
+	}
+
+	gtp_register_powermanager(ts);
+
+	ret = gtp_create_file(ts);
+	if (ret) {
+		dev_info(&client->dev, "Failed create attributes file");
+		goto exit_powermanager;
+	}
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+	init_wr_node(client);/*TODO judge return value */
+#endif
+
+	gtp_esd_init(ts);
+	gtp_esd_on(ts);
+	/* probe init finished */
+	ts->init_done = true;
+	gtp_work_control_enable(ts, true);
+
+	return 0;
+
+exit_powermanager:
+	gtp_unregister_powermanager(ts);
+exit_unreg_input_dev:
+	input_unregister_device(ts->input_dev);
+exit_power_off:
+	gtp_power_off(ts);
+exit_free_io_port:
+	if (gpio_is_valid(ts->pdata->rst_gpio))
+		gpio_free(ts->pdata->rst_gpio);
+	if (gpio_is_valid(ts->pdata->irq_gpio))
+		gpio_free(ts->pdata->irq_gpio);
+exit_pinctrl:
+	gtp_pinctrl_deinit(ts);
+exit_deinit_power:
+	gtp_power_deinit(ts);
+exit_free_client_data:
+	devm_kfree(&client->dev, pdata);
+	devm_kfree(&client->dev, ts);
+	i2c_set_clientdata(client, NULL);
+
+	return ret;
+}
+
+static int gtp_drv_remove(struct i2c_client *client)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	gtp_work_control_enable(ts, false);
+	gtp_unregister_powermanager(ts);
+
+	remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
+
+	sysfs_remove_group(&client->dev.kobj, &gtp_attr_group);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+	uninit_wr_node();
+#endif
+
+	if (ts->pdata->esd_protect)
+		gtp_esd_off(ts);
+
+	/* TODO: how to judge a irq numbers validity */
+	if (ts->client->irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+
+	if (gpio_is_valid(ts->pdata->rst_gpio))
+		gpio_free(ts->pdata->rst_gpio);
+
+	if (gpio_is_valid(ts->pdata->irq_gpio))
+		gpio_free(ts->pdata->irq_gpio);
+
+	gtp_power_off(ts);
+	gtp_power_deinit(ts);
+	gtp_pinctrl_deinit(ts);
+	dev_info(&client->dev, "goodix ts driver removed");
+	i2c_set_clientdata(client, NULL);
+	input_unregister_device(ts->input_dev);
+	mutex_destroy(&ts->lock);
+
+	devm_kfree(&client->dev, ts->pdata);
+	devm_kfree(&client->dev, ts);
+
+	return 0;
+}
+
+static void gtp_suspend(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+
+	if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+		dev_warn(&ts->client->dev,
+			 "Fw upgrade in progress, can't go to suspend\n");
+		return;
+	}
+
+	if (test_and_set_bit(SLEEP_MODE, &ts->flags)) {
+		dev_info(&ts->client->dev, "Already in suspend state\n");
+		return;
+	}
+
+	dev_dbg(&ts->client->dev, "Try enter suspend mode\n");
+
+	gtp_esd_off(ts);
+	gtp_work_control_enable(ts, false);
+	if (ts->pdata->slide_wakeup) {
+		ret = gtp_enter_doze(ts);
+		gtp_work_control_enable(ts, true);
+	} else if (ts->pdata->power_off_sleep) {
+		/*TODO: power off routine */
+		gtp_power_off(ts);
+		ret = SUCCESS;
+	} else {
+		ret = gtp_enter_sleep(ts);
+	}
+
+	if (ret < 0)
+		dev_err(&ts->client->dev, "Failed enter suspend\n");
+
+	/*  to avoid waking up while not sleeping */
+	/*	delay 48 + 10ms to ensure reliability */
+	msleep(GTP_58_DLY_MS);
+}
+
+static int gtp_gesture_wakeup(struct goodix_ts_data *ts)
+{
+	int ret;
+	int retry = 10;
+
+	do {
+		gtp_reset_guitar(ts->client, 10);
+		ret = gtp_i2c_test(ts->client);
+		if (!ret)
+			break;
+	} while (--retry);
+
+	if (!retry)
+		ret = -EIO;
+
+	clear_bit(DOZE_MODE, &ts->flags);
+	return ret;
+}
+
+static void gtp_resume(struct goodix_ts_data *ts)
+{
+	int ret = 0;
+
+	if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+		dev_info(&ts->client->dev,
+			 "Fw upgrade in progress, can't do resume\n");
+		return;
+	}
+
+	if (!test_bit(SLEEP_MODE, &ts->flags)) {
+		dev_dbg(&ts->client->dev, "Already in awake state\n");
+		return;
+	}
+
+	dev_info(&ts->client->dev, "Try resume from sleep mode\n");
+
+	gtp_work_control_enable(ts, false);
+
+	if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
+		ret = gtp_gesture_wakeup(ts);
+		if (ret)
+			dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
+	} else if (ts->pdata->power_off_sleep) {
+		ret = gtp_power_on(ts);
+		if (ret) {
+			dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
+		} else {
+			gtp_reset_guitar(ts->client, 20);
+			ret = gtp_i2c_test(ts->client);
+			if (ret)
+				dev_warn(&ts->client->dev,
+					 "I2C communicate failed after power on\n");
+		}
+	} else {
+		ret = gtp_wakeup_sleep(ts);
+		if (ret)
+			dev_warn(&ts->client->dev,
+				 "Failed wakeup from sleep mode\n");
+	}
+
+	if (ret)
+		dev_warn(&ts->client->dev, "Later resume failed\n");
+	else
+		gtp_esd_on(ts);
+
+	clear_bit(SLEEP_MODE, &ts->flags);
+	gtp_work_control_enable(ts, true);
+}
+
+#if defined(CONFIG_FB)
+static void fb_notify_resume_work(struct work_struct *work)
+{
+	struct goodix_ts_data *ts =
+		container_of(work, struct goodix_ts_data, fb_notify_work);
+	dev_info(&ts->client->dev, "try resume in workqueue\n");
+	gtp_resume(ts);
+}
+
+/* frame buffer notifier block control the suspend/resume procedure */
+static int gtp_fb_notifier_callback(struct notifier_block *noti,
+				    unsigned long event, void *data)
+{
+	struct fb_event *ev_data = data;
+	struct goodix_ts_data *ts = container_of(noti,
+			struct goodix_ts_data, notifier);
+	int *blank;
+
+	if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) {
+		blank = ev_data->data;
+		if (*blank == FB_BLANK_UNBLANK ||
+		    *blank == FB_BLANK_NORMAL) {
+			dev_dbg(&ts->client->dev, "ts_resume");
+			if (ts->pdata->resume_in_workqueue)
+				schedule_work(&ts->fb_notify_work);
+			else
+				gtp_resume(ts);
+		} else if (*blank == FB_BLANK_POWERDOWN) {
+			dev_dbg(&ts->client->dev, "ts_suspend");
+			if (ts->pdata->resume_in_workqueue)
+				flush_work(&ts->fb_notify_work);
+			gtp_suspend(ts);
+		}
+	}
+
+	return 0;
+}
+
+#elif defined(CONFIG_PM)
+static int gtp_pm_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts) {
+		dev_dbg(&ts->client->dev, "Suspend by i2c pm.");
+		gtp_suspend(ts);
+	}
+
+	return 0;
+}
+
+static int gtp_pm_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts) {
+		dev_dbg(&ts->client->dev, "Resume by i2c pm.");
+		gtp_resume(ts);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops gtp_pm_ops = {
+	.suspend = gtp_pm_suspend,
+	.resume  = gtp_pm_resume,
+};
+
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void gtp_early_suspend(struct early_suspend *h)
+{
+	struct goodix_ts_data *ts = container_of(h,
+			struct goodix_ts_data, early_suspend);
+
+	if (ts) {
+		dev_dbg(&ts->client->dev, "Suspend by earlysuspend module.");
+		gtp_suspend(ts);
+	}
+}
+
+static void gtp_late_resume(struct early_suspend *h)
+{
+	struct goodix_ts_data *ts = container_of(h,
+			struct goodix_ts_data, early_suspend);
+
+	if (ts) {
+		dev_dbg(&ts->client->dev, "Resume by earlysuspend module.");
+		gtp_resume(ts);
+	}
+}
+#endif
+
+static int gtp_register_powermanager(struct goodix_ts_data *ts)
+{
+	int ret;
+#if defined(CONFIG_FB)
+	INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work);
+	ts->notifier.notifier_call = gtp_fb_notifier_callback;
+	ret = fb_register_client(&ts->notifier);
+	if (ret)
+		dev_err(&ts->client->dev,
+			"Unable to register fb_notifier: %d\n", ret);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = goodix_ts_early_suspend;
+	ts->early_suspend.resume = goodix_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+
+	return ret;
+}
+
+static int gtp_unregister_powermanager(struct goodix_ts_data *ts)
+{
+#if defined(CONFIG_FB)
+		fb_unregister_client(&ts->notifier);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+		unregister_early_suspend(&ts->early_suspend);
+#endif
+
+	return 0;
+}
+
+/*******************************************************
+ * Function:
+ *	Initialize external watchdog for esd protect
+ * Input:
+ *	client: i2c device.
+ * Output:
+ *	result of i2c write operation.
+ *		0: succeed, otherwise: failed
+ ********************************************************/
+static int gtp_init_ext_watchdog(struct i2c_client *client)
+{
+	int ret;
+	u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8),
+			     (u8)GTP_REG_ESD_CHECK,
+			     (u8)GTP_ESD_CHECK_VALUE };
+
+	dev_dbg(&client->dev, "[Esd]Init external watchdog\n");
+	ret = gtp_i2c_write(client, opr_buffer, 3);
+	if (ret == 1)
+		return 0;
+
+	dev_err(&client->dev, "Failed init ext watchdog\n");
+	return -EINVAL;
+}
+
+static void gtp_esd_check_func(struct work_struct *work)
+{
+	s32 i;
+	s32 ret = -1;
+	u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND };
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd,
+						    delayed_work);
+	struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data,
+						 ts_esd);
+
+	if (test_bit(SLEEP_MODE, &ts->flags) ||
+	    test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+		dev_dbg(&ts->client->dev,
+			"Esd cancled by power_suspend or fw_update!");
+		return;
+	}
+
+	if (ts_esd->esd_on == false)
+		return;
+
+	for (i = 0; i < 3; i++) {
+		ret = gtp_i2c_read(ts->client, esd_buf, 4);
+		if (ret < 0)
+			continue;
+
+		dev_dbg(&ts->client->dev,
+			"[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X",
+			esd_buf[2], esd_buf[3]);
+		if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
+		    esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
+			gtp_i2c_read(ts->client, esd_buf, 4);
+			if (ret < 0)
+				continue;
+
+			if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
+			    esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
+				i = 3;
+				break;
+			}
+		} else {
+			/* IC works normally, Write 0x8040 0xAA, feed the dog */
+			esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE;
+			gtp_i2c_write(ts->client, esd_buf, 3);
+			break;
+		}
+	}
+	if (i >= 3) {
+		dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n");
+		esd_buf[0] = 0x42;
+		esd_buf[1] = 0x26;
+		esd_buf[2] = 0x01;
+		esd_buf[3] = 0x01;
+		esd_buf[4] = 0x01;
+		gtp_i2c_write(ts->client, esd_buf, 5);
+		/* TODO: Is power off really need? */
+		msleep(GTP_50_DLY_MS);
+		gtp_power_off(ts);
+		msleep(GTP_20_DLY_MS);
+		gtp_power_on(ts);
+		msleep(GTP_20_DLY_MS);
+
+		gtp_reset_guitar(ts->client, 50);
+		msleep(GTP_50_DLY_MS);
+		gtp_send_cfg(ts->client);
+	}
+
+	if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) {
+		schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
+		dev_dbg(&ts->client->dev, "ESD work rescheduled\n");
+	}
+}
+
+static int gtp_esd_init(struct goodix_ts_data *ts)
+{
+	struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+	INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func);
+	mutex_init(&ts_esd->mutex);
+	ts_esd->esd_on = false;
+
+	return 0;
+}
+
+void gtp_esd_on(struct goodix_ts_data *ts)
+{
+	struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+	if (!ts->pdata->esd_protect)
+		return;
+	mutex_lock(&ts_esd->mutex);
+	if (ts_esd->esd_on == false) {
+		ts_esd->esd_on = true;
+		schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
+		dev_info(&ts->client->dev, "ESD on");
+	}
+	mutex_unlock(&ts_esd->mutex);
+}
+
+void gtp_esd_off(struct goodix_ts_data *ts)
+{
+	struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+	if (!ts->pdata->esd_protect)
+		return;
+	mutex_lock(&ts_esd->mutex);
+	if (ts_esd->esd_on == true) {
+		ts_esd->esd_on = false;
+		cancel_delayed_work_sync(&ts_esd->delayed_work);
+		dev_info(&ts->client->dev, "ESD off");
+	}
+	mutex_unlock(&ts_esd->mutex);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id gtp_match_table[] = {
+	{.compatible = "goodix,gt9xx",},
+	{ },
+};
+#endif
+
+static const struct i2c_device_id gtp_device_id[] = {
+	{ GTP_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver goodix_ts_driver = {
+	.probe		= gtp_probe,
+	.remove		= gtp_drv_remove,
+	.id_table	= gtp_device_id,
+	.shutdown	= gtp_shutdown,
+	.driver = {
+		.name	  = GTP_I2C_NAME,
+		.owner	  = THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = gtp_match_table,
+#endif
+#if !defined(CONFIG_FB) && defined(CONFIG_PM)
+		.pm		  = &gtp_pm_ops,
+#endif
+	},
+};
+
+static int __init gtp_init(void)
+{
+	s32 ret;
+
+	pr_info("Gt9xx driver installing..\n");
+	ret = i2c_add_driver(&goodix_ts_driver);
+
+	return ret;
+}
+
+static void __exit gtp_exit(void)
+{
+	pr_info("Gt9xx driver exited\n");
+	i2c_del_driver(&goodix_ts_driver);
+}
+
+module_init(gtp_init);
+module_exit(gtp_exit);
+
+MODULE_DESCRIPTION("GT9 serials touch controller Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h
new file mode 100644
index 0000000..78fa338
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h
@@ -0,0 +1,375 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright  (C)  2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version: 2.8.0.2
+ * Release Date: 2017/12/14
+ */
+
+#ifndef _GOODIX_GT9XX_H_
+#define _GOODIX_GT9XX_H_
+
+#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/usb.h>
+#include <linux/power_supply.h>
+
+#define GTP_TOOL_PEN	1
+#define GTP_TOOL_FINGER 2
+
+#define MAX_KEY_NUMS 4
+#define GTP_CONFIG_MAX_LENGTH 240
+#define GTP_ADDR_LENGTH       2
+
+/***************************PART1:ON/OFF define*******************************/
+#define GTP_DEBUG_ON          1
+#define GTP_DEBUG_ARRAY_ON    0
+#define GTP_DEBUG_FUNC_ON     0
+
+struct goodix_point_t {
+	int id;
+	int x;
+	int y;
+	int w;
+	int p;
+	int tool_type;
+};
+
+struct goodix_config_data {
+	int length;
+	u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
+};
+
+struct goodix_ts_platform_data {
+	int irq_gpio;
+	int rst_gpio;
+	u32 irq_flags;
+	u32 abs_size_x;
+	u32 abs_size_y;
+	u32 max_touch_id;
+	u32 max_touch_width;
+	u32 max_touch_pressure;
+	u32 key_map[MAX_KEY_NUMS];
+	u32 key_nums;
+	u32 int_sync;
+	u32 driver_send_cfg;
+	u32 swap_x2y;
+	u32 slide_wakeup;
+	u32 auto_update;
+	u32 auto_update_cfg;
+	u32 esd_protect;
+	u32 type_a_report;
+	u32 power_off_sleep;
+	u32 resume_in_workqueue;
+	u32 pen_suppress_finger;
+	struct goodix_config_data config;
+};
+
+struct goodix_ts_esd {
+	struct delayed_work delayed_work;
+	struct mutex mutex;
+	bool esd_on;
+};
+
+enum {
+	REPORT_THREAD_ENABLED = 0,
+	HRTIMER_USED,
+	FW_ERROR,
+
+	DOZE_MODE,
+	SLEEP_MODE,
+	POWER_OFF_MODE,
+	RAW_DATA_MODE,
+
+	FW_UPDATE_RUNNING,
+	PANEL_RESETTING
+};
+
+struct goodix_pinctrl {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *int_default;
+	struct pinctrl_state *int_out_high;
+	struct pinctrl_state *int_out_low;
+	struct pinctrl_state *int_input;
+	struct pinctrl_state *rst_default;
+	struct pinctrl_state *rst_out_high;
+	struct pinctrl_state *rst_out_low;
+	struct pinctrl_state *rst_input;
+};
+
+struct goodix_fw_info {
+	u8 pid[6];
+	u16 version;
+	u8 sensor_id;
+};
+
+struct goodix_ts_data {
+	unsigned long flags; /* This member record the device status */
+
+	struct goodix_ts_esd ts_esd;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct input_dev *pen_dev;
+	struct goodix_ts_platform_data *pdata;
+	/* use pinctrl control int-pin output low or high */
+	struct goodix_pinctrl pinctrl;
+	struct hrtimer timer;
+	struct mutex lock;
+	struct notifier_block ps_notif;
+	struct regulator *vdd_ana;
+	struct regulator *vcc_i2c;
+#if defined(CONFIG_FB)
+	struct notifier_block notifier;
+	struct work_struct fb_notify_work;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	struct early_suspend early_suspend;
+#endif
+	struct goodix_fw_info fw_info;
+	bool force_update;
+	bool init_done;
+};
+
+/************************* PART2:TODO define *******************************/
+/* STEP_1(REQUIRED): Define Configuration Information Group(s)
+ * Sensor_ID Map:
+ *	 sensor_opt1 sensor_opt2 Sensor_ID
+ *		GND         GND          0
+ *		VDDIO      GND          1
+ *		NC           GND          2
+ *		GND         NC/300K    3
+ *		VDDIO      NC/300K    4
+ *		NC           NC/300K    5
+ */
+/* TODO: define your own default or for Sensor_ID == 0 config here.
+ *	 The predefined one is just a sample config,
+ *	 which is not suitable for your tp in most cases.
+ */
+#define CTP_CFG_GROUP0 {\
+	0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \
+	0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \
+	0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \
+	0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \
+	0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \
+	0x08, 0x00, 0x00, 0x04,	0xF2, 0x1C, 0x00, \
+	0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \
+	0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \
+	0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \
+	0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x02,	0x04, 0x06, 0x08, \
+	0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \
+	0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \
+	0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	0x00, 0x00, 0xB8, 0x01\
+}
+
+/* TODO: define your config for Sensor_ID == 1 here, if needed */
+#define CTP_CFG_GROUP1 {\
+}
+
+/* TODO: define your config for Sensor_ID == 2 here, if needed */
+#define CTP_CFG_GROUP2 {\
+}
+
+/* TODO: define your config for Sensor_ID == 3 here, if needed */
+#define CTP_CFG_GROUP3 {\
+}
+/* TODO: define your config for Sensor_ID == 4 here, if needed */
+#define CTP_CFG_GROUP4 {\
+}
+
+/* TODO: define your config for Sensor_ID == 5 here, if needed */
+#define CTP_CFG_GROUP5 {\
+}
+
+/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */
+#define GTP_RST_PORT    64 /* EXYNOS4_GPX2(0) */
+#define GTP_INT_PORT    65 /* EXYNOS4_GPX2(1) */
+
+#define GTP_GPIO_AS_INPUT(pin)          (gpio_direction_input(pin))
+#define GTP_GPIO_AS_INT(pin)            (GTP_GPIO_AS_INPUT(pin))
+#define GTP_GPIO_GET_VALUE(pin)         gpio_get_value(pin)
+#define GTP_GPIO_OUTPUT(pin, level)      gpio_direction_output(pin, level)
+#define GTP_GPIO_REQUEST(pin, label)    gpio_request(pin, label)
+#define GTP_GPIO_FREE(pin)              gpio_free(pin)
+
+/* STEP_3(optional): Specify your special config info if needed */
+#define GTP_DEFAULT_MAX_X	 720    /* default coordinate max values */
+#define GTP_DEFAULT_MAX_Y	 1080
+#define GTP_DEFAULT_MAX_WIDTH	 1024
+#define GTP_DEFAULT_MAX_PRESSURE 1024
+#define GTP_DEFAULT_INT_TRIGGER	 1 /* 1 rising, 2 falling */
+#define GTP_MAX_TOUCH_ID	 16
+
+/* STEP_4(optional): If keys are available and reported as keys,
+ * config your key info here
+ */
+#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \
+	KEY_F1, KEY_F2, KEY_F3}
+
+/**************************PART3:OTHER define*******************************/
+#define GTP_DRIVER_VERSION	"V2.8.0.2<2017/12/14>"
+#define GTP_I2C_NAME		"goodix-ts"
+#define GT91XX_CONFIG_PROC_FILE	"gt9xx_config"
+#define GTP_POLL_TIME		10
+#define GTP_CONFIG_MIN_LENGTH	186
+#define GTP_ESD_CHECK_VALUE	0xAA
+#define RETRY_MAX_TIMES		5
+#define PEN_TRACK_ID		9
+#define MASK_BIT_8		0x80
+#define FAIL			0
+#define SUCCESS			1
+
+/* Registers define */
+#define GTP_REG_COMMAND		0x8040
+#define GTP_REG_ESD_CHECK	0x8041
+#define GTP_REG_COMMAND_CHECK	0x8046
+#define GTP_REG_CONFIG_DATA	0x8047
+#define GTP_REG_VERSION		0x8140
+#define GTP_REG_SENSOR_ID	0x814A
+#define GTP_REG_DOZE_BUF	0x814B
+#define GTP_READ_COOR_ADDR	0x814E
+
+/* Sleep time define */
+#define GTP_1_DLY_MS		1
+#define GTP_2_DLY_MS		2
+#define GTP_10_DLY_MS		10
+#define GTP_20_DLY_MS		20
+#define GTP_50_DLY_MS		50
+#define GTP_58_DLY_MS		58
+#define GTP_100_DLY_MS		100
+#define GTP_500_DLY_MS		500
+#define GTP_1000_DLY_MS		1000
+#define GTP_3000_DLY_MS		3000
+
+#define RESOLUTION_LOC        3
+#define TRIGGER_LOC           8
+
+#define CFG_GROUP_LEN(p_cfg_grp)  ARRAY_SIZE(p_cfg_grp)
+/* Log define */
+#define GTP_DEBUG(fmt, arg...) \
+do { \
+	if (GTP_DEBUG_ON) {\
+		pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\
+	} \
+} while (0)
+#define GTP_DEBUG_ARRAY(array, num) \
+do { \
+	s32 i;\
+	u8 *a = array;\
+	if (GTP_DEBUG_ARRAY_ON) {\
+		pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\
+		for (i = 0; i < (num); i++) {\
+			pr_warn("%02x  ", (a)[i]);\
+			if ((i + 1) % 10 == 0) {\
+				pr_warn("\n");\
+			} \
+		} \
+		pr_warn("\n");\
+	} \
+} while (0)
+#define GTP_DEBUG_FUNC() \
+do {\
+	if (GTP_DEBUG_FUNC_ON) {\
+		pr_warn("<<-GTP-FUNC->>  Func:%s@Line:%d\n", \
+		__func__, __LINE__);\
+	} \
+} while (0)
+#define GTP_SWAP(x, y) \
+do {\
+	typeof(x) z = x;\
+	x = y;\
+	y = z;\
+} while (0)
+
+/******************************End of Part III********************************/
+#ifdef CONFIG_OF
+extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid);
+#endif
+
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms);
+extern void gtp_esd_on(struct goodix_ts_data *ts);
+extern void gtp_esd_off(struct goodix_ts_data *ts);
+extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+extern u16 show_len;
+extern u16 total_len;
+extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
+extern s32 gup_update_proc(void *dir);
+extern s32 gup_enter_update_mode(struct i2c_client *client);
+extern void gup_leave_update_mode(struct i2c_client *client);
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+extern s32 init_wr_node(struct i2c_client *client);
+extern void uninit_wr_node(void);
+#endif
+
+/*********** For gt9xx_update Start *********/
+extern struct i2c_client *i2c_connect_client;
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern void gtp_int_output(struct goodix_ts_data *ts, int level);
+extern void gtp_rst_output(struct goodix_ts_data *ts, int level);
+extern void gtp_rst_input(struct goodix_ts_data *ts);
+extern s32 gtp_send_cfg(struct i2c_client *client);
+extern s32 gtp_get_fw_info(struct i2c_client *client,
+			   struct goodix_fw_info *fw_info);
+extern s32 gtp_i2c_read_dbl_check(struct i2c_client *client,
+				  u16 addr, u8 *rxbuf, int len);
+extern int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len);
+extern int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len);
+extern s32 gtp_fw_startup(struct i2c_client *client);
+extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf);
+/*********** For gt9xx_update End *********/
+
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c
new file mode 100644
index 0000000..7a428a3
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c
@@ -0,0 +1,2090 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright  (C)  2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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/kthread.h>
+#include "gt9xx.h"
+
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+
+#define GUP_REG_HW_INFO		0x4220
+#define GUP_REG_FW_MSG		0x41E4
+#define GUP_REG_PID_VID		0x8140
+
+#define FIRMWARE_NAME_LEN_MAX		256
+#define GOODIX_FIRMWARE_FILE_NAME	"goodix_firmware.bin"
+#define GOODIX_CONFIG_FILE_NAME		"goodix_config.cfg"
+
+#define FW_HEAD_LENGTH			14
+#define FW_SECTION_LENGTH		0x2000	/*  8K */
+#define FW_DSP_ISP_LENGTH		0x1000	/*  4K */
+#define FW_DSP_LENGTH			0x1000	/*  4K */
+#define FW_BOOT_LENGTH			0x800	/*  2K */
+#define FW_SS51_LENGTH		(4 * FW_SECTION_LENGTH)	/*  32K */
+#define FW_BOOT_ISP_LENGTH		0x800	/*  2k */
+#define FW_GLINK_LENGTH			0x3000	/*  12k */
+#define FW_GWAKE_LENGTH		(4 * FW_SECTION_LENGTH) /*  32k */
+
+#define DELAY_FOR_SENDCFG		500
+#define PACK_SIZE			256
+#define MAX_FRAME_CHECK_TIME		5
+
+#define _bRW_MISCTL__SRAM_BANK		0x4048
+#define _bRW_MISCTL__MEM_CD_EN		0x4049
+#define _bRW_MISCTL__CACHE_EN		0x404B
+#define _bRW_MISCTL__TMR0_EN		0x40B0
+#define _rRW_MISCTL__SWRST_B0_		0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE	0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_	0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_	0x4218
+#define _rRW_MISCTL__BOOT_CTL_		0x5094
+
+#pragma pack(1)
+struct st_fw_head {
+	u8	hw_info[4];			 /* hardware info */
+	u8	pid[8];				 /* product id */
+	u16 vid;				 /* version id */
+};
+#pragma pack()
+
+struct st_update_msg {
+	u8 fw_damaged;
+	u8 fw_flag;
+	const u8 *fw_data;
+	struct file *cfg_file;
+	struct st_fw_head ic_fw_msg;
+	u32 fw_total_len;
+	u32 fw_burned_len;
+	const struct firmware *fw;
+} update_msg;
+
+struct st_update_msg update_msg;
+
+u16 show_len;
+u16 total_len;
+
+static u8 gup_burn_fw_gwake_section(struct i2c_client *client,
+				    u8 *fw_section, u16 start_addr,
+				    u32 len, u8 bank_cmd);
+
+static s32 gup_init_panel(struct goodix_ts_data *ts)
+{
+	s32 ret = 0;
+	u8 opr_buf[16];
+	u8 sensor_id = 0;
+	u8 drv_cfg_version;
+	u8 flash_cfg_version;
+	struct goodix_config_data *cfg = &ts->pdata->config;
+
+	if (cfg->length < GTP_CONFIG_MIN_LENGTH) {
+		dev_err(&ts->client->dev,
+			"No valid config with sensor_ID(%d) ",
+			sensor_id);
+
+		return -EPERM;
+	}
+
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+				     &opr_buf[0], 1);
+	if (ret == SUCCESS) {
+		dev_dbg(&ts->client->dev,
+			"CFG_GROUP%d Config Version: %d, IC Config Version: %d",
+			sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]);
+
+		flash_cfg_version = opr_buf[0];
+		drv_cfg_version = cfg->data[GTP_ADDR_LENGTH];
+
+		if (flash_cfg_version < 90 &&
+		    flash_cfg_version > drv_cfg_version)
+			cfg->data[GTP_ADDR_LENGTH] = 0x00;
+	} else {
+		dev_err(&ts->client->dev,
+			"Failed to get ic config version!No config sent!");
+		return -EPERM;
+	}
+
+	ret = gtp_send_cfg(ts->client);
+	if (ret < 0)
+		dev_err(&ts->client->dev, "Send config error.");
+	else
+		usleep_range(10000, 11000);
+
+	/* restore config vrsion */
+	cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version;
+
+	return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
+{
+	s32 i = 0;
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+
+	for (i = 0; i < 5; i++) {
+		if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+			break;
+	}
+
+	if (i >= 5) {
+		dev_err(&client->dev,
+				"Read data from 0x%02x%02x failed!",
+				msg[0], msg[1]);
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+	s32 i = 0;
+	u8 msg[3];
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	msg[2] = val;
+
+	for (i = 0; i < 5; i++) {
+		if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+			break;
+	}
+
+	if (i >= 5) {
+		dev_err(&client->dev,
+			"Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_get_ic_fw_msg(struct i2c_client *client)
+{
+	s32 ret = -1;
+	u8	retry = 0;
+	u8	buf[16];
+	u8	i;
+
+	/*  step1:get hardware info */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+				     &buf[GTP_ADDR_LENGTH], 4);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit");
+		return FAIL;
+	}
+
+	/*  buf[2~5]: 00 06 90 00
+	 *  hw_info: 00 90 06 00
+	 */
+	for (i = 0; i < 4; i++)
+		update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+		dev_dbg(&client->dev,
+			"IC Hardware info:%02x%02x%02x%02x",
+			update_msg.ic_fw_msg.hw_info[0],
+			update_msg.ic_fw_msg.hw_info[1],
+			update_msg.ic_fw_msg.hw_info[2],
+			update_msg.ic_fw_msg.hw_info[3]);
+	/*  step2:get firmware message */
+	for (retry = 0; retry < 2; retry++) {
+		ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+		if (ret == FAIL) {
+			dev_err(&client->dev, "Read firmware message fail.");
+			return ret;
+		}
+
+		update_msg.fw_damaged = buf[GTP_ADDR_LENGTH];
+		if ((update_msg.fw_damaged != 0xBE) && (!retry)) {
+			dev_info(&client->dev, "The check sum in ic is error.");
+			dev_info(&client->dev, "The IC will be updated by force.");
+			continue;
+		}
+		break;
+	}
+	dev_dbg(&client->dev,
+		"IC force update flag:0x%x", update_msg.fw_damaged);
+
+	/*  step3:get pid & vid */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+				     &buf[GTP_ADDR_LENGTH], 6);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit");
+		return FAIL;
+	}
+
+	memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+	memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+	dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+	/* GT9XX PID MAPPING */
+	/*|-----FLASH-----RAM-----|
+	 *|------918------918-----|
+	 *|------968------968-----|
+	 *|------913------913-----|
+	 *|------913P-----913P----|
+	 *|------927------927-----|
+	 *|------927P-----927P----|
+	 *|------9110-----9110----|
+	 *|------9110P----9111----|
+	 */
+	if (update_msg.ic_fw_msg.pid[0] != 0) {
+		if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+			dev_dbg(&client->dev, "IC Mapping Product id:%s",
+					update_msg.ic_fw_msg.pid);
+			memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+		}
+	}
+
+	update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+				   (buf[GTP_ADDR_LENGTH + 5] << 8);
+	dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+	return SUCCESS;
+}
+
+s32 gup_enter_update_mode(struct i2c_client *client)
+{
+	s32 ret = -1;
+	s32 retry = 0;
+	u8 rd_buf[3];
+
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	/* step1:RST output low last at least 2ms */
+	if (!gpio_is_valid(ts->pdata->rst_gpio)) {
+		dev_err(&ts->client->dev, "update failed, no rst pin\n");
+		return FAIL;
+	}
+	gtp_rst_output(ts, 0);
+	usleep_range(2000, 3000);
+
+	/* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+	gtp_int_output(ts, client->addr == 0x14);
+	usleep_range(2000, 3000);
+
+	/* step3:RST output high reset guitar */
+	gtp_rst_output(ts, 1);
+
+	/* 20121211 modify start */
+	usleep_range(5000, 6000);
+	while (retry++ < 200) {
+		/* step4:Hold ss51 & dsp */
+		ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+		if (ret <= 0) {
+			dev_dbg(&client->dev,
+				"Hold ss51 & dsp I2C error,retry:%d",
+				retry);
+			continue;
+		}
+
+		/* step5:Confirm hold */
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_dbg(&client->dev,
+				"Hold ss51 & dsp I2C error,retry:%d",
+				retry);
+			continue;
+		}
+		if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+			dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS");
+			break;
+		}
+		dev_dbg(&client->dev,
+			"Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+			rd_buf[GTP_ADDR_LENGTH]);
+	}
+	if (retry >= 200) {
+		dev_err(&client->dev, "Enter update Hold ss51 failed.");
+		return FAIL;
+	}
+
+	/* step6:DSP_CK and DSP_ALU_CK PowerOn */
+	ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+	/* 20121211 modify end */
+	return ret;
+}
+
+void gup_leave_update_mode(struct i2c_client *client)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->pdata->int_sync && ts->pinctrl.pinctrl)
+		pinctrl_select_state(ts->pinctrl.pinctrl,
+				     ts->pinctrl.int_input);
+	else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio))
+		gpio_direction_input(ts->pdata->irq_gpio);
+	dev_dbg(&client->dev, "[leave_update_mode]reset chip.");
+	gtp_reset_guitar(i2c_connect_client, 20);
+}
+
+static u8 gup_enter_update_judge(struct i2c_client *client,
+				 struct st_fw_head *fw_head)
+{
+	u16 u16_tmp;
+	s32 i = 0;
+	u32 fw_len = 0;
+	s32 pid_cmp_len = 0;
+
+	u16_tmp = fw_head->vid;
+	fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+	dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4,
+		 &fw_head->hw_info[0]);
+	dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid);
+	dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid);
+
+	dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4,
+		 &update_msg.ic_fw_msg.hw_info[0]);
+	dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid);
+	dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid);
+
+	if (!memcmp(fw_head->pid, "9158", 4) &&
+	    !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) {
+		dev_info(&client->dev, "Update GT915S to GT9158 directly!");
+		return SUCCESS;
+	}
+	/* First two conditions */
+	if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+	sizeof(update_msg.ic_fw_msg.hw_info))) {
+		fw_len = 42 * 1024;
+	} else {
+		fw_len = fw_head->hw_info[3];
+		fw_len += (((u32)fw_head->hw_info[2]) << 8);
+		fw_len += (((u32)fw_head->hw_info[1]) << 16);
+		fw_len += (((u32)fw_head->hw_info[0]) << 24);
+	}
+	if (update_msg.fw_total_len != fw_len) {
+		dev_err(&client->dev,
+			"Inconsistent firmware size, Update aborted!");
+		dev_err(&client->dev,
+			" Default size: %d(%dK), actual size: %d(%dK)",
+			fw_len, fw_len/1024, update_msg.fw_total_len,
+			update_msg.fw_total_len/1024);
+		return FAIL;
+	}
+	dev_info(&client->dev, "Firmware length:%d(%dK)",
+		 update_msg.fw_total_len,
+		 update_msg.fw_total_len/1024);
+
+	if (update_msg.fw_damaged != 0xBE) {
+		dev_info(&client->dev, "FW chksum error,need enter update.");
+		return SUCCESS;
+	}
+
+	/*  20130523 start */
+	if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+		dev_info(&client->dev, "Illegal IC pid, need enter update");
+		return SUCCESS;
+	}
+
+	/* check pid legality */
+	for (i = 0; i < 3; i++) {
+		if (!isdigit(update_msg.ic_fw_msg.pid[i])) {
+			dev_info(&client->dev,
+				 "Illegal IC pid, need enter update");
+			return SUCCESS;
+		}
+	}
+	/*  20130523 end */
+
+	pid_cmp_len = strlen(fw_head->pid);
+	if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid))
+		pid_cmp_len = strlen(update_msg.ic_fw_msg.pid);
+
+	if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) ||
+			(!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+			(!memcmp(fw_head->pid, "91XX", 4))) {
+		if (!memcmp(fw_head->pid, "91XX", 4))
+			dev_dbg(&client->dev,
+				"Force none same pid update mode.");
+		else
+			dev_dbg(&client->dev, "Get the same pid.");
+
+		/* The third condition */
+		if (fw_head->vid != update_msg.ic_fw_msg.vid) {
+			dev_info(&client->dev, "Need enter update.");
+			return SUCCESS;
+		}
+		dev_err(&client->dev, "File VID == Ic VID, update aborted!");
+	} else {
+		dev_err(&client->dev, "File PID != Ic PID, update aborted!");
+	}
+
+	return FAIL;
+}
+
+static int gup_update_config(struct i2c_client *client)
+{
+	s32 ret = 0;
+	s32 i = 0;
+	s32 file_cfg_len = 0;
+	u8 *file_config;
+	const struct firmware *fw_cfg;
+
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME,
+			       &client->dev);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"Cannot get config file - %s (%d)\n",
+			GOODIX_CONFIG_FILE_NAME, ret);
+		return -EFAULT;
+	}
+	if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) {
+		dev_err(&client->dev, "config file illegal");
+		ret = -EFAULT;
+		goto cfg_fw_err;
+	}
+
+	dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size);
+
+	file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+			      GFP_KERNEL);
+	if (!file_config) {
+		ret = -ENOMEM;
+		goto cfg_fw_err;
+	}
+	file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+	file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+	file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size,
+					  &file_config[GTP_ADDR_LENGTH]);
+	if (file_cfg_len < 0) {
+		dev_err(&client->dev, "failed covert ascii to hex");
+		ret = -EFAULT;
+		goto update_cfg_file_failed;
+	}
+
+	GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len);
+
+	i = 0;
+	while (i++ < 5) {
+		ret = gtp_i2c_write(client, file_config, file_cfg_len + 2);
+		if (ret > 0) {
+			dev_info(&client->dev, "Send config SUCCESS.");
+			msleep(DELAY_FOR_SENDCFG);
+			break;
+		}
+		dev_err(&ts->client->dev, "Send config i2c error.");
+	}
+
+update_cfg_file_failed:
+	kfree(file_config);
+cfg_fw_err:
+	release_firmware(fw_cfg);
+	return ret;
+}
+
+static u8 gup_check_firmware_name(struct i2c_client *client,
+		u8 **path_p)
+{
+	u8 len;
+	u8 *fname;
+
+	if (!(*path_p)) {
+		*path_p = GOODIX_FIRMWARE_FILE_NAME;
+		return 0;
+	}
+
+	len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX);
+	if (len >= FIRMWARE_NAME_LEN_MAX) {
+		dev_err(&client->dev, "firmware name too long!");
+		return -EINVAL;
+	}
+
+	fname = strrchr(*path_p, '/');
+	if (fname) {
+		fname = fname + 1;
+		*path_p = fname;
+	}
+
+	return 0;
+}
+
+static u8 gup_get_update_file(struct i2c_client *client,
+				struct st_fw_head *fw_head, u8 *path)
+{
+	s32 ret = 0;
+	s32 i = 0;
+	s32 fw_checksum = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->pdata->auto_update_cfg) {
+		ret = gup_update_config(client);
+		if (ret <= 0)
+			dev_err(&client->dev, "Update config failed.");
+	}
+
+	ret = gup_check_firmware_name(client, &path);
+	if (ret < 0)
+		return FAIL;
+
+	ret = request_firmware(&update_msg.fw, path, &client->dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed get firmware:%d\n", ret);
+		return FAIL;
+	}
+
+	dev_info(&client->dev, "FW File: %s size=%zu",
+		 path, update_msg.fw->size);
+	update_msg.fw_data = update_msg.fw->data;
+	update_msg.fw_total_len = update_msg.fw->size;
+
+	if (update_msg.fw_total_len <
+	    FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+	    FW_DSP_LENGTH + FW_BOOT_LENGTH) {
+		dev_err(&client->dev,
+			"INVALID bin file(size: %d), update aborted.",
+			update_msg.fw_total_len);
+		goto invalied_fw;
+	}
+
+	update_msg.fw_total_len -= FW_HEAD_LENGTH;
+
+	dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)",
+		update_msg.fw_total_len, update_msg.fw_total_len/1024);
+
+	memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH);
+
+	/* check firmware legality */
+	fw_checksum = 0;
+	for (i = 0; i < update_msg.fw_total_len; i += 2) {
+		u16 temp;
+
+		temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) +
+			update_msg.fw_data[FW_HEAD_LENGTH + i + 1];
+		fw_checksum += temp;
+	}
+
+	dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF);
+	if (fw_checksum & 0xFFFF) {
+		dev_err(&client->dev, "Illegal firmware file.");
+		goto invalied_fw;
+	}
+
+	return SUCCESS;
+
+invalied_fw:
+	update_msg.fw_data = NULL;
+	update_msg.fw_total_len = 0;
+	release_firmware(update_msg.fw);
+	return FAIL;
+}
+
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf,
+		u16 start_addr, u16 total_length)
+{
+	s32 ret = 0;
+	u16 burn_addr = start_addr;
+	u16 frame_length = 0;
+	u16 burn_length = 0;
+	u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8 retry = 0;
+
+	dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x",
+		total_length / 1024, start_addr);
+	while (burn_length < total_length) {
+		dev_dbg(&client->dev,
+			"B/T:%04d/%04d", burn_length, total_length);
+		frame_length = ((total_length - burn_length)
+		> PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
+		wr_buf[0] = (u8)(burn_addr>>8);
+		rd_buf[0] = wr_buf[0];
+		wr_buf[1] = (u8)burn_addr;
+		rd_buf[1] = wr_buf[1];
+		memcpy(&wr_buf[GTP_ADDR_LENGTH],
+		&burn_buf[burn_length], frame_length);
+
+		for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+			ret = gtp_i2c_write(client,
+			wr_buf, GTP_ADDR_LENGTH + frame_length);
+			if (ret <= 0) {
+				dev_err(&client->dev,
+					"Write frame data i2c error.");
+				continue;
+			}
+			ret = gtp_i2c_read(client, rd_buf,
+					   GTP_ADDR_LENGTH + frame_length);
+			if (ret <= 0) {
+				dev_err(&client->dev,
+					"Read back frame data i2c error.");
+				continue;
+			}
+			if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+				&rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+				dev_err(&client->dev,
+					"Check frame data fail,not equal.");
+				dev_dbg(&client->dev, "write array:");
+				GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+				frame_length);
+				dev_dbg(&client->dev, "read array:");
+				GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+				frame_length);
+				continue;
+			} else {
+				/* dev_dbg(&client->dev,
+				 * "Check frame data success.");
+				 */
+				break;
+			}
+		}
+		if (retry >= MAX_FRAME_CHECK_TIME) {
+			dev_err(&client->dev,
+				"Burn frame data time out,exit.");
+			return FAIL;
+		}
+		burn_length += frame_length;
+		burn_addr += frame_length;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end)
+{
+	if (!update_msg.fw_data ||
+	    update_msg.fw_total_len < FW_HEAD_LENGTH + offset + length) {
+		pr_err("<<-GTP->> cannot load section data. fw_len=%d read end=%d\n",
+		update_msg.fw_total_len,
+		FW_HEAD_LENGTH + offset + length);
+		return FAIL;
+	}
+
+	if (set_or_end == SEEK_SET) {
+		memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset],
+		       length);
+	} else {
+		/* seek end */
+		memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len +
+		       FW_HEAD_LENGTH - offset], length);
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+			   u16 start_rd_addr, u16 chk_length)
+{
+	u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	s32 ret = 0;
+	u16 recall_addr = start_rd_addr;
+	u16 recall_length = 0;
+	u16 frame_length = 0;
+
+	while (recall_length < chk_length) {
+		frame_length = ((chk_length - recall_length)
+				> PACK_SIZE) ? PACK_SIZE :
+				(chk_length - recall_length);
+		ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+		if (ret <= 0) {
+			dev_err(&client->dev, "recall i2c error,exit");
+			return FAIL;
+		}
+
+		if (memcmp(&rd_buf[GTP_ADDR_LENGTH],
+		&chk_src[recall_length], frame_length)) {
+			dev_err(&client->dev, "Recall frame data fail,not equal.");
+			dev_dbg(&client->dev, "chk_src array:");
+			GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+			dev_dbg(&client->dev, "recall array:");
+			GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+			return FAIL;
+		}
+
+		recall_length += frame_length;
+		recall_addr += frame_length;
+	}
+	dev_dbg(&client->dev,
+			"Recall check %dk firmware success.",
+			(chk_length/1024));
+
+	return SUCCESS;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+			      u16 start_addr, u8 bank_cmd)
+{
+	s32 ret = 0;
+	u8	rd_buf[5];
+
+	/* step1:hold ss51 & dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail.");
+		return FAIL;
+	}
+
+	/* step2:set scramble */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_section]set scramble fail.");
+		return FAIL;
+	}
+
+	/* step3:select bank */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+	(bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]select bank %d fail.",
+			(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step4:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step5:burn 8k fw section */
+	ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_section]burn fw_section fail.");
+		return FAIL;
+	}
+
+	/* step6:hold ss51 & release dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]hold ss51 & release dsp fail.");
+		return FAIL;
+	}
+	/* must delay */
+	usleep_range(1000, 2000);
+
+	/* step7:send burn cmd to move data to flash from sram */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_section]send burn cmd fail.");
+		return FAIL;
+	}
+	dev_dbg(&client->dev,
+		"[burn_fw_section]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_err(&client->dev,
+				"[burn_fw_section]Get burn state fail");
+			return FAIL;
+		}
+		usleep_range(10000, 11000);
+	/* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.",
+	 * rd_buf[GTP_ADDR_LENGTH]);
+	 */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:select bank */
+	ret = gup_set_ic_msg(client,
+			     _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]select bank %d fail.",
+			(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step9:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step10:recall 8k fw section */
+	ret = gup_recall_check(client,
+	fw_section, start_addr, FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_section]recall check %dk firmware fail.",
+			FW_SECTION_LENGTH / 1024);
+		return FAIL;
+	}
+
+	/* step11:disable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]disable accessing code fail.");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_burn_dsp_isp(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_dsp_isp = NULL;
+	u8	retry = 0;
+
+	dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>");
+
+	/* step1:alloc memory */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+		if (fw_dsp_isp == NULL) {
+			continue;
+		} else {
+			dev_info(&client->dev,
+				"[burn_dsp_isp]Alloc %dk byte memory success.",
+				FW_DSP_ISP_LENGTH / 1024);
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load dsp isp file data */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data");
+	ret = gup_load_section_file(fw_dsp_isp,
+	FW_DSP_ISP_LENGTH, FW_DSP_ISP_LENGTH, SEEK_END);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_dsp_isp]load firmware dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step3:disable wdt,clear cache enable */
+	dev_dbg(&client->dev,
+		"[burn_dsp_isp]step3:disable wdt,clear cache enable");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_dsp_isp]clear cache enable fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step4:hold ss51 & dsp */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step5:set boot from sram */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step6:software reboot */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot");
+	ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]software reboot fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step7:select bank2 */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step8:enable accessing code */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_dsp_isp]enable accessing code fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step9:burn 4k dsp_isp */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp");
+	ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step10:set scramble */
+	dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_dsp_isp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	update_msg.fw_burned_len += FW_DSP_ISP_LENGTH;
+	dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d",
+			update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_dsp_isp:
+	kfree(fw_dsp_isp);
+
+	return ret;
+}
+
+static u8 gup_burn_fw_ss51(struct i2c_client *client)
+{
+	u8 *fw_ss51 = NULL;
+	u8	retry = 0;
+	s32 ret = 0;
+
+	dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+	/* step1:alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_ss51 == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_ss51]Alloc %dk byte memory success.",
+				(FW_SECTION_LENGTH / 1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF.");
+	dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000");
+	memset(fw_ss51, 0xFF, FW_SECTION_LENGTH);
+
+	/* step3:clear control flag */
+	dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail.");
+		ret = FAIL;
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step4:burn ss51 firmware section 1 */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step4:burn ss51 firmware section 1");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step5:load ss51 firmware section 2 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+	ret = gup_load_section_file(fw_ss51,
+	FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]load ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step6:burn ss51 firmware section 2 */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step6:burn ss51 firmware section 2");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step7:load ss51 firmware section 3 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+	ret = gup_load_section_file(fw_ss51,
+	2 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]load ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step8:burn ss51 firmware section 3 */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step8:burn ss51 firmware section 3");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step9:load ss51 firmware section 4 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+	ret = gup_load_section_file(fw_ss51,
+	3 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]load ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step10:burn ss51 firmware section 4 */
+	dev_dbg(&client->dev,
+		"[burn_fw_ss51]step10:burn ss51 firmware section 4");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	update_msg.fw_burned_len += (FW_SECTION_LENGTH*4);
+	dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d",
+		update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_ss51:
+	kfree(fw_ss51);
+	return ret;
+}
+
+static u8 gup_burn_fw_dsp(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_dsp = NULL;
+	u8 retry = 0;
+	u8 rd_buf[5];
+
+	dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>");
+	/* step1:alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+		if (fw_dsp == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_dsp]Alloc %dk byte memory success.",
+				FW_SECTION_LENGTH / 1024);
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware dsp */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp");
+	ret = gup_load_section_file(fw_dsp,
+	4 * FW_SECTION_LENGTH, FW_DSP_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step3:select bank3 */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step4:hold ss51 & dsp */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step5:set scramble */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_dsp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step6:release ss51 & dsp */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp");
+	ret = gup_set_ic_msg(
+	client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+	/* must delay */
+	usleep_range(1000, 1100);
+
+	/* step7:burn 4k dsp firmware */
+	dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware");
+	ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step8:send burn cmd to move data to flash from sram */
+	dev_dbg(&client->dev,
+	"[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail.");
+		goto exit_burn_fw_dsp;
+	}
+	dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail");
+			goto exit_burn_fw_dsp;
+		}
+		usleep_range(10000, 11000);
+	/* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.",
+	 * rd_buf[GTP_ADDR_LENGTH]);
+	 */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step9:recall check 4k dsp firmware */
+	dev_dbg(&client->dev,
+		"[burn_fw_dsp]step9:recall check 4k dsp firmware");
+	ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_dsp]recall check 4k dsp firmware fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	update_msg.fw_burned_len += FW_DSP_LENGTH;
+	dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d",
+			update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_dsp:
+	kfree(fw_dsp);
+
+	return ret;
+}
+
+static u8 gup_burn_fw_boot(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_boot = NULL;
+	u8	retry = 0;
+	u8	rd_buf[5];
+
+	dev_info(&client->dev,
+		 "[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+	/* step1:Alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory");
+	while (retry++ < 5) {
+		fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+		if (fw_boot == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_boot]Alloc %dk byte memory success.",
+				FW_BOOT_LENGTH / 1024);
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware bootloader */
+	dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader");
+	ret = gup_load_section_file(fw_boot,
+	(4 * FW_SECTION_LENGTH + FW_DSP_LENGTH), FW_BOOT_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_boot]load firmware bootcode fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step3:hold ss51 & dsp */
+	dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step4:set scramble */
+	dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step5:hold ss51 & release dsp */
+	dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	/* 20121211 */
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+	/* must delay */
+	usleep_range(1000, 1100);
+
+	/* step6:select bank3 */
+	dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step6:burn 2k bootloader firmware */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot]step6:burn 2k bootloader firmware");
+	ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step7:send burn cmd to move data to flash from sram */
+	dev_dbg(&client->dev,
+	"[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail.");
+		goto exit_burn_fw_boot;
+	}
+	dev_dbg(&client->dev,
+		"[burn_fw_boot]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_err(&client->dev,
+				"[burn_fw_boot]Get burn state fail");
+			goto exit_burn_fw_boot;
+		}
+		usleep_range(10000, 11000);
+	/* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.",
+	 * rd_buf[GTP_ADDR_LENGTH]);
+	 */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:recall check 2k bootloader firmware */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot]step8:recall check 2k bootloader firmware");
+	ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_boot]recall check 2k bootcode firmware fail");
+		goto exit_burn_fw_boot;
+	}
+
+	update_msg.fw_burned_len += FW_BOOT_LENGTH;
+	dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d",
+		update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_boot:
+	kfree(fw_boot);
+
+	return ret;
+}
+static u8 gup_burn_fw_boot_isp(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_boot_isp = NULL;
+	u8	retry = 0;
+	u8	rd_buf[5];
+
+	if (update_msg.fw_burned_len >= update_msg.fw_total_len) {
+		dev_dbg(&client->dev, "No need to upgrade the boot_isp code!");
+		return SUCCESS;
+	}
+	dev_info(&client->dev,
+		"[burn_fw_boot_isp]Begin burn boot_isp firmware---->>");
+
+	/* step1:Alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory");
+	while (retry++ < 5) {
+		fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL);
+		if (fw_boot_isp == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_boot_isp]Alloc %dk byte memory success.",
+				(FW_BOOT_ISP_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev,
+			"[burn_fw_boot_isp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware bootloader */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]step2:load firmware bootloader isp");
+	/* ret = gup_load_section_file(fw_boot_isp,
+	 * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH +
+	 * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET);
+	 */
+	ret = gup_load_section_file(fw_boot_isp,
+	(update_msg.fw_burned_len - FW_DSP_ISP_LENGTH),
+	FW_BOOT_ISP_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_boot_isp]load firmware boot_isp fail.");
+		goto exit_burn_fw_boot_isp;
+	}
+
+	/* step3:hold ss51 & dsp */
+	dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail");
+		ret = FAIL;
+		goto exit_burn_fw_boot_isp;
+	}
+
+	/* step4:set scramble */
+	dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot_isp;
+	}
+
+
+	/* step5:hold ss51 & release dsp */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]step5:hold ss51 & release dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	/* 20121211 */
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_boot_isp]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot_isp;
+	}
+	/* must delay */
+	usleep_range(1000, 2000);
+
+	/* step6:select bank3 */
+	dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot_isp;
+	}
+
+	/* step7:burn 2k bootload_isp firmware */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]step7:burn 2k bootloader firmware");
+	ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_boot_isp]burn fw_section fail.");
+		goto exit_burn_fw_boot_isp;
+	}
+
+	/* step7:send burn cmd to move data to flash from sram */
+	dev_dbg(&client->dev,
+	"[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07);
+	if (ret <= 0) {
+		dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail.");
+		goto exit_burn_fw_boot_isp;
+	}
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_err(&client->dev,
+				"[burn_fw_boot_isp]Get burn state fail");
+			goto exit_burn_fw_boot_isp;
+		}
+		usleep_range(10000, 11000);
+	/* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get
+	 * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+	 */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:recall check 2k bootload_isp firmware */
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]step9:recall check 2k bootloader firmware");
+	ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+		"[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail.");
+		goto exit_burn_fw_boot_isp;
+	}
+
+	update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH;
+	dev_dbg(&client->dev,
+		"[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_boot_isp:
+	kfree(fw_boot_isp);
+
+	return ret;
+}
+
+static u8 gup_burn_fw_link(struct i2c_client *client)
+{
+	u8 *fw_link = NULL;
+	u8	retry = 0;
+	s32 ret = 0;
+	u32 offset;
+
+	if (update_msg.fw_burned_len >= update_msg.fw_total_len) {
+		dev_dbg(&client->dev, "No need to upgrade the link code!");
+		return SUCCESS;
+	}
+	dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>");
+
+	/* step1:Alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory");
+	while (retry++ < 5) {
+		fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_link == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_link]Alloc %dk byte memory success.",
+				(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware link section 1 */
+	dev_dbg(&client->dev,
+		"[burn_fw_link]step2:load firmware link section 1");
+	offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH;
+	ret = gup_load_section_file(
+	fw_link, offset, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_link]load firmware link section 1 fail.");
+		goto exit_burn_fw_link;
+	}
+
+	/* step3:burn link firmware section 1 */
+	dev_dbg(&client->dev,
+		"[burn_fw_link]step3:burn link firmware section 1");
+	ret = gup_burn_fw_gwake_section(
+	client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38);
+
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_link]burn link firmware section 1 fail.");
+		goto exit_burn_fw_link;
+	}
+
+	/* step4:load link firmware section 2 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_link]step4:load link firmware section 2 file data");
+	offset += FW_SECTION_LENGTH;
+	ret = gup_load_section_file(
+	fw_link, offset, FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET);
+
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_link]load link firmware section 2 fail.");
+		goto exit_burn_fw_link;
+	}
+
+	/* step5:burn link firmware section 2 */
+	dev_dbg(&client->dev,
+		"[burn_fw_link]step4:burn link firmware section 2");
+	ret = gup_burn_fw_gwake_section(client,
+	fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39);
+
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_link]burn link firmware section 2 fail.");
+		goto exit_burn_fw_link;
+	}
+
+	update_msg.fw_burned_len += FW_GLINK_LENGTH;
+	dev_dbg(&client->dev,
+		"[burn_fw_link]Burned length:%d", update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_link:
+	kfree(fw_link);
+
+	return ret;
+}
+
+static u8 gup_burn_fw_gwake_section(struct i2c_client *client,
+		u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd)
+{
+	s32 ret = 0;
+	u8	rd_buf[5];
+
+	/* step1:hold ss51 & dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]hold ss51 & dsp fail.");
+		return FAIL;
+	}
+
+	/* step2:set scramble */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]set scramble fail.");
+		return FAIL;
+	}
+
+	/* step3:hold ss51 & release dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]hold ss51 & release dsp fail.");
+		return FAIL;
+	}
+	/* must delay */
+	usleep_range(1000, 2000);
+
+	/* step4:select bank */
+	ret = gup_set_ic_msg(
+	client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_section]select bank %d fail.",
+			(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step5:burn fw section */
+	ret = gup_burn_proc(client, fw_section, start_addr, len);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]burn fw_section fail.");
+		return FAIL;
+	}
+
+	/* step6:send burn cmd to move data to flash from sram */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]send burn cmd fail.");
+		return FAIL;
+	}
+	dev_dbg(&client->dev,
+		"[burn_fw_section]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			dev_err(&client->dev,
+				"[burn_fw_app_section]Get burn state fail");
+			return FAIL;
+		}
+		usleep_range(10000, 11000);
+	/* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d."
+	 * rd_buf[GTP_ADDR_LENGTH]);
+	 */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step7:recall fw section */
+	ret = gup_recall_check(client, fw_section, start_addr, len);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_app_section]recall check %dk firmware fail.",
+			len/1024);
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_burn_fw_gwake(struct i2c_client *client)
+{
+	u8 *fw_gwake = NULL;
+	u8	retry = 0;
+	s32 ret = 0;
+	u16 start_index = 4*FW_SECTION_LENGTH +
+	FW_DSP_LENGTH + FW_BOOT_LENGTH +
+	FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */
+	/* u16 start_index; */
+
+	if (start_index >= update_msg.fw_total_len) {
+		dev_dbg(&client->dev, "No need to upgrade the gwake code!");
+		return SUCCESS;
+	}
+	/* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */
+	dev_info(&client->dev,
+		 "[burn_fw_gwake]Begin burn gwake firmware---->>");
+
+	/* step1:alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_gwake =
+	kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_gwake == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_gwake]Alloc %dk byte memory success.",
+				(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* clear control flag */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]clear control flag fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step2:load app_code firmware section 1 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step2:load app_code firmware section 1 file data");
+	ret = gup_load_section_file(fw_gwake,
+	start_index, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]load app_code firmware section 1 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step3:burn app_code firmware section 1 */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step3:burn app_code firmware section 1");
+	ret = gup_burn_fw_gwake_section(client,
+	fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]burn app_code firmware section 1 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step5:load app_code firmware section 2 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step5:load app_code firmware section 2 file data");
+	ret = gup_load_section_file(
+	fw_gwake, start_index+FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]load app_code firmware section 2 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step6:burn app_code firmware section 2 */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step6:burn app_code firmware section 2");
+	ret = gup_burn_fw_gwake_section(client,
+	fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]burn app_code firmware section 2 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step7:load app_code firmware section 3 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step7:load app_code firmware section 3 file data");
+	ret = gup_load_section_file(
+	fw_gwake, start_index + 2*FW_SECTION_LENGTH,
+	FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]load app_code firmware section 3 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step8:burn app_code firmware section 3 */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step8:burn app_code firmware section 3");
+	ret = gup_burn_fw_gwake_section(
+	client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]burn app_code firmware section 3 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step9:load app_code firmware section 4 file data */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step9:load app_code firmware section 4 file data");
+	ret = gup_load_section_file(fw_gwake,
+	start_index + 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]load app_code firmware section 4 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* step10:burn app_code firmware section 4 */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]step10:burn app_code firmware section 4");
+	ret = gup_burn_fw_gwake_section(
+	client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_gwake]burn app_code firmware section 4 fail.");
+		goto exit_burn_fw_gwake;
+	}
+
+	/* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */
+	dev_dbg(&client->dev,
+		"[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len);
+	ret = SUCCESS;
+
+exit_burn_fw_gwake:
+	kfree(fw_gwake);
+
+	return ret;
+}
+
+static u8 gup_burn_fw_finish(struct i2c_client *client)
+{
+	u8 *fw_ss51 = NULL;
+	u8	retry = 0;
+	s32 ret = 0;
+
+	dev_info(&client->dev,
+		 "[burn_fw_finish]burn first 8K of ss51 and finish update.");
+	/* step1:alloc memory */
+	dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_ss51 == NULL) {
+			continue;
+		} else {
+			dev_dbg(&client->dev,
+				"[burn_fw_finish]Alloc %dk byte memory success.",
+				(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K.");
+	ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]load ss51 firmware section 1 fail.");
+		goto exit_burn_fw_finish;
+	}
+
+	dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]clear control flag fail.");
+		goto exit_burn_fw_finish;
+	}
+
+	dev_dbg(&client->dev,
+		"[burn_fw_finish]step4:burn ss51 firmware section 1");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+	if (ret == FAIL) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]burn ss51 firmware section 1 fail.");
+		goto exit_burn_fw_finish;
+	}
+
+	/* step11:enable download DSP code */
+	dev_dbg(&client->dev,
+		"[burn_fw_finish]step5:enable download DSP code ");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]enable download DSP code fail.");
+		goto exit_burn_fw_finish;
+	}
+
+	/* step12:release ss51 & hold dsp */
+	dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+	if (ret <= 0) {
+		dev_err(&client->dev,
+			"[burn_fw_finish]release ss51 & hold dsp fail.");
+		goto exit_burn_fw_finish;
+	}
+
+	if (fw_ss51 != NULL)
+		kfree(fw_ss51);
+	return SUCCESS;
+
+exit_burn_fw_finish:
+	if (fw_ss51 != NULL)
+		kfree(fw_ss51);
+
+	return FAIL;
+}
+
+/* return 0 can update, else no update condition */
+static int gup_update_condition_check(struct goodix_ts_data *ts)
+{
+	if (test_bit(SLEEP_MODE, &ts->flags)) {
+		dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+s32 gup_update_proc(void *dir)
+{
+	s32 ret = 0;
+	s32 update_ret = FAIL;
+	u8	retry = 0;
+	struct st_fw_head fw_head;
+	struct goodix_ts_data *ts = NULL;
+
+	ts = i2c_get_clientdata(i2c_connect_client);
+
+	dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n");
+
+	show_len = 1;
+	total_len = 100;
+
+	ret = gup_update_condition_check(ts);
+	if (ret) {
+		dev_warn(&ts->client->dev, "Update start failed\n");
+		return FAIL;
+	}
+
+	if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+		dev_warn(&ts->client->dev, "FW update may already running\n");
+		return FAIL;
+	}
+
+	ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+	if (ret == FAIL) {
+		dev_err(&ts->client->dev,
+			"Failed get valied firmware data\n");
+		clear_bit(FW_UPDATE_RUNNING, &ts->flags);
+		return FAIL;
+	}
+
+	gtp_work_control_enable(ts, false);
+	gtp_esd_off(ts);
+
+	ret = gup_get_ic_fw_msg(i2c_connect_client);
+	if (ret == FAIL) {
+		dev_err(&ts->client->dev, "[update_proc]get ic message fail.");
+		goto file_fail;
+	}
+
+	if (ts->force_update || dir) {
+		dev_dbg(&ts->client->dev, "Enter force update.");
+	} else {
+		ret = gup_enter_update_judge(i2c_connect_client, &fw_head);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]Doesn't meet update condition\n");
+			goto file_fail;
+		}
+	}
+
+	ret = gup_enter_update_mode(ts->client);
+	if (ret == FAIL) {
+		dev_err(&ts->client->dev,
+			"[update_proc]enter update mode fail.");
+		goto update_fail;
+	}
+
+	while (retry++ < 5) {
+		show_len = 10;
+		total_len = 100;
+		update_msg.fw_burned_len = 0;
+		ret = gup_burn_dsp_isp(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn dsp isp fail.");
+			continue;
+		}
+
+		show_len = 20;
+		ret = gup_burn_fw_gwake(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn app_code firmware fail.");
+			continue;
+		}
+
+		show_len = 30;
+		ret = gup_burn_fw_ss51(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn ss51 firmware fail.");
+			continue;
+		}
+
+		show_len = 40;
+		ret = gup_burn_fw_dsp(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn dsp firmware fail.");
+			continue;
+		}
+
+		show_len = 50;
+		ret = gup_burn_fw_boot(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn bootloader firmware fail.");
+			continue;
+		}
+		show_len = 60;
+
+		ret = gup_burn_fw_boot_isp(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn boot_isp firmware fail.");
+			continue;
+		}
+
+		show_len = 70;
+		ret = gup_burn_fw_link(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn link firmware fail.");
+			continue;
+		}
+
+		show_len = 80;
+		ret = gup_burn_fw_finish(i2c_connect_client);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+				"[update_proc]burn finish fail.");
+			continue;
+		}
+		show_len = 90;
+		dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS.");
+		retry = 0;
+		break;
+	}
+
+	if (retry >= 5) {
+		dev_err(&ts->client->dev,
+			"[update_proc]retry timeout,UPDATE FAIL.");
+		update_ret = FAIL;
+	} else {
+		update_ret = SUCCESS;
+	}
+
+update_fail:
+	dev_dbg(&ts->client->dev, "[update_proc]leave update mode.");
+	gup_leave_update_mode(i2c_connect_client);
+
+	msleep(GTP_100_DLY_MS);
+
+	if (update_ret == SUCCESS) {
+		dev_info(&ts->client->dev,
+			"firmware error auto update, resent config!\n");
+		gup_init_panel(ts);
+	}
+	gtp_get_fw_info(ts->client, &ts->fw_info);
+
+file_fail:
+
+	update_msg.fw_data = NULL;
+	update_msg.fw_total_len = 0;
+	release_firmware(update_msg.fw);
+
+	clear_bit(FW_UPDATE_RUNNING, &ts->flags);
+	gtp_work_control_enable(ts, true);
+	gtp_esd_on(ts);
+	total_len = 100;
+	ts->force_update = false;
+	if (update_ret == SUCCESS) {
+		show_len = 100;
+		clear_bit(FW_ERROR, &ts->flags);
+		return SUCCESS;
+	}
+
+	show_len = 200;
+	return FAIL;
+}
+
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+	struct task_struct *thread = NULL;
+
+	dev_info(&ts->client->dev, "Ready to run update thread.");
+
+	thread = kthread_run(gup_update_proc,
+			(void *)NULL, "guitar_update");
+
+	if (IS_ERR(thread)) {
+		dev_err(&ts->client->dev,
+				"Failed to create update thread.\n");
+		return -EPERM;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index a15ccdc..d3c39f9 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -1884,7 +1884,7 @@
 	}
 
 	rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK,
-		&g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ);
+		&g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc);
 		goto detach_smmu;
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index 2c364e01..4256064 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -153,4 +153,10 @@
 int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
 	void __iomem *icp_base, bool debug);
 
+/**
+ * cam_hfi_queue_dump() - utility function to dump hfi queues
+ */
+void cam_hfi_queue_dump(void);
+
+
 #endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index a0752f5..de72e85 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -47,6 +47,49 @@
 static DEFINE_MUTEX(hfi_cmd_q_mutex);
 static DEFINE_MUTEX(hfi_msg_q_mutex);
 
+void cam_hfi_queue_dump(void)
+{
+	struct hfi_qtbl *qtbl;
+	struct hfi_qtbl_hdr *qtbl_hdr;
+	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr;
+	struct hfi_mem_info *hfi_mem = NULL;
+	uint32_t *read_q, *read_ptr;
+	int i;
+
+	hfi_mem = &g_hfi->map;
+	if (!hfi_mem) {
+		CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL");
+		return;
+	}
+
+	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+	qtbl_hdr = &qtbl->q_tbl_hdr;
+	CAM_INFO(CAM_HFI,
+		"qtbl: version = %x size = %u num q = %u qhdr_size = %u",
+		qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size,
+		qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size);
+
+	cmd_q_hdr = &qtbl->q_hdr[Q_CMD];
+	CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x",
+		cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx,
+		cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova);
+	read_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+	read_ptr = (uint32_t *)(read_q + 0);
+	CAM_INFO(CAM_HFI, "CMD Q START");
+	for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++)
+		CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]);
+
+	msg_q_hdr = &qtbl->q_hdr[Q_MSG];
+	CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x",
+		msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx,
+		msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova);
+	read_q = (uint32_t *)g_hfi->map.msg_q.kva;
+	read_ptr = (uint32_t *)(read_q + 0);
+	CAM_INFO(CAM_HFI, "MSG Q START");
+	for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++)
+		CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]);
+}
+
 int hfi_write_cmd(void *cmd_ptr)
 {
 	uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp;
@@ -92,7 +135,8 @@
 		(q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) :
 		(read_idx - q->qhdr_write_idx);
 	if (empty_space <= size_in_words) {
-		CAM_ERR(CAM_HFI, "failed");
+		CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u",
+			empty_space, size_in_words);
 		rc = -EIO;
 		goto err;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 16e97ea..3c5690d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1833,7 +1833,7 @@
 
 	rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len);
 	if (rc) {
-		CAM_DBG(CAM_ICP, "Unable to read msg q");
+		CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc);
 	} else {
 		read_len = read_len << BYTE_WORD_SHIFT;
 		msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
@@ -2323,6 +2323,7 @@
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
 		CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command");
+		cam_hfi_queue_dump();
 	}
 
 	kfree(abort_cmd);
@@ -2379,6 +2380,7 @@
 		if (icp_hw_mgr.a5_debug_type ==
 			HFI_DEBUG_MODE_QUEUE)
 			cam_icp_mgr_process_dbg_buf();
+		cam_hfi_queue_dump();
 	}
 	kfree(destroy_cmd);
 	return rc;
@@ -2680,6 +2682,7 @@
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
 		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+		cam_hfi_queue_dump();
 	}
 	CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message");
 
@@ -2858,8 +2861,10 @@
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async *hfi_cmd;
 	struct cam_hw_update_entry *hw_update_entries;
+	struct icp_frame_info *frame_info = NULL;
 
-	request_id = *(uint64_t *)config_args->priv;
+	frame_info = (struct icp_frame_info *)config_args->priv;
+	request_id = frame_info->request_id;
 	hw_update_entries = config_args->hw_update_entries;
 	CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv);
 
@@ -2881,6 +2886,82 @@
 	return rc;
 }
 
+static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
+	uint32_t io_buf_addr)
+{
+	int rc = 0;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async ioconfig_cmd;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
+	struct crm_workq_task *task;
+	uint32_t size_in_words;
+
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task)
+		return -ENOMEM;
+
+	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
+	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+	else
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+	reinit_completion(&ctx_data->wait_complete);
+
+	ioconfig_cmd.num_fw_handles = 1;
+	ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
+	ioconfig_cmd.payload.indirect = io_buf_addr;
+	ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
+	ioconfig_cmd.user_data2 = (uint64_t)0x0;
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&ioconfig_cmd;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	size_in_words = (*(uint32_t *)task_data->data) >> 2;
+	CAM_INFO(CAM_ICP, "size_in_words %u", size_in_words);
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	if (rc)
+		return rc;
+
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+		msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+		cam_hfi_queue_dump();
+	}
+
+	return rc;
+}
+
+static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data,
+	struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id)
+{
+	int rc = 0;
+	struct hfi_cmd_work_data *task_data;
+	struct crm_workq_task *task;
+
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task)
+		return -ENOMEM;
+
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)ioconfig_cmd;
+	task_data->request_id = req_id;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
 static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
 {
 	int rc = 0;
@@ -2889,6 +2970,7 @@
 	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
 	struct cam_hw_config_args *config_args = config_hw_args;
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct icp_frame_info *frame_info = NULL;
 
 	if (!hw_mgr || !config_args) {
 		CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK",
@@ -2912,11 +2994,23 @@
 		return -EINVAL;
 	}
 
-	req_id = *(uint64_t *)config_args->priv;
+	frame_info = (struct icp_frame_info *)config_args->priv;
+	req_id = frame_info->request_id;
 	idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id);
 	ctx_data->hfi_frame_process.fw_process_flag[idx] = true;
 	cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx);
 
+	CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id,
+		frame_info->io_config);
+
+	if (frame_info->io_config != 0) {
+		CAM_INFO(CAM_ICP, "Send recfg io");
+		rc = cam_icp_mgr_send_recfg_io(ctx_data,
+			&frame_info->hfi_cfg_io_cmd, req_id);
+		if (rc)
+			CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd");
+	}
+
 	rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
 	if (rc)
 		goto config_err;
@@ -3147,7 +3241,9 @@
 	struct icp_cmd_generic_blob *blob;
 	struct cam_icp_hw_ctx_data *ctx_data;
 	uint32_t index;
+	size_t io_buf_size;
 	int rc = 0;
+	uint64_t pResource;
 
 	if (!blob_data || (blob_size == 0)) {
 		CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data,
@@ -3176,6 +3272,28 @@
 			clk_info->compressed_bw);
 		break;
 
+	case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO:
+		CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO");
+		pResource = *((uint32_t *)blob_data);
+		if (copy_from_user(&ctx_data->icp_dev_io_info,
+			(void __user *)pResource,
+			sizeof(struct cam_icp_acquire_dev_info))) {
+			CAM_ERR(CAM_ICP, "Failed in copy from user");
+			return -EFAULT;
+		}
+		CAM_DBG(CAM_ICP, "buf handle %d",
+			ctx_data->icp_dev_io_info.io_config_cmd_handle);
+		rc = cam_mem_get_io_buf(
+			ctx_data->icp_dev_io_info.io_config_cmd_handle,
+			icp_hw_mgr.iommu_hdl,
+			blob->io_buf_addr, &io_buf_size);
+		if (rc)
+			CAM_ERR(CAM_ICP, "Failed in blob update");
+		else
+			CAM_DBG(CAM_ICP, "io buf addr %llu",
+				*blob->io_buf_addr);
+		break;
+
 	default:
 		CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type);
 		break;
@@ -3186,7 +3304,8 @@
 static int cam_icp_process_generic_cmd_buffer(
 	struct cam_packet *packet,
 	struct cam_icp_hw_ctx_data *ctx_data,
-	int32_t index)
+	int32_t index,
+	uint64_t *io_buf_addr)
 {
 	int i, rc = 0;
 	struct cam_cmd_buf_desc *cmd_desc = NULL;
@@ -3194,6 +3313,7 @@
 
 	cmd_generic_blob.ctx = ctx_data;
 	cmd_generic_blob.frame_info_idx = index;
+	cmd_generic_blob.io_buf_addr = io_buf_addr;
 
 	cmd_desc = (struct cam_cmd_buf_desc *)
 		((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
@@ -3213,6 +3333,28 @@
 	return rc;
 }
 
+static int cam_icp_mgr_process_cfg_io_cmd(
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct hfi_cmd_ipebps_async *ioconfig_cmd,
+	uint64_t request_id,
+	uint64_t io_config)
+{
+	ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async);
+	ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+	else
+		ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+	ioconfig_cmd->num_fw_handles = 1;
+	ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle;
+	ioconfig_cmd->payload.indirect = io_config;
+	ioconfig_cmd->user_data1 = (uint64_t)ctx_data;
+	ioconfig_cmd->user_data2 = request_id;
+
+	return 0;
+}
+
 static int cam_icp_mgr_update_hfi_frame_process(
 	struct cam_icp_hw_ctx_data *ctx_data,
 	struct cam_packet *packet,
@@ -3220,6 +3362,7 @@
 	int32_t *idx)
 {
 	int32_t index, rc;
+	struct hfi_cmd_ipebps_async *hfi_cmd = NULL;
 
 	index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
 		ctx_data->hfi_frame_process.bits);
@@ -3231,15 +3374,27 @@
 
 	ctx_data->hfi_frame_process.request_id[index] =
 		packet->header.request_id;
-	rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index);
+	ctx_data->hfi_frame_process.frame_info[index].request_id =
+		packet->header.request_id;
+	ctx_data->hfi_frame_process.frame_info[index].io_config = 0;
+	rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index,
+		&ctx_data->hfi_frame_process.frame_info[index].io_config);
 	if (rc) {
 		clear_bit(index, ctx_data->hfi_frame_process.bitmap);
 		ctx_data->hfi_frame_process.request_id[index] = -1;
 		return rc;
 	}
+
+	if (ctx_data->hfi_frame_process.frame_info[index].io_config)  {
+		hfi_cmd = (struct hfi_cmd_ipebps_async *)&ctx_data->
+			hfi_frame_process.frame_info[index].hfi_cfg_io_cmd;
+		rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd,
+			packet->header.request_id, ctx_data->
+			hfi_frame_process.frame_info[index].io_config);
+	}
 	*idx = index;
 
-	return 0;
+	return rc;
 }
 
 static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv,
@@ -3320,7 +3475,7 @@
 
 	prepare_args->num_hw_update_entries = 1;
 	prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
-	prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+	prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx];
 
 	CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u",
 		packet->header.request_id, ctx_data->ctx_id);
@@ -3584,53 +3739,6 @@
 	return rc;
 }
 
-static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
-	uint32_t io_buf_addr)
-{
-	int rc = 0;
-	struct hfi_cmd_work_data *task_data;
-	struct hfi_cmd_ipebps_async ioconfig_cmd;
-	unsigned long rem_jiffies;
-	int timeout = 5000;
-	struct crm_workq_task *task;
-
-	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
-	if (!task)
-		return -ENOMEM;
-
-	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
-	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
-	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
-		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
-	else
-		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
-
-	reinit_completion(&ctx_data->wait_complete);
-	ioconfig_cmd.num_fw_handles = 1;
-	ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
-	ioconfig_cmd.payload.indirect = io_buf_addr;
-	ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
-	ioconfig_cmd.user_data2 = (uint64_t)0x0;
-	task_data = (struct hfi_cmd_work_data *)task->payload;
-	task_data->data = (void *)&ioconfig_cmd;
-	task_data->request_id = 0;
-	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
-	task->process_cb = cam_icp_mgr_process_cmd;
-	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
-		CRM_TASK_PRIORITY_0);
-	if (rc)
-		return rc;
-
-	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
-			msecs_to_jiffies((timeout)));
-	if (!rem_jiffies) {
-		rc = -ETIMEDOUT;
-		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
-	}
-
-	return rc;
-}
-
 static int cam_icp_mgr_create_handle(uint32_t dev_type,
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
@@ -3665,6 +3773,7 @@
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
 		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+		cam_hfi_queue_dump();
 	}
 
 	if (ctx_data->fw_handle == 0) {
@@ -3710,6 +3819,7 @@
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
 		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+		cam_hfi_queue_dump();
 	}
 
 	return rc;
@@ -3843,6 +3953,8 @@
 
 	icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
 
+	CAM_DBG(CAM_ICP, "acquire io buf handle %d",
+		icp_dev_acquire_info->io_config_cmd_handle);
 	rc = cam_mem_get_io_buf(
 		icp_dev_acquire_info->io_config_cmd_handle,
 		hw_mgr->iommu_hdl,
@@ -4134,21 +4246,22 @@
 	int i;
 
 	rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
-		&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
+		&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ,
+		0);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to create a command worker");
 		goto cmd_work_failed;
 	}
 
 	rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
-		&icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ);
+		&icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to create a message worker");
 		goto msg_work_failed;
 	}
 
 	rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK,
-		&icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ);
+		&icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to create a timer worker");
 		goto timer_work_failed;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 8746ee2..3e3c0e0 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -126,6 +126,19 @@
 };
 
 /**
+  * struct icp_frame_info
+  * @request_id: request id
+  * @io_config: the address of io config
+  * @hfi_cfg_io_cmd: command struct to be sent to hfi
+  */
+struct icp_frame_info {
+	uint64_t request_id;
+	uint64_t io_config;
+	struct hfi_cmd_ipebps_async hfi_cfg_io_cmd;
+};
+
+
+/**
  * struct hfi_frame_process_info
  * @hfi_frame_cmd: Frame process command info
  * @bitmap: Bitmap for hfi_frame_cmd
@@ -136,6 +149,7 @@
  * @out_resource: Out sync info
  * @fw_process_flag: Frame process flag
  * @clk_info: Clock information for a request
+ * @frame_info: information needed to process request
  */
 struct hfi_frame_process_info {
 	struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX];
@@ -149,6 +163,7 @@
 	uint32_t in_free_resource[CAM_FRAME_CMD_MAX];
 	uint32_t fw_process_flag[CAM_FRAME_CMD_MAX];
 	struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX];
+	struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX];
 };
 
 /**
@@ -189,6 +204,7 @@
  * @clk_info: Current clock info of a context
  * @watch_dog: watchdog timer handle
  * @watch_dog_reset_counter: Counter for watch dog reset
+ * @icp_dev_io_info: io config resource
  */
 struct cam_icp_hw_ctx_data {
 	void *context_priv;
@@ -208,16 +224,19 @@
 	struct cam_ctx_clk_info clk_info;
 	struct cam_req_mgr_timer *watch_dog;
 	uint32_t watch_dog_reset_counter;
+	struct cam_icp_acquire_dev_info icp_dev_io_info;
 };
 
 /**
  * struct icp_cmd_generic_blob
  * @ctx: Current context info
  * @frame_info_idx: Index used for frame process info
+ * @io_buf_addr: pointer to io buffer address
  */
 struct icp_cmd_generic_blob {
 	struct cam_icp_hw_ctx_data *ctx;
 	uint32_t frame_info_idx;
+	uint64_t *io_buf_addr;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index c1aa501..e5c54d6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -225,6 +225,8 @@
 				CAM_ERR(CAM_ISP, "Can not start HW resources");
 				goto err;
 			}
+			CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx,
+				isp_hw_res->hw_res[i]->res_id);
 		} else {
 			CAM_ERR(CAM_ISP, "function null");
 			goto err;
@@ -366,7 +368,8 @@
 			isp_res = hw_mgr_res->hw_res[i];
 			if (isp_res->hw_intf->hw_idx != base_idx)
 				continue;
-
+			CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u",
+				base_idx, isp_res->res_id, cnt);
 			stop_res[cnt] = isp_res;
 			cnt++;
 		}
@@ -483,8 +486,8 @@
 			"Add split id = %d for base idx = %d num_base=%d",
 			split_id, base_idx, ctx->num_base);
 	} else {
-		/*Check if base index is alreay exist in the list */
-		for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
+		/*Check if base index already exists in the list */
+		for (i = 0; i < ctx->num_base; i++) {
 			if (ctx->base[i].idx == base_idx) {
 				if (split_id != CAM_ISP_HW_SPLIT_MAX &&
 					ctx->base[i].split_id ==
@@ -495,7 +498,7 @@
 			}
 		}
 
-		if (i == CAM_IFE_HW_NUM_MAX) {
+		if (i == ctx->num_base) {
 			ctx->base[ctx->num_base].split_id = split_id;
 			ctx->base[ctx->num_base].idx      = base_idx;
 			ctx->num_base++;
@@ -845,7 +848,8 @@
 			}
 			ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
 			CAM_DBG(CAM_ISP,
-				"acquire success res type :0x%x res id:0x%x",
+				"acquire success IFE:%d  res type :0x%x res id:0x%x",
+				hw_intf->hw_idx,
 				ife_src_res->hw_res[i]->res_type,
 				ife_src_res->hw_res[i]->res_id);
 
@@ -871,29 +875,75 @@
 static int cam_ife_mgr_acquire_cid_res(
 	struct cam_ife_hw_mgr_ctx          *ife_ctx,
 	struct cam_isp_in_port_info        *in_port,
-	uint32_t                           *cid_res_id,
+	struct cam_ife_hw_mgr_res         **cid_res,
 	enum cam_ife_pix_path_res_id        csid_path)
 {
 	int rc = -1;
 	int i, j;
 	struct cam_ife_hw_mgr               *ife_hw_mgr;
-	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
+	struct cam_ife_hw_mgr_res           *cid_res_temp, *cid_res_iterator;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
+	uint32_t acquired_cnt = 0;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
+	*cid_res = NULL;
 
-	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
+	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-		goto err;
+		goto end;
 	}
-	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
+
+	cid_res_temp = *cid_res;
 
 	csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
 	csid_acquire.in_port = in_port;
 	csid_acquire.res_id =  csid_path;
+	CAM_DBG(CAM_ISP, "path %d", csid_path);
 
+	/* Try acquiring CID resource from previously acquired HW */
+	list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid,
+		list) {
+
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!cid_res_iterator->hw_res[i])
+				continue;
+
+			hw_intf = cid_res_iterator->hw_res[i]->hw_intf;
+			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+				&csid_acquire, sizeof(csid_acquire));
+			if (rc) {
+				CAM_DBG(CAM_ISP,
+					"No ife cid resource from hw %d",
+					hw_intf->hw_idx);
+				continue;
+			}
+
+			cid_res_temp->hw_res[acquired_cnt++] =
+				csid_acquire.node_res;
+
+			CAM_DBG(CAM_ISP,
+				"acquired csid(%s)=%d CID rsrc successfully",
+				(i == 0) ? "left" : "right",
+				hw_intf->hw_idx);
+
+			if (in_port->usage_type && acquired_cnt == 1 &&
+				csid_path == CAM_IFE_PIX_PATH_RES_IPP)
+				/* Continue to acquire Right */
+				continue;
+
+			if (acquired_cnt)
+				/*
+				 * If successfully acquired CID from
+				 * previously acquired HW, skip the next
+				 * part
+				 */
+				goto acquire_successful;
+		}
+	}
+
+	/* Acquire Left if not already acquired */
 	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
 		if (!ife_hw_mgr->csid_devices[i])
 			continue;
@@ -903,31 +953,45 @@
 			sizeof(csid_acquire));
 		if (rc)
 			continue;
-		else
+		else {
+			cid_res_temp->hw_res[acquired_cnt++] =
+				csid_acquire.node_res;
 			break;
+		}
 	}
 
 	if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
-		CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
-		goto err;
+		CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d",
+			csid_path);
+		goto put_res;
 	}
 
-	cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
-	cid_res->res_id = csid_acquire.node_res->res_id;
-	cid_res->is_dual_vfe = in_port->usage_type;
-	cid_res->hw_res[0] = csid_acquire.node_res;
-	cid_res->hw_res[1] = NULL;
-	/* CID(DT_ID) value of acquire device, require for path */
-	*cid_res_id = csid_acquire.node_res->res_id;
+acquire_successful:
+	CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d",
+		in_port->usage_type);
 
-	if (cid_res->is_dual_vfe) {
+	cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID;
+	/* CID(DT_ID) value of acquire device, require for path */
+	cid_res_temp->res_id = csid_acquire.node_res->res_id;
+	cid_res_temp->is_dual_vfe = in_port->usage_type;
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res);
+
+	/*
+	 * Acquire Right if not already acquired.
+	 * Dual IFE for RDI is not currently supported.
+	 */
+	if (cid_res_temp->is_dual_vfe && csid_path
+		== CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) {
 		csid_acquire.node_res = NULL;
 		csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
 		csid_acquire.in_port = in_port;
-		for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
+		for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
 			if (!ife_hw_mgr->csid_devices[j])
 				continue;
 
+			if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx)
+				continue;
+
 			hw_intf = ife_hw_mgr->csid_devices[j];
 			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
 				&csid_acquire, sizeof(csid_acquire));
@@ -940,16 +1004,20 @@
 		if (j == CAM_IFE_CSID_HW_NUM_MAX) {
 			CAM_ERR(CAM_ISP,
 				"Can not acquire ife csid rdi resource");
-			goto err;
+			goto end;
 		}
-		cid_res->hw_res[1] = csid_acquire.node_res;
+		cid_res_temp->hw_res[1] = csid_acquire.node_res;
+		CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d",
+			in_port->usage_type);
 	}
-	cid_res->parent = &ife_ctx->res_list_ife_in;
+	cid_res_temp->parent = &ife_ctx->res_list_ife_in;
 	ife_ctx->res_list_ife_in.child[
-		ife_ctx->res_list_ife_in.num_children++] = cid_res;
+		ife_ctx->res_list_ife_in.num_children++] = cid_res_temp;
 
 	return 0;
-err:
+put_res:
+	cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res);
+end:
 	return rc;
 
 }
@@ -966,35 +1034,25 @@
 	struct cam_ife_hw_mgr_res           *csid_res;
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
-	uint32_t                             cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
+	ife_hw_mgr = ife_ctx->hw_mgr;
 	/* get cid resource */
-	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
 		CAM_IFE_PIX_PATH_RES_IPP);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
-		goto err;
+		goto end;
 	}
 
-	ife_hw_mgr = ife_ctx->hw_mgr;
-
 	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-		goto err;
+		goto end;
 	}
-	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
-
-	csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
-	csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP;
-	csid_acquire.cid = cid_res_id;
-	csid_acquire.in_port = in_port;
-	csid_acquire.out_port = in_port->data;
 
 	csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH;
 	csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP;
-	csid_res->is_dual_vfe = in_port->usage_type;
 
 	if (in_port->usage_type)
 		csid_res->is_dual_vfe = 1;
@@ -1003,66 +1061,60 @@
 		csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
 	}
 
-	list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid,
-		list) {
-		if (cid_res->res_id != cid_res_id)
-			continue;
+	/* IPP resource needs to be from same HW as CID resource */
+	for (i = 0; i <= csid_res->is_dual_vfe; i++) {
+		CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe);
+		csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
+		csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP;
+		csid_acquire.cid = cid_res->hw_res[i]->res_id;
+		csid_acquire.in_port = in_port;
+		csid_acquire.out_port = in_port->data;
+		csid_acquire.node_res = NULL;
 
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!cid_res->hw_res[i])
-				continue;
+		hw_intf = cid_res->hw_res[i]->hw_intf;
 
-			hw_intf = ife_hw_mgr->csid_devices[
-				cid_res->hw_res[i]->hw_intf->hw_idx];
-
-			csid_acquire.node_res = NULL;
-			if (csid_res->is_dual_vfe) {
-				if (i == CAM_ISP_HW_SPLIT_LEFT) {
-					master_idx = hw_intf->hw_idx;
-					csid_acquire.sync_mode =
-						CAM_ISP_HW_SYNC_MASTER;
-				} else {
-					if (master_idx == -1) {
-						CAM_ERR(CAM_ISP,
-							"No Master found");
-						goto err;
-					}
-					csid_acquire.sync_mode =
-						CAM_ISP_HW_SYNC_SLAVE;
-					csid_acquire.master_idx = master_idx;
+		if (csid_res->is_dual_vfe) {
+			if (i == CAM_ISP_HW_SPLIT_LEFT) {
+				master_idx = hw_intf->hw_idx;
+				csid_acquire.sync_mode =
+					CAM_ISP_HW_SYNC_MASTER;
+			} else {
+				if (master_idx == -1) {
+					CAM_ERR(CAM_ISP,
+						"No Master found");
+					goto put_res;
 				}
+				csid_acquire.sync_mode =
+					CAM_ISP_HW_SYNC_SLAVE;
+				csid_acquire.master_idx = master_idx;
 			}
-
-			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-				&csid_acquire, sizeof(csid_acquire));
-			if (rc) {
-				CAM_ERR(CAM_ISP,
-					"Cannot acquire ife csid ipp resource");
-				goto err;
-			}
-
-			csid_res->hw_res[i] = csid_acquire.node_res;
-			CAM_DBG(CAM_ISP,
-				"acquired csid(%s)=%d ipp rsrc successfully",
-				(i == 0) ? "left" : "right",
-				hw_intf->hw_idx);
-
 		}
 
-		if (i == CAM_IFE_CSID_HW_NUM_MAX) {
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+			&csid_acquire, sizeof(csid_acquire));
+		if (rc) {
 			CAM_ERR(CAM_ISP,
-				"Can not acquire ife csid ipp resource");
-			goto err;
+				"Cannot acquire ife csid ipp resource");
+			goto put_res;
 		}
 
-		csid_res->parent = cid_res;
-		cid_res->child[cid_res->num_children++] = csid_res;
+		csid_res->hw_res[i] = csid_acquire.node_res;
+		CAM_DBG(CAM_ISP,
+			"acquired csid(%s)=%d ipp rsrc successfully",
+			(i == 0) ? "left" : "right",
+			hw_intf->hw_idx);
 	}
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
+
+	csid_res->parent = cid_res;
+	cid_res->child[cid_res->num_children++] = csid_res;
 
 	CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id);
 
 	return 0;
-err:
+put_res:
+	cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
+end:
 	return rc;
 }
 
@@ -1099,111 +1151,88 @@
 	struct cam_ife_hw_mgr_ctx     *ife_ctx,
 	struct cam_isp_in_port_info   *in_port)
 {
-	int rc = -1;
-	int i, j;
+	int rc = -EINVAL;
+	int i;
 
 	struct cam_ife_hw_mgr               *ife_hw_mgr;
 	struct cam_ife_hw_mgr_res           *csid_res;
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
 	struct cam_isp_out_port_info        *out_port;
-	uint32_t                             cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
+	enum cam_ife_pix_path_res_id         path_type;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
 
 	for (i = 0; i < in_port->num_out_res; i++) {
 		out_port = &in_port->data[i];
-		if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
+		path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+			out_port->res_type);
+		if (path_type == CAM_IFE_PIX_PATH_RES_MAX)
 			continue;
 
-			/* get cid resource */
-			rc = cam_ife_mgr_acquire_cid_res(ife_ctx,
-				in_port, &cid_res_id,
-				cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
-				out_port->res_type));
-			if (rc) {
-				CAM_ERR(CAM_ISP,
-					"Acquire IFE CID resource Failed");
-				goto err;
+		/* get cid resource */
+		rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
+			path_type);
+		if (rc) {
+			CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+			goto end;
 		}
 
+		/* For each RDI we need CID + PATH resource */
 		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
 			&csid_res);
 		if (rc) {
 			CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-			goto err;
+			goto end;
 		}
-		cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
-
-		/*
-		 * no need to check since we are doing one to one mapping
-		 * between the csid rdi type and out port rdi type
-		 */
 
 		memset(&csid_acquire, 0, sizeof(csid_acquire));
-		csid_acquire.res_id =
-			cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
-				out_port->res_type);
+		csid_acquire.res_id = path_type;
 
 		csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
-		csid_acquire.cid = cid_res_id;
+		csid_acquire.cid = cid_res->hw_res[0]->res_id;
 		csid_acquire.in_port = in_port;
 		csid_acquire.out_port = out_port;
 		csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
+		csid_acquire.node_res = NULL;
 
-		list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid,
-			list) {
-			if (cid_res->res_id != cid_res_id)
-				continue;
+		hw_intf = cid_res->hw_res[0]->hw_intf;
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+			&csid_acquire, sizeof(csid_acquire));
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"CSID Path reserve failed hw=%d rc=%d cid=%d",
+				hw_intf->hw_idx, rc,
+				cid_res->hw_res[0]->res_id);
 
-			for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
-				if (!cid_res->hw_res[j])
-					continue;
-
-				csid_acquire.node_res = NULL;
-
-				hw_intf = ife_hw_mgr->csid_devices[
-					cid_res->hw_res[j]->hw_intf->hw_idx];
-				rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-					&csid_acquire, sizeof(csid_acquire));
-				if (rc) {
-					CAM_DBG(CAM_ISP,
-					 "CSID Path reserve failed hw=%d rc=%d",
-					 hw_intf->hw_idx, rc);
-					continue;
-				}
-
-				/* RDI does not need Dual ISP. Break */
-				break;
-			}
-
-			if (j == CAM_ISP_HW_SPLIT_MAX &&
-				csid_acquire.node_res == NULL) {
-				CAM_ERR(CAM_ISP,
-					"acquire csid rdi rsrc failed, cid %d",
-					cid_res_id);
-				goto err;
-			}
-
-			csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH;
-			csid_res->res_id = csid_acquire.res_id;
-			csid_res->is_dual_vfe = 0;
-			csid_res->hw_res[0] = csid_acquire.node_res;
-			csid_res->hw_res[1] = NULL;
-			CAM_DBG(CAM_ISP, "acquire res %d",
-				csid_acquire.res_id);
-			csid_res->parent = cid_res;
-			cid_res->child[cid_res->num_children++] =
-				csid_res;
-
-			/* Done with cid_res_id. Break */
-			break;
+			goto put_res;
 		}
+
+		if (csid_acquire.node_res == NULL) {
+			CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed");
+
+			goto put_res;
+		}
+
+		csid_res->res_type = (enum cam_ife_hw_mgr_res_type)
+			CAM_ISP_RESOURCE_PIX_PATH;
+		csid_res->res_id = csid_acquire.res_id;
+		csid_res->is_dual_vfe = 0;
+		csid_res->hw_res[0] = csid_acquire.node_res;
+		csid_res->hw_res[1] = NULL;
+		CAM_DBG(CAM_ISP, "acquire res %d",
+			csid_acquire.res_id);
+		csid_res->parent = cid_res;
+		cid_res->child[cid_res->num_children++] =
+			csid_res;
+		cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
 	}
 
 	return 0;
-err:
+put_res:
+	cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
+end:
 	return rc;
 }
 
@@ -1870,6 +1899,24 @@
 	 */
 	if (i == ctx->num_base)
 		master_base_idx = ctx->base[0].idx;
+	CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);
+
+	/* Stop the master CSID path first */
+	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
+		master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+
+	/* stop rest of the CSID paths  */
+	for (i = 0; i < ctx->num_base; i++) {
+		if (ctx->base[i].idx == master_base_idx)
+			continue;
+		CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d",
+			ctx->base[i].idx, i, master_base_idx);
+
+		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
+			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+	}
+
+	CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx);
 
 	/* Stop the master CIDs first */
 	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
@@ -1877,26 +1924,14 @@
 
 	/* stop rest of the CIDs  */
 	for (i = 0; i < ctx->num_base; i++) {
-		if (i == master_base_idx)
+		if (ctx->base[i].idx == master_base_idx)
 			continue;
+		CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d",
+			ctx->base[i].idx, i, master_base_idx);
 		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
 			ctx->base[i].idx, csid_halt_type);
 	}
 
-	/* Stop the master CSID path first */
-	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-			master_base_idx, csid_halt_type);
-
-	/* stop rest of the CSID paths  */
-	for (i = 0; i < ctx->num_base; i++) {
-		if (i == master_base_idx)
-			continue;
-
-		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-			ctx->base[i].idx, csid_halt_type);
-	}
-
-
 	/* Deinit IFE CID */
 	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
 		CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
@@ -4218,7 +4253,7 @@
 
 	/* Create Worker for ife_hw_mgr with 10 tasks */
 	rc = cam_req_mgr_workq_create("cam_ife_worker", 10,
-			&g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ);
+			&g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0);
 	if (rc < 0) {
 		CAM_ERR(CAM_ISP, "Unable to create worker");
 		goto end;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index e869e2b..1444911 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -70,6 +70,12 @@
 			hw_entry[num_ent].handle = kmd_buf_info->handle;
 			hw_entry[num_ent].len    = get_base.cmd.used_bytes;
 			hw_entry[num_ent].offset = kmd_buf_info->offset;
+			CAM_DBG(CAM_ISP,
+				"num_ent=%d handle=0x%x, len=%u, offset=%u",
+				num_ent,
+				hw_entry[num_ent].handle,
+				hw_entry[num_ent].len,
+				hw_entry[num_ent].offset);
 
 			kmd_buf_info->used_bytes += get_base.cmd.used_bytes;
 			kmd_buf_info->offset     += get_base.cmd.used_bytes;
@@ -184,6 +190,16 @@
 		return -EINVAL;
 	}
 
+	cmd_update.cmd_type = hw_cmd_type;
+	cmd_update.cmd.cmd_buf_addr = cmd_buf_addr;
+	cmd_update.cmd.size = kmd_buf_remain_size;
+	cmd_update.cmd.used_bytes = 0;
+	cmd_update.data = cmd_update_data;
+	CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d",
+		cmd_update.cmd_type,
+		cmd_update.cmd.cmd_buf_addr,
+		cmd_update.cmd.size);
+
 	for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
 		if (!hw_mgr_res->hw_res[i])
 			continue;
@@ -193,14 +209,7 @@
 
 		res = hw_mgr_res->hw_res[i];
 		cmd_update.res = res;
-		cmd_update.cmd_type = hw_cmd_type;
-		cmd_update.cmd.cmd_buf_addr = cmd_buf_addr;
-		cmd_update.cmd.size = kmd_buf_remain_size;
-		cmd_update.data = cmd_update_data;
 
-		CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d",
-			cmd_update.cmd.cmd_buf_addr,
-			cmd_update.cmd.size);
 		rc = res->hw_intf->hw_ops.process_cmd(
 			res->hw_intf->hw_priv,
 			cmd_update.cmd_type, &cmd_update,
@@ -280,6 +289,12 @@
 				hw_entry[num_ent].handle =
 					cmd_desc[i].mem_handle;
 				hw_entry[num_ent].offset = cmd_desc[i].offset;
+				CAM_DBG(CAM_ISP,
+					"Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u",
+					num_ent,
+					hw_entry[num_ent].handle,
+					hw_entry[num_ent].len,
+					hw_entry[num_ent].offset);
 
 				if (cmd_meta_data ==
 					CAM_ISP_PACKET_META_DMI_LEFT)
@@ -295,6 +310,12 @@
 				hw_entry[num_ent].handle =
 					cmd_desc[i].mem_handle;
 				hw_entry[num_ent].offset = cmd_desc[i].offset;
+				CAM_DBG(CAM_ISP,
+					"Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u",
+					num_ent,
+					hw_entry[num_ent].handle,
+					hw_entry[num_ent].len,
+					hw_entry[num_ent].offset);
 
 				if (cmd_meta_data ==
 					CAM_ISP_PACKET_META_DMI_RIGHT)
@@ -308,7 +329,12 @@
 			hw_entry[num_ent].handle =
 				cmd_desc[i].mem_handle;
 			hw_entry[num_ent].offset = cmd_desc[i].offset;
-
+			CAM_DBG(CAM_ISP,
+				"Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u",
+				num_ent,
+				hw_entry[num_ent].handle,
+				hw_entry[num_ent].len,
+				hw_entry[num_ent].offset);
 			if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON)
 				hw_entry[num_ent].flags = 0x1;
 
@@ -647,6 +673,12 @@
 		prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes;
 		prepare->hw_update_entries[num_ent].offset =
 			kmd_buf_info->offset;
+		CAM_DBG(CAM_ISP,
+			"num_ent=%d handle=0x%x, len=%u, offset=%u",
+			num_ent,
+			prepare->hw_update_entries[num_ent].handle,
+			prepare->hw_update_entries[num_ent].len,
+			prepare->hw_update_entries[num_ent].offset);
 		num_ent++;
 
 		kmd_buf_info->used_bytes += io_cfg_used_bytes;
@@ -741,6 +773,12 @@
 		prepare->hw_update_entries[num_ent].len = reg_update_size;
 		prepare->hw_update_entries[num_ent].offset =
 			kmd_buf_info->offset;
+		CAM_DBG(CAM_ISP,
+			"num_ent=%d handle=0x%x, len=%u, offset=%u",
+			num_ent,
+			prepare->hw_update_entries[num_ent].handle,
+			prepare->hw_update_entries[num_ent].len,
+			prepare->hw_update_entries[num_ent].offset);
 		num_ent++;
 
 		kmd_buf_info->used_bytes += reg_update_size;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 3edae4a..29b9e11 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -20,6 +20,7 @@
 #include "cam_soc_util.h"
 #include "cam_io_util.h"
 #include "cam_debug_util.h"
+#include "cam_cpas_api.h"
 
 /* Timeout value in msec */
 #define IFE_CSID_TIMEOUT                               1000
@@ -286,67 +287,49 @@
 }
 
 static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
-	struct cam_isp_resource_node **res, int32_t vc, uint32_t dt,
-	uint32_t res_type)
+	struct cam_isp_resource_node **res, int32_t vc, uint32_t dt)
 {
-	int  rc = 0;
 	struct cam_ife_csid_cid_data    *cid_data;
-	uint32_t  i = 0, j = 0;
+	uint32_t  i = 0;
 
+	*res = NULL;
+
+	/* Return already reserved CID if the VC/DT matches */
 	for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
 		if (csid_hw->cid_res[i].res_state >=
 			CAM_ISP_RESOURCE_STATE_RESERVED) {
 			cid_data = (struct cam_ife_csid_cid_data *)
 				csid_hw->cid_res[i].res_priv;
-			if (res_type == CAM_ISP_IFE_IN_RES_TPG) {
-				if (cid_data->tpg_set) {
-					cid_data->cnt++;
-					*res = &csid_hw->cid_res[i];
-					break;
-				}
-			} else {
-				if (cid_data->vc == vc && cid_data->dt == dt) {
-					cid_data->cnt++;
-					*res = &csid_hw->cid_res[i];
-					break;
-				}
+			if (cid_data->vc == vc && cid_data->dt == dt) {
+				cid_data->cnt++;
+				*res = &csid_hw->cid_res[i];
+				return 0;
 			}
 		}
 	}
 
-	if (i == CAM_IFE_CSID_CID_RES_MAX) {
-		if (res_type == CAM_ISP_IFE_IN_RES_TPG) {
-			CAM_ERR(CAM_ISP, "CSID:%d TPG CID not available",
-				 csid_hw->hw_intf->hw_idx);
-			rc = -EINVAL;
-		}
-
-		for (j = 0; j < CAM_IFE_CSID_CID_RES_MAX; j++) {
-			if (csid_hw->cid_res[j].res_state ==
-				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
-				cid_data = (struct cam_ife_csid_cid_data *)
-					csid_hw->cid_res[j].res_priv;
-				cid_data->vc  = vc;
-				cid_data->dt  = dt;
-				cid_data->cnt = 1;
-				csid_hw->cid_res[j].res_state =
-					CAM_ISP_RESOURCE_STATE_RESERVED;
-				*res = &csid_hw->cid_res[j];
-				CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated",
-					csid_hw->hw_intf->hw_idx,
-					csid_hw->cid_res[j].res_id);
-				break;
-			}
-		}
-
-		if (j == CAM_IFE_CSID_CID_RES_MAX) {
-			CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available",
-				 csid_hw->hw_intf->hw_idx);
-			rc = -EINVAL;
+	for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
+		if (csid_hw->cid_res[i].res_state ==
+			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+			cid_data = (struct cam_ife_csid_cid_data *)
+				csid_hw->cid_res[i].res_priv;
+			cid_data->vc  = vc;
+			cid_data->dt  = dt;
+			cid_data->cnt = 1;
+			csid_hw->cid_res[i].res_state =
+				CAM_ISP_RESOURCE_STATE_RESERVED;
+			*res = &csid_hw->cid_res[i];
+			CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated",
+				csid_hw->hw_intf->hw_idx,
+				csid_hw->cid_res[i].res_id);
+			return 0;
 		}
 	}
 
-	return rc;
+	CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available",
+		 csid_hw->hw_intf->hw_idx);
+
+	return -EINVAL;
 }
 
 
@@ -547,6 +530,7 @@
 {
 	int rc = 0;
 	struct cam_ife_csid_cid_data       *cid_data;
+	uint32_t camera_hw_version;
 
 	CAM_DBG(CAM_ISP,
 		"CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d",
@@ -614,12 +598,40 @@
 		goto end;
 	}
 
-	if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 &&
-		csid_hw->hw_intf->hw_idx != 2) {
+	if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
+		CAM_ERR(CAM_ISP,
+			"CSID%d reserve cnt reached max",
+			csid_hw->hw_intf->hw_idx);
 		rc = -EINVAL;
 		goto end;
 	}
 
+	rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc);
+		goto end;
+	}
+	CAM_DBG(CAM_ISP, "HW version: %d", camera_hw_version);
+
+	switch (camera_hw_version) {
+	case CAM_CPAS_TITAN_NONE:
+	case CAM_CPAS_TITAN_MAX:
+		CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version);
+		break;
+	case CAM_CPAS_TITAN_170_V100:
+	case CAM_CPAS_TITAN_170_V110:
+	case CAM_CPAS_TITAN_170_V120:
+		if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 &&
+			csid_hw->hw_intf->hw_idx != 2) {
+			rc = -EINVAL;
+			goto end;
+		}
+		break;
+	default:
+		break;
+	}
+	CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt);
+
 	if (csid_hw->csi2_reserve_cnt) {
 		/* current configure res type should match requested res type */
 		if (csid_hw->res_type != cid_reserv->in_port->res_type) {
@@ -652,12 +664,53 @@
 		}
 	}
 
+	switch (cid_reserv->res_id) {
+	case CAM_IFE_PIX_PATH_RES_IPP:
+		if (csid_hw->ipp_res.res_state !=
+			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+			CAM_DBG(CAM_ISP,
+				"CSID:%d IPP resource not available",
+				csid_hw->hw_intf->hw_idx);
+			rc = -EINVAL;
+			goto end;
+		}
+		break;
+	case CAM_IFE_PIX_PATH_RES_RDI_0:
+	case CAM_IFE_PIX_PATH_RES_RDI_1:
+	case CAM_IFE_PIX_PATH_RES_RDI_2:
+	case CAM_IFE_PIX_PATH_RES_RDI_3:
+		if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
+			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+			CAM_ERR(CAM_ISP,
+				"CSID:%d RDI:%d resource not available",
+				csid_hw->hw_intf->hw_idx,
+				cid_reserv->res_id);
+			rc = -EINVAL;
+			goto end;
+		}
+		break;
+	default:
+		CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
+			csid_hw->hw_intf->hw_idx);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = cam_ife_csid_cid_get(csid_hw,
+		&cid_reserv->node_res,
+		cid_reserv->in_port->vc,
+		cid_reserv->in_port->dt);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d",
+			csid_hw->hw_intf->hw_idx,
+			cid_reserv->in_port->res_type);
+		goto end;
+	}
+	cid_data = (struct cam_ife_csid_cid_data *)
+		cid_reserv->node_res->res_priv;
+
 	if (!csid_hw->csi2_reserve_cnt) {
 		csid_hw->res_type = cid_reserv->in_port->res_type;
-		/* Take the first CID resource*/
-		csid_hw->cid_res[0].res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
-		cid_data = (struct cam_ife_csid_cid_data *)
-				csid_hw->cid_res[0].res_priv;
 
 		csid_hw->csi2_rx_cfg.lane_cfg =
 			cid_reserv->in_port->lane_cfg;
@@ -699,71 +752,13 @@
 			csid_hw->csi2_rx_cfg.phy_sel =
 				(cid_reserv->in_port->res_type & 0xFF) - 1;
 		}
-
-		cid_data->vc = cid_reserv->in_port->vc;
-		cid_data->dt = cid_reserv->in_port->dt;
-		cid_data->cnt = 1;
-		cid_reserv->node_res = &csid_hw->cid_res[0];
-		csid_hw->csi2_reserve_cnt++;
-
-		CAM_DBG(CAM_ISP,
-			"CSID:%d CID :%d resource acquired successfully",
-			csid_hw->hw_intf->hw_idx,
-			cid_reserv->node_res->res_id);
-	} else {
-		switch (cid_reserv->res_id) {
-		case CAM_IFE_PIX_PATH_RES_IPP:
-			if (csid_hw->ipp_res.res_state !=
-				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
-				CAM_DBG(CAM_ISP,
-					"CSID:%d IPP resource not available",
-					csid_hw->hw_intf->hw_idx);
-				rc = -EINVAL;
-				goto end;
-			}
-			break;
-		case CAM_IFE_PIX_PATH_RES_RDI_0:
-		case CAM_IFE_PIX_PATH_RES_RDI_1:
-		case CAM_IFE_PIX_PATH_RES_RDI_2:
-		case CAM_IFE_PIX_PATH_RES_RDI_3:
-			if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
-				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
-				CAM_DBG(CAM_ISP,
-					"CSID:%d RDI:%d resource not available",
-					csid_hw->hw_intf->hw_idx,
-					cid_reserv->res_id);
-				rc = -EINVAL;
-				goto end;
-			}
-			break;
-		default:
-			CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
-				csid_hw->hw_intf->hw_idx);
-			rc = -EINVAL;
-			goto end;
-		}
-
-		rc = cam_ife_csid_cid_get(csid_hw,
-			&cid_reserv->node_res,
-			cid_reserv->in_port->vc,
-			cid_reserv->in_port->dt,
-			cid_reserv->in_port->res_type);
-		/* if success then increment the reserve count */
-		if (!rc) {
-			if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
-				CAM_ERR(CAM_ISP,
-					"CSID%d reserve cnt reached max",
-					csid_hw->hw_intf->hw_idx);
-				rc = -EINVAL;
-			} else {
-				csid_hw->csi2_reserve_cnt++;
-				CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired",
-					csid_hw->hw_intf->hw_idx,
-					cid_reserv->node_res->res_id);
-			}
-		}
 	}
 
+	csid_hw->csi2_reserve_cnt++;
+	CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired",
+		csid_hw->hw_intf->hw_idx,
+		cid_reserv->node_res->res_id);
+
 end:
 	return rc;
 }
@@ -2415,12 +2410,24 @@
 		return -EINVAL;
 	}
 	csid_stop = (struct cam_csid_hw_stop_args  *) stop_args;
+
+	if (!csid_stop->num_res) {
+		CAM_ERR(CAM_ISP, "CSID: Invalid args");
+		return -EINVAL;
+	}
+
 	csid_hw_info = (struct cam_hw_info  *)hw_priv;
 	csid_hw = (struct cam_ife_csid_hw   *)csid_hw_info->core_info;
+	CAM_DBG(CAM_ISP, "CSID:%d num_res %d",
+		csid_hw->hw_intf->hw_idx,
+		csid_stop->num_res);
 
 	/* Stop the resource first */
 	for (i = 0; i < csid_stop->num_res; i++) {
 		res = csid_stop->node_res[i];
+		CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d",
+			csid_hw->hw_intf->hw_idx,
+			res->res_type, res->res_id);
 		switch (res->res_type) {
 		case CAM_ISP_RESOURCE_CID:
 			if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG)
@@ -2777,6 +2784,7 @@
 {
 	int rc = -EINVAL;
 	uint32_t i;
+	uint32_t num_paths;
 	struct cam_ife_csid_path_cfg         *path_data;
 	struct cam_ife_csid_cid_data         *cid_data;
 	struct cam_hw_info                   *csid_hw_info;
@@ -2828,8 +2836,10 @@
 	ife_csid_hw->hw_intf->hw_ops.write       = cam_ife_csid_write;
 	ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd;
 
-	/*Initialize the CID resoure */
-	for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
+	num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->no_pix +
+		ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis;
+	/* Initialize the CID resource */
+	for (i = 0; i < num_paths; i++) {
 		ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID;
 		ife_csid_hw->cid_res[i].res_id = i;
 		ife_csid_hw->cid_res[i].res_state  =
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 97d076a..fdeee54 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1171,7 +1171,7 @@
 		"jpeg_command_queue",
 		CAM_JPEG_WORKQ_NUM_TASK,
 		&g_jpeg_hw_mgr.work_process_frame,
-		CRM_WORKQ_USAGE_NON_IRQ);
+		CRM_WORKQ_USAGE_NON_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc);
 		goto work_process_frame_failed;
@@ -1181,7 +1181,7 @@
 		"jpeg_message_queue",
 		CAM_JPEG_WORKQ_NUM_TASK,
 		&g_jpeg_hw_mgr.work_process_irq_cb,
-		CRM_WORKQ_USAGE_IRQ);
+		CRM_WORKQ_USAGE_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc);
 		goto work_process_irq_cb_failed;
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
index a60661e..0f34c9f 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
@@ -989,7 +989,8 @@
 	CAM_DBG(CAM_LRME, "Create submit workq for %s", buf);
 	rc = cam_req_mgr_workq_create(buf,
 		CAM_LRME_WORKQ_NUM_TASK,
-		&hw_device->work, CRM_WORKQ_USAGE_NON_IRQ);
+		&hw_device->work, CRM_WORKQ_USAGE_NON_IRQ,
+		0);
 	if (rc) {
 		CAM_ERR(CAM_LRME,
 			"Unable to create a worker, rc=%d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
index da42c84..ec392f5 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,8 +28,6 @@
 #include "cam_mem_mgr_api.h"
 #include "cam_smmu_api.h"
 
-#define CAM_LRME_HW_WORKQ_NUM_TASK 30
-
 static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core,
 	struct cam_hw_info *lrme_hw)
 {
@@ -122,7 +120,7 @@
 
 	rc = cam_req_mgr_workq_create("cam_lrme_hw_worker",
 		CAM_LRME_HW_WORKQ_NUM_TASK,
-		&lrme_core->work, CRM_WORKQ_USAGE_IRQ);
+		&lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0);
 	if (rc) {
 		CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc);
 		goto free_memory;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 4602d6c..060aaf2 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -2324,6 +2324,7 @@
 int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info)
 {
 	int                                     rc = 0;
+	int                                     wq_flag = 0;
 	char                                    buf[128];
 	struct cam_create_dev_hdl               root_dev;
 	struct cam_req_mgr_core_session        *cam_session;
@@ -2394,8 +2395,9 @@
 	/* Create worker for current link */
 	snprintf(buf, sizeof(buf), "%x-%x",
 		link_info->session_hdl, link->link_hdl);
+	wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL;
 	rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS,
-		&link->workq, CRM_WORKQ_USAGE_NON_IRQ);
+		&link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag);
 	if (rc < 0) {
 		CAM_ERR(CAM_CRM, "FATAL: unable to create worker");
 		__cam_req_mgr_destroy_link_info(link);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index 066efd6..3798ef8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -178,9 +178,10 @@
 }
 
 int cam_req_mgr_workq_create(char *name, int32_t num_tasks,
-	struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq)
+	struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq,
+	int flags)
 {
-	int32_t i;
+	int32_t i, wq_flags = 0, max_active_tasks = 0;
 	struct crm_workq_task  *task;
 	struct cam_req_mgr_core_workq *crm_workq = NULL;
 	char buf[128] = "crm_workq-";
@@ -192,10 +193,17 @@
 		if (crm_workq == NULL)
 			return -ENOMEM;
 
+		wq_flags |= WQ_UNBOUND;
+		if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY)
+			wq_flags |= WQ_HIGHPRI;
+
+		if (flags & CAM_WORKQ_FLAG_SERIAL)
+			max_active_tasks = 1;
+
 		strlcat(buf, name, sizeof(buf));
 		CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name);
 		crm_workq->job = alloc_workqueue(buf,
-			WQ_HIGHPRI | WQ_UNBOUND, 0, NULL);
+			wq_flags, max_active_tasks, NULL);
 		if (!crm_workq->job) {
 			kfree(crm_workq);
 			return -ENOMEM;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
index eb3b804..af76ae46 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -23,6 +23,15 @@
 
 #include "cam_req_mgr_core.h"
 
+/* Flag to create a high priority workq */
+#define CAM_WORKQ_FLAG_HIGH_PRIORITY             (1 << 0)
+
+/* This flag ensures only one task from a given
+ * workq will execute at any given point on any
+ * given CPU.
+ */
+#define CAM_WORKQ_FLAG_SERIAL                    (1 << 1)
+
 /* Task priorities, lower the number higher the priority*/
 enum crm_task_priority {
 	CRM_TASK_PRIORITY_0,
@@ -101,11 +110,14 @@
  * @num_task : Num_tasks to be allocated for workq
  * @workq    : Double pointer worker
  * @in_irq   : Set to one if workq might be used in irq context
+ * @flags    : Bitwise OR of Flags for workq behavior.
+ *             e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL
  * This function will allocate and create workqueue and pass
  * the workq pointer to caller.
  */
 int cam_req_mgr_workq_create(char *name, int32_t num_tasks,
-	struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq);
+	struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq,
+	int flags);
 
 /**
  * cam_req_mgr_workq_destroy()
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index a34d70c..da8ff21 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -53,6 +53,7 @@
 
 free_power_settings:
 	kfree(power_info->power_setting);
+	power_info->power_setting = NULL;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index 96fdfeb..733c9e8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -252,6 +252,8 @@
 	a_ctrl->io_master_info.cci_client = NULL;
 	kfree(power_info->power_setting);
 	kfree(power_info->power_down_setting);
+	power_info->power_setting = NULL;
+	power_info->power_down_setting = NULL;
 	kfree(a_ctrl->soc_info.soc_private);
 	kfree(a_ctrl->i2c_data.per_frame);
 	a_ctrl->i2c_data.per_frame = NULL;
@@ -284,6 +286,8 @@
 	kfree(power_info->power_setting);
 	kfree(power_info->power_down_setting);
 	kfree(a_ctrl->soc_info.soc_private);
+	power_info->power_setting = NULL;
+	power_info->power_down_setting = NULL;
 	a_ctrl->soc_info.soc_private = NULL;
 	kfree(a_ctrl);
 	return rc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 9b74826..f0efd4c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -191,25 +191,11 @@
 
 int cam_flash_off(struct cam_flash_ctrl *flash_ctrl)
 {
-	int i = 0;
-
 	if (!flash_ctrl) {
 		CAM_ERR(CAM_FLASH, "Flash control Null");
 		return -EINVAL;
 	}
 
-	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
-		if (flash_ctrl->flash_trigger[i])
-			cam_res_mgr_led_trigger_event(
-				flash_ctrl->flash_trigger[i],
-				LED_OFF);
-
-	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
-		if (flash_ctrl->torch_trigger[i])
-			cam_res_mgr_led_trigger_event(
-				flash_ctrl->torch_trigger[i],
-				LED_OFF);
-
 	if (flash_ctrl->switch_trigger)
 		cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger,
 			LED_SWITCH_OFF);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index dfcb9fc..6f77e0e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -55,6 +55,7 @@
 
 free_power_settings:
 	kfree(power_info->power_setting);
+	power_info->power_setting = NULL;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
index d742acf..5d16a4e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -240,6 +240,8 @@
 
 	kfree(power_info->power_setting);
 	kfree(power_info->power_down_setting);
+	power_info->power_setting = NULL;
+	power_info->power_down_setting = NULL;
 	kfree(o_ctrl->soc_info.soc_private);
 	kfree(o_ctrl);
 
@@ -341,6 +343,8 @@
 
 	kfree(power_info->power_setting);
 	kfree(power_info->power_down_setting);
+	power_info->power_setting = NULL;
+	power_info->power_down_setting = NULL;
 	kfree(o_ctrl->soc_info.soc_private);
 	kfree(o_ctrl->io_master_info.cci_client);
 	kfree(o_ctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 2133932..6fe051a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -599,7 +599,8 @@
 		} else {
 			CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d",
 				 cmd->handle_type);
-			return -EINVAL;
+			rc = -EINVAL;
+			goto release_mutex;
 		}
 
 		pu = power_info->power_setting;
@@ -653,7 +654,7 @@
 		}
 
 		CAM_INFO(CAM_SENSOR,
-			"Probe Succees,slot:%d,slave_addr:0x%x,sensor_id:0x%x",
+			"Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x",
 			s_ctrl->soc_info.index,
 			s_ctrl->sensordata->slave_info.sensor_slave_addr,
 			s_ctrl->sensordata->slave_info.sensor_id);
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 517b7df..55896f4 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -46,6 +46,7 @@
 	}
 
 	*sync_obj = idx;
+	CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj);
 	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 
 	return rc;
@@ -170,21 +171,24 @@
 	INIT_LIST_HEAD(&sync_list);
 
 	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) {
-		CAM_ERR(CAM_SYNC, "Error: Out of range sync obj");
+		CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)",
+			sync_obj, CAM_SYNC_MAX_OBJS);
 		return -EINVAL;
 	}
 	row = sync_dev->sync_table + sync_obj;
+	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
 	if (row->state == CAM_SYNC_STATE_INVALID) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
 		CAM_ERR(CAM_SYNC,
 			"Error: accessing an uninitialized sync obj = %d",
 			sync_obj);
 		return -EINVAL;
 	}
 
-	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
 	if (row->type == CAM_SYNC_TYPE_GROUP) {
 		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
-		CAM_ERR(CAM_SYNC, "Error: Signaling a GROUP sync object = %d",
+		CAM_ERR(CAM_SYNC,
+			"Error: Signaling a GROUP sync object = %d",
 			sync_obj);
 		return -EINVAL;
 	}
@@ -368,6 +372,7 @@
 
 int cam_sync_destroy(int32_t sync_obj)
 {
+	CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj);
 	return cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
index ed69829..43bce51 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -51,8 +51,9 @@
 	init_completion(&row->signaled);
 	INIT_LIST_HEAD(&row->callback_list);
 	INIT_LIST_HEAD(&row->user_payload_list);
-	CAM_DBG(CAM_SYNC, "Sync object Initialised: sync_id:%u row_state:%u ",
-		row->sync_id, row->state);
+	CAM_DBG(CAM_SYNC,
+		"row name:%s sync_id:%i [idx:%u] row_state:%u ",
+		row->name, row->sync_id, idx, row->state);
 
 	return 0;
 }
@@ -74,9 +75,11 @@
 	 * counts of error, active and success states of all children objects
 	 */
 	for (i = 0; i < num_objs; i++) {
+		spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
 		child_row = table + sync_objs[i];
 		switch (child_row->state) {
 		case CAM_SYNC_STATE_SIGNALED_ERROR:
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
 			return CAM_SYNC_STATE_SIGNALED_ERROR;
 		case CAM_SYNC_STATE_SIGNALED_SUCCESS:
 			success_count++;
@@ -87,8 +90,10 @@
 		default:
 			CAM_ERR(CAM_SYNC,
 				"Invalid state of child object during merge");
+			spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
 			return CAM_SYNC_STATE_SIGNALED_ERROR;
 		}
+		spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
 	}
 
 	if (active_count)
@@ -209,12 +214,16 @@
 	if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
 		return -EINVAL;
 
+	CAM_DBG(CAM_SYNC,
+		"row name:%s sync_id:%i [idx:%u] row_state:%u",
+		row->name, row->sync_id, idx, row->state);
+
 	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
 	if (row->state == CAM_SYNC_STATE_INVALID) {
+		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 		CAM_ERR(CAM_SYNC,
 			"Error: accessing an uninitialized sync obj: idx = %d",
 			idx);
-		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 		return -EINVAL;
 	}
 	row->state = CAM_SYNC_STATE_INVALID;
@@ -252,9 +261,9 @@
 		spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
 
 		if (child_row->state == CAM_SYNC_STATE_INVALID) {
+			list_del_init(&child_info->list);
 			spin_unlock_bh(&sync_dev->row_spinlocks[
 				child_info->sync_id]);
-			list_del_init(&child_info->list);
 			kfree(child_info);
 			continue;
 		}
@@ -262,9 +271,8 @@
 		cam_sync_util_cleanup_parents_list(child_row,
 			SYNC_LIST_CLEAN_ONE, idx);
 
-		spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
-
 		list_del_init(&child_info->list);
+		spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
 		kfree(child_info);
 	}
 
@@ -277,9 +285,9 @@
 		spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
 
 		if (parent_row->state == CAM_SYNC_STATE_INVALID) {
+			list_del_init(&parent_info->list);
 			spin_unlock_bh(&sync_dev->row_spinlocks[
 				parent_info->sync_id]);
-			list_del_init(&parent_info->list);
 			kfree(parent_info);
 			continue;
 		}
@@ -287,9 +295,8 @@
 		cam_sync_util_cleanup_children_list(parent_row,
 			SYNC_LIST_CLEAN_ONE, idx);
 
-		spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
-
 		list_del_init(&parent_info->list);
+		spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
 		kfree(parent_info);
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
index 30ab075..db2629d 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -171,6 +171,24 @@
 			patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
 			patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
 
+		if (patch_desc[i].src_offset >= src_buf_size) {
+			CAM_ERR_RATE_LIMIT(CAM_UTIL,
+				"Inval src offset:0x%x src len:0x%x reqid:%lld",
+				patch_desc[i].src_offset,
+				(unsigned int)src_buf_size,
+				packet->header.request_id);
+			return -EINVAL;
+		}
+
+		if (patch_desc[i].dst_offset >= dst_buf_len) {
+			CAM_ERR_RATE_LIMIT(CAM_UTIL,
+				"Inval dst offset:0x%x dst len:0x%x reqid:%lld",
+				patch_desc[i].dst_offset,
+				(unsigned int)dst_buf_len,
+				packet->header.request_id);
+			return -EINVAL;
+		}
+
 		dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr +
 			patch_desc[i].dst_offset);
 		temp += patch_desc[i].src_offset;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
index 7d37d7e..0811efb 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
@@ -32,6 +32,8 @@
 #define MSM_JPEG_NAME "jpeg"
 #define DEV_NAME_LEN 10
 
+static char devname[DEV_NAME_LEN];
+
 static int msm_jpeg_open(struct inode *inode, struct file *filp)
 {
 	int rc = 0;
@@ -159,7 +161,6 @@
 	struct msm_jpeg_device *msm_jpeg_device_p;
 	const struct of_device_id *device_id;
 	const struct msm_jpeg_priv_data *priv_data;
-	char devname[DEV_NAME_LEN];
 
 	msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
 	if (!msm_jpeg_device_p) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index d77ea21..b878971 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -6724,6 +6724,7 @@
 	struct msm_vidc_buffer *temp;
 	bool found = false;
 	int i = 0;
+	u32 planes[VIDEO_MAX_PLANES] = {0};
 
 	mutex_lock(&inst->flush_lock);
 	mutex_lock(&inst->registeredbufs.lock);
@@ -6737,6 +6738,10 @@
 		}
 	}
 	if (found) {
+		/* save device_addr */
+		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
+			planes[i] = mbuf->smem[i].device_addr;
+
 		/* send RBR event to client */
 		msm_vidc_queue_rbr_event(inst,
 			mbuf->vvb.vb2_buf.planes[0].m.fd,
@@ -6755,6 +6760,7 @@
 		if (!mbuf->smem[0].refcount) {
 			list_del(&mbuf->list);
 			kref_put_mbuf(mbuf);
+			mbuf = NULL;
 		}
 	} else {
 		print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf);
@@ -6772,8 +6778,8 @@
 	 */
 	found = false;
 	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
-		if (msm_comm_compare_vb2_plane(inst, mbuf,
-				&temp->vvb.vb2_buf, 0)) {
+		if (msm_comm_compare_device_plane(temp, planes, 0)) {
+			mbuf = temp;
 			found = true;
 			break;
 		}
@@ -6793,9 +6799,11 @@
 		/* don't queue the buffer */
 		found = false;
 	}
-	/* clear DEFERRED flag, if any, as the buffer is going to be queued */
-	if (found)
+	/* clear required flags as the buffer is going to be queued */
+	if (found) {
 		mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+		mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
+	}
 
 unlock:
 	mutex_unlock(&inst->registeredbufs.lock);
diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h
index f31fdfe..bf2e755 100644
--- a/drivers/net/wireless/cnss2/debug.h
+++ b/drivers/net/wireless/cnss2/debug.h
@@ -26,23 +26,23 @@
 	} while (0)
 
 #define cnss_pr_err(_fmt, ...) do {					\
-		pr_err("cnss: " _fmt, ##__VA_ARGS__);			\
-		cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__);	\
+		printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__);	\
+		cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
 	} while (0)
 
 #define cnss_pr_warn(_fmt, ...) do {					\
-		pr_warn("cnss: " _fmt, ##__VA_ARGS__);			\
-		cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__);	\
+		printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__);	\
+		cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
 	} while (0)
 
 #define cnss_pr_info(_fmt, ...) do {					\
-		pr_info("cnss: " _fmt, ##__VA_ARGS__);			\
-		cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__);	\
+		printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__);	\
+		cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
 	} while (0)
 
 #define cnss_pr_dbg(_fmt, ...) do {					\
-		pr_debug("cnss: " _fmt, ##__VA_ARGS__);			\
-		cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__);	\
+		printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__);	\
+		cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
 	} while (0)
 
 #ifdef CONFIG_CNSS2_DEBUG
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 2c29538..5d8b12b 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -2788,27 +2788,21 @@
 		return -GSI_STATUS_UNSUPPORTED_OP;
 	}
 
+	spin_lock_irqsave(&gsi_ctx->slock, flags);
 	if (curr == GSI_CHAN_MODE_CALLBACK &&
 			mode == GSI_CHAN_MODE_POLL) {
-		spin_lock_irqsave(&gsi_ctx->slock, flags);
 		__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
-		spin_unlock_irqrestore(&gsi_ctx->slock, flags);
-		spin_lock_irqsave(&ctx->ring.slock, flags);
 		atomic_set(&ctx->poll_mode, mode);
-		spin_unlock_irqrestore(&ctx->ring.slock, flags);
 		ctx->stats.callback_to_poll++;
 	}
 
 	if (curr == GSI_CHAN_MODE_POLL &&
 			mode == GSI_CHAN_MODE_CALLBACK) {
-		spin_lock_irqsave(&ctx->ring.slock, flags);
 		atomic_set(&ctx->poll_mode, mode);
-		spin_unlock_irqrestore(&ctx->ring.slock, flags);
-		spin_lock_irqsave(&gsi_ctx->slock, flags);
 		__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
-		spin_unlock_irqrestore(&gsi_ctx->slock, flags);
 		ctx->stats.poll_to_callback++;
 	}
+	spin_unlock_irqrestore(&gsi_ctx->slock, flags);
 
 	return GSI_STATUS_SUCCESS;
 }
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6e54fbf..05a8c66 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -1020,8 +1020,6 @@
 				"sps:%s:BAMs are still registered", __func__);
 
 		sps_map_de_init();
-
-		kfree(sps);
 	}
 
 	sps_mem_de_init();
@@ -3006,6 +3004,7 @@
 		.name	= SPS_DRV_NAME,
 		.owner	= THIS_MODULE,
 		.of_match_table = msm_sps_match,
+		.suppress_bind_attrs = true,
 	},
 	.remove		= msm_sps_remove,
 };
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index d1b6bea..41b8d3c 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -452,13 +452,11 @@
 }
 
 #define MIN_FIFO_FULL_TIME_MS			12000
-static int process_rt_fifo_data(struct qpnp_qg *chip,
-			bool update_vbat_low, bool update_smb)
+static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb)
 {
 	int rc = 0;
 	ktime_t now = ktime_get();
 	s64 time_delta;
-	u8 fifo_length;
 
 	/*
 	 * Reject the FIFO read event if there are back-to-back requests
@@ -467,11 +465,10 @@
 	 */
 	time_delta = ktime_ms_delta(now, chip->last_user_update_time);
 
-	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_vbat_low=%d update_smb=%d\n",
-				time_delta, update_vbat_low, update_smb);
+	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n",
+				time_delta, update_smb);
 
-	if (time_delta > MIN_FIFO_FULL_TIME_MS || update_vbat_low
-						|| update_smb) {
+	if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) {
 		rc = qg_master_hold(chip, true);
 		if (rc < 0) {
 			pr_err("Failed to hold master, rc=%d\n", rc);
@@ -484,20 +481,6 @@
 			goto done;
 		}
 
-		if (update_vbat_low) {
-			/* change FIFO length */
-			fifo_length = chip->vbat_low ?
-					chip->dt.s2_vbat_low_fifo_length :
-					chip->dt.s2_fifo_length;
-			rc = qg_update_fifo_length(chip, fifo_length);
-			if (rc < 0)
-				goto done;
-
-			qg_dbg(chip, QG_DEBUG_STATUS,
-				"FIFO length updated to %d vbat_low=%d\n",
-					fifo_length, chip->vbat_low);
-		}
-
 		if (update_smb) {
 			rc = qg_masked_write(chip, chip->qg_base +
 				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
@@ -539,60 +522,67 @@
 static int qg_vbat_low_wa(struct qpnp_qg *chip)
 {
 	int rc, i, temp = 0;
-	u32 vbat_low_uv = 0;
+	u32 vbat_low_uv = 0, fifo_length = 0;
 
-	rc = qg_get_battery_temp(chip, &temp);
-	if (rc < 0) {
-		pr_err("Failed to read batt_temp rc=%d\n", rc);
-		temp = 250;
-	}
+	if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) {
+		rc = qg_get_battery_temp(chip, &temp);
+		if (rc < 0) {
+			pr_err("Failed to read batt_temp rc=%d\n", rc);
+			temp = 250;
+		}
 
-	vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ?
-				chip->dt.vbatt_low_cold_mv :
-				chip->dt.vbatt_low_mv);
-	vbat_low_uv += VBAT_LOW_HYST_UV;
-
-	if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low)
-		return 0;
-
-	/*
-	 * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
-	 * To exit from VBAT_LOW config, check if any of the FIFO
-	 * averages is > vbat_low threshold and reconfigure the
-	 * FIFO length to normal.
-	 */
-	for (i = 0; i < chip->kdata.fifo_length; i++) {
-		if (chip->kdata.fifo[i].v > vbat_low_uv) {
-			rc = qg_master_hold(chip, true);
-			if (rc < 0) {
-				pr_err("Failed to hold master, rc=%d\n", rc);
-				goto done;
-			}
-			rc = qg_update_fifo_length(chip,
-					chip->dt.s2_fifo_length);
-			if (rc < 0)
-				goto done;
-
-			rc = qg_master_hold(chip, false);
-			if (rc < 0) {
-				pr_err("Failed to release master, rc=%d\n", rc);
-				goto done;
-			}
-			/* FIFOs restarted */
-			chip->last_fifo_update_time = ktime_get();
-
-			chip->vbat_low = false;
-			pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
+		vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ?
+					chip->dt.vbatt_low_cold_mv :
+					chip->dt.vbatt_low_mv);
+		vbat_low_uv += VBAT_LOW_HYST_UV;
+		/*
+		 * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
+		 * To exit from VBAT_LOW config, check if any of the FIFO
+		 * averages is > vbat_low threshold and reconfigure the
+		 * FIFO length to normal.
+		 */
+		for (i = 0; i < chip->kdata.fifo_length; i++) {
+			if (chip->kdata.fifo[i].v > vbat_low_uv) {
+				chip->vbat_low = false;
+				pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
 					chip->kdata.fifo[i].v, vbat_low_uv,
 					chip->dt.s2_fifo_length);
-			break;
+				break;
+			}
 		}
 	}
 
-	return 0;
+	rc = get_fifo_length(chip, &fifo_length, false);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO length, rc=%d\n", rc);
+		return rc;
+	}
 
+	if (chip->vbat_low && fifo_length == chip->dt.s2_vbat_low_fifo_length)
+		return 0;
+
+	if (!chip->vbat_low && fifo_length == chip->dt.s2_fifo_length)
+		return 0;
+
+	rc = qg_master_hold(chip, true);
+	if (rc < 0) {
+		pr_err("Failed to hold master, rc=%d\n", rc);
+		goto done;
+	}
+
+	fifo_length = chip->vbat_low ? chip->dt.s2_vbat_low_fifo_length :
+					chip->dt.s2_fifo_length;
+
+	rc = qg_update_fifo_length(chip, fifo_length);
+	if (rc < 0)
+		goto done;
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "FIFO length updated to %d vbat_low=%d\n",
+					fifo_length, chip->vbat_low);
 done:
 	qg_master_hold(chip, false);
+	/* FIFOs restarted */
+	chip->last_fifo_update_time = ktime_get();
 	return rc;
 }
 
@@ -1174,10 +1164,6 @@
 
 	chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT);
 
-	rc = process_rt_fifo_data(chip, true, false);
-	if (rc < 0)
-		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
-
 	qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low);
 done:
 	mutex_unlock(&chip->data_lock);
@@ -1950,7 +1936,7 @@
 	if (!chip->dt.qg_ext_sense)
 		update_smb = true;
 
-	rc = process_rt_fifo_data(chip, false, update_smb);
+	rc = process_rt_fifo_data(chip, update_smb);
 	if (rc < 0)
 		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
 
@@ -3474,10 +3460,10 @@
 			return rc;
 		}
 
-		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
-		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
 		 /* Clear suspend data as there has been a GOOD OCV */
 		memset(&chip->kdata, 0, sizeof(chip->kdata));
+		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
 		chip->suspend_data = false;
 
 		qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 6685f05..2c0c0ed 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -374,7 +374,6 @@
 	struct rx_msg		*rx_ext_msg;
 
 	u32			received_pdos[PD_MAX_DATA_OBJ];
-	u32			received_ado;
 	u16			src_cap_id;
 	u8			selected_pdo;
 	u8			requested_pdo;
@@ -443,6 +442,7 @@
 	u8			src_cap_ext_db[PD_SRC_CAP_EXT_DB_LEN];
 	bool			send_get_pps_status;
 	u32			pps_status_db;
+	bool			send_get_status;
 	u8			status_db[PD_STATUS_DB_LEN];
 	bool			send_get_battery_cap;
 	u8			get_battery_cap_db;
@@ -2252,7 +2252,7 @@
 			pd->send_pr_swap = false;
 			ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev, "Error sending PR Swap\n");
+				usbpd_err(&pd->dev, "Error sending PR Swap\n");
 				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
 				break;
 			}
@@ -2263,7 +2263,7 @@
 			pd->send_dr_swap = false;
 			ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev, "Error sending DR Swap\n");
+				usbpd_err(&pd->dev, "Error sending DR Swap\n");
 				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
 				break;
 			}
@@ -2552,8 +2552,7 @@
 			ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP_EXTENDED, NULL,
 				0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev,
-					"Error sending get_src_cap_ext\n");
+				usbpd_err(&pd->dev, "Error sending get_src_cap_ext\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -2572,8 +2571,7 @@
 			ret = pd_send_msg(pd, MSG_GET_PPS_STATUS, NULL,
 				0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev,
-					"Error sending get_pps_status\n");
+				usbpd_err(&pd->dev, "Error sending get_pps_status\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -2588,23 +2586,32 @@
 				sizeof(pd->pps_status_db));
 			complete(&pd->is_ready);
 		} else if (IS_DATA(rx_msg, MSG_ALERT)) {
-			if (rx_msg->data_len != sizeof(pd->received_ado)) {
+			u32 ado;
+
+			if (rx_msg->data_len != sizeof(ado)) {
 				usbpd_err(&pd->dev, "Invalid ado\n");
 				break;
 			}
-			memcpy(&pd->received_ado, rx_msg->payload,
-				sizeof(pd->received_ado));
-			ret = pd_send_msg(pd, MSG_GET_STATUS, NULL,
-				0, SOP_MSG);
+			memcpy(&ado, rx_msg->payload, sizeof(ado));
+			usbpd_dbg(&pd->dev, "Received Alert 0x%08x\n", ado);
+
+			/*
+			 * Don't send Get_Status right away so we can coalesce
+			 * multiple Alerts. 150ms should be enough to not get
+			 * in the way of any other AMS that might happen.
+			 */
+			pd->send_get_status = true;
+			kick_sm(pd, 150);
+		} else if (pd->send_get_status && is_sink_tx_ok(pd)) {
+			pd->send_get_status = false;
+			ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev,
-					"Error sending get_status\n");
+				usbpd_err(&pd->dev, "Error sending get_status\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
 			kick_sm(pd, SENDER_RESPONSE_TIME);
-		} else if (rx_msg &&
-			IS_EXT(rx_msg, MSG_STATUS)) {
+		} else if (rx_msg && IS_EXT(rx_msg, MSG_STATUS)) {
 			if (rx_msg->data_len != PD_STATUS_DB_LEN) {
 				usbpd_err(&pd->dev, "Invalid status db\n");
 				break;
@@ -2617,8 +2624,7 @@
 			ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP,
 				&pd->get_battery_cap_db, 1, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev,
-					"Error sending get_battery_cap\n");
+				usbpd_err(&pd->dev, "Error sending get_battery_cap\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -2637,8 +2643,7 @@
 			ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_STATUS,
 				&pd->get_battery_status_db, 1, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev,
-					"Error sending get_battery_status\n");
+				usbpd_err(&pd->dev, "Error sending get_battery_status\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -2668,7 +2673,7 @@
 			pd->send_pr_swap = false;
 			ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev, "Error sending PR Swap\n");
+				usbpd_err(&pd->dev, "Error sending PR Swap\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -2679,7 +2684,7 @@
 			pd->send_dr_swap = false;
 			ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
 			if (ret) {
-				dev_err(&pd->dev, "Error sending DR Swap\n");
+				usbpd_err(&pd->dev, "Error sending DR Swap\n");
 				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
 				break;
 			}
@@ -3297,9 +3302,9 @@
 				"explicit" : "implicit");
 	add_uevent_var(env, "ALT_MODE=%d", pd->vdm_state == MODE_ENTERED);
 
-	add_uevent_var(env, "ADO=%08x", pd->received_ado);
-	for (i = 0; i < PD_STATUS_DB_LEN; i++)
-		add_uevent_var(env, "SDB%d=%08x", i, pd->status_db[i]);
+	add_uevent_var(env, "SDB=%02x %02x %02x %02x %02x", pd->status_db[0],
+			pd->status_db[1], pd->status_db[2], pd->status_db[3],
+			pd->status_db[4]);
 
 	return 0;
 }
@@ -3690,12 +3695,40 @@
 		return ret;
 
 	for (i = 0; i < PD_SRC_CAP_EXT_DB_LEN; i++)
-		len += snprintf(buf + len, PAGE_SIZE - len, "%d\n",
-			pd->src_cap_ext_db[i]);
+		len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+				i ? " " : "", pd->src_cap_ext_db[i]);
+
+	buf[len++] = '\n';
+	buf[len] = '\0';
+
 	return len;
 }
 static DEVICE_ATTR_RO(get_src_cap_ext);
 
+static ssize_t get_status_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int i, ret, len = 0;
+	struct usbpd *pd = dev_get_drvdata(dev);
+
+	if (pd->spec_rev == USBPD_REV_20)
+		return -EINVAL;
+
+	ret = trigger_tx_msg(pd, &pd->send_get_status);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < PD_STATUS_DB_LEN; i++)
+		len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+				i ? " " : "", pd->status_db[i]);
+
+	buf[len++] = '\n';
+	buf[len] = '\0';
+
+	return len;
+}
+static DEVICE_ATTR_RO(get_status);
+
 static ssize_t get_pps_status_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -3709,20 +3742,10 @@
 	if (ret)
 		return ret;
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", pd->pps_status_db);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db);
 }
 static DEVICE_ATTR_RO(get_pps_status);
 
-static ssize_t rx_ado_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct usbpd *pd = dev_get_drvdata(dev);
-
-	/* dump the ADO as a hex string */
-	return snprintf(buf, PAGE_SIZE, "%08x\n", pd->received_ado);
-}
-static DEVICE_ATTR_RO(rx_ado);
-
 static ssize_t get_battery_cap_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
@@ -3751,8 +3774,12 @@
 		return -EINVAL;
 
 	for (i = 0; i < PD_BATTERY_CAP_DB_LEN; i++)
-		len += snprintf(buf + len, PAGE_SIZE - len, "%d\n",
-			pd->battery_cap_db[i]);
+		len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+				i ? " " : "", pd->battery_cap_db[i]);
+
+	buf[len++] = '\n';
+	buf[len] = '\0';
+
 	return len;
 }
 static DEVICE_ATTR_RW(get_battery_cap);
@@ -3783,7 +3810,7 @@
 	if (pd->get_battery_status_db == -EINVAL)
 		return -EINVAL;
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", pd->battery_sts_dobj);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->battery_sts_dobj);
 }
 static DEVICE_ATTR_RW(get_battery_status);
 
@@ -3807,8 +3834,8 @@
 	&dev_attr_rdo_h.attr,
 	&dev_attr_hard_reset.attr,
 	&dev_attr_get_src_cap_ext.attr,
+	&dev_attr_get_status.attr,
 	&dev_attr_get_pps_status.attr,
-	&dev_attr_rx_ado.attr,
 	&dev_attr_get_battery_cap.attr,
 	&dev_attr_get_battery_status.attr,
 	NULL,
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 2997976..a1b8a32 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -50,7 +50,7 @@
 #define TX_SIZE_MASK			0xF
 
 #define USB_PDPHY_TX_CONTROL		0x44
-#define TX_CONTROL_RETRY_COUNT		(BIT(6) | BIT(5))
+#define TX_CONTROL_RETRY_COUNT(n)	(((n) & 0x3) << 5)
 #define TX_CONTROL_FRAME_TYPE		(BIT(4) | BIT(3) | BIT(2))
 #define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2)
 #define TX_CONTROL_SEND_SIGNAL		BIT(1)
@@ -80,6 +80,9 @@
 #define VDD_PDPHY_VOL_MAX		3088000 /* uV */
 #define VDD_PDPHY_HPM_LOAD		3000 /* uA */
 
+/* Message Spec Rev field */
+#define PD_MSG_HDR_REV(hdr)		(((hdr) >> 6) & 3)
+
 /* timers */
 #define RECEIVER_RESPONSE_TIME		15	/* tReceiverResponse */
 #define HARD_RESET_COMPLETE_TIME	5	/* tHardResetComplete */
@@ -437,12 +440,12 @@
 	if (ret)
 		return ret;
 
-	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
+	ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq,
 		pdphy->tx_status != -EINPROGRESS,
-		msecs_to_jiffies(HARD_RESET_COMPLETE_TIME));
-	if (ret <= 0) {
+		ms_to_ktime(HARD_RESET_COMPLETE_TIME));
+	if (ret) {
 		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
-		return ret ? ret : -ETIMEDOUT;
+		return ret;
 	}
 
 	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0);
@@ -520,18 +523,24 @@
 
 	usleep_range(2, 3);
 
-	val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG;
+	val = (sop << 2) | TX_CONTROL_SEND_MSG;
+
+	/* nRetryCount == 2 for PD 3.0, 3 for PD 2.0 */
+	if (PD_MSG_HDR_REV(hdr) == USBPD_REV_30)
+		val |= TX_CONTROL_RETRY_COUNT(2);
+	else
+		val |= TX_CONTROL_RETRY_COUNT(3);
 
 	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
 	if (ret)
 		return ret;
 
-	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
+	ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq,
 		pdphy->tx_status != -EINPROGRESS,
-		msecs_to_jiffies(RECEIVER_RESPONSE_TIME));
-	if (ret <= 0) {
+		ms_to_ktime(RECEIVER_RESPONSE_TIME));
+	if (ret) {
 		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
-		return ret ? ret : -ETIMEDOUT;
+		return ret;
 	}
 
 	if (hdr && !pdphy->tx_status)
diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h
index cd2d2d2..680d05b 100644
--- a/include/uapi/media/cam_icp.h
+++ b/include/uapi/media/cam_icp.h
@@ -59,8 +59,9 @@
 /* Command meta types */
 #define CAM_ICP_CMD_META_GENERIC_BLOB           0x1
 
-/* Generic blon types */
+/* Generic blob types */
 #define CAM_ICP_CMD_GENERIC_BLOB_CLK            0x1
+#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO         0x2
 
 /**
  * struct cam_icp_clk_bw_request
diff --git a/net/ipc_router/ipc_router_fifo_xprt.c b/net/ipc_router/ipc_router_fifo_xprt.c
index ae85fd1..c90534d 100644
--- a/net/ipc_router/ipc_router_fifo_xprt.c
+++ b/net/ipc_router/ipc_router_fifo_xprt.c
@@ -255,7 +255,7 @@
 	hdr_len = sizeof(struct rr_header_v1);
 	while (1) {
 		rx_avail = fifo_rx_avail(&xprtp->rx_pipe);
-		if (!rx_avail || (rx_avail < hdr_len))
+		if (!rx_avail)
 			break;
 
 		fifo_rx_peak(&xprtp->rx_pipe, &hdr, 0, hdr_len);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c88874f..0a67d80 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -949,6 +949,7 @@
 	nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
 
 	list_del_rcu(&wdev->list);
+	synchronize_rcu();
 	rdev->devlist_generation++;
 
 	switch (wdev->iftype) {
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index ce1f0ad..fe29aed 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -110,8 +110,8 @@
 	unsigned long curr_xfer_buf_iova;
 	/* bit fields representing pcm card enabled */
 	unsigned long card_slot;
-	/* cache event ring phys addr */
-	u64 er_phys_addr;
+	/* indicate event ring mapped or not */
+	bool er_mapped;
 };
 
 static struct uaudio_qmi_dev *uaudio_qdev;
@@ -295,7 +295,7 @@
 	case MEM_EVENT_RING:
 		va = IOVA_BASE;
 		/* er already mapped */
-		if (uaudio_qdev->er_phys_addr == pa)
+		if (uaudio_qdev->er_mapped)
 			map = false;
 		break;
 	case MEM_XFER_RING:
@@ -407,8 +407,8 @@
 
 	switch (mtype) {
 	case MEM_EVENT_RING:
-		if (uaudio_qdev->er_phys_addr)
-			uaudio_qdev->er_phys_addr = 0;
+		if (uaudio_qdev->er_mapped)
+			uaudio_qdev->er_mapped = false;
 		else
 			unmap = false;
 		break;
@@ -637,7 +637,7 @@
 						uaudio_qdev->sid);
 	resp->xhci_mem_info.evt_ring.pa = dma;
 	resp->xhci_mem_info.evt_ring.size = PAGE_SIZE;
-	uaudio_qdev->er_phys_addr = xhci_pa;
+	uaudio_qdev->er_mapped = true;
 
 	resp->speed_info = get_speed_info(subs->dev->speed);
 	if (resp->speed_info == USB_AUDIO_DEVICE_SPEED_INVALID_V01)