Merge "usb: dwc3-msm: Initialize mutex before registering extcon"
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index d11af52..ac9489f 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -54,6 +54,7 @@
 | ARM            | Cortex-A57      | #852523         | N/A                         |
 | ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220        |
 | ARM            | Cortex-A72      | #853709         | N/A                         |
+| ARM            | Cortex-A55      | #1024718        | ARM64_ERRATUM_1024718       |
 | ARM            | MMU-500         | #841119,#826419 | N/A                         |
 |                |                 |                 |                             |
 | Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375        |
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index d150116..1b8b7cf 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -175,6 +175,9 @@
 - VR device:
   compatible = "qcom,qvr"
 
+- SVR device:
+  compatible = "qcom,svr"
+
 - HDK device:
   compatible = "qcom,hdk"
 
@@ -295,6 +298,7 @@
 compatible = "qcom,sda845-mtp"
 compatible = "qcom,sda845-qrd"
 compatible = "qcom,sda845-hdk"
+compatible = "qcom,sda845-svr"
 compatible = "qcom,sdm670-rumi"
 compatible = "qcom,sdm670-cdp"
 compatible = "qcom,sdm670-mtp"
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
index 36e1a69..a53eba5 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -4,15 +4,28 @@
 It tells about the individual masters information at any given
 time like "system sleep counts", "system sleep last entered at"
 and "system sleep accumulated duration" etc. These stats can be
-show to the user using the debugfs interface of the kernel.
+displayed using the sysfs interface.
 To achieve this, device tree node has been added.
 
+Additionally, RPMH master stats also maintains application processor's
+master stats. It uses profiling units to calculate power down and power
+up stats.
+
 The required properties for rpmh-master-stats are:
 
-- compatible: "qcom,rpmh-master-stats".
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,rpmh-master-stats-v1".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Specifies physical address of start of profiling unit.
 
 Example:
 
 qcom,rpmh-master-stats {
 	compatible = "qcom,rpmh-master-stats";
+	reg = <0xb221200 0x60>;
 };
diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
new file mode 100644
index 0000000..0149ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
@@ -0,0 +1,57 @@
+* Qualcomm Technologies, Inc. Connectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for SDIO
+based Wi-Fi devices. It also adds support to manage two 1.8V voltage
+regulators and WLAN power enable 3.3V regulators. The main purpose of this
+device tree entry below is to invoke the CNSS SDIO platform driver
+and provide handle to the WLAN power enable 3.3V pmic GPIO and two 1.8V
+PMIC voltage regulator resources.
+
+Required properties:
+  - compatible: "qcom,cnss_sdio"
+  - reg: memory resource to save firmware dump, optional.
+  - reg-names: memory resource name.
+  - subsys-name: cnss sdio subsytem device name, required.
+  - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node.
+  - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node.
+  - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node.
+  - vdd-wlan-xtal-supply: phandle to the WLAM XTAL regulator device tree node.
+
+Optional properties:
+  - pinctrl-names: Names corresponding to the numbered pinctrl states
+  - pinctrl-<n>: Pinctrl states as described in
+                bindings/pinctrl/pinctrl-bindings.txt
+  - qcom,is-antenna-shared: Enabled for Platforms with both sdio and pcie QCA
+                           Chipsets are attached.
+  - qcom,cnss-enable-bus-bandwidth: Boolean - Define this property when target
+					support to vote for bus bandwidth.
+  - qcom,msm-bus,name: client name for msm bus register.
+  - qcom,msm-bus,num-cases: number of cases for bus scaling.
+  - qcom,msm-bus,num-paths: number of paths for bus scale vector.
+  - qcom,msm-bus,vectors-KBps: bus scale vector table.
+  - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where
+                           wlan_en toggling is not supported.
+Example:
+	qcom,cnss-sdio {
+		compatible = "qcom,cnss_sdio";
+		reg = <0x87a00000, 0x200000>;
+		reg-names = "ramdump";
+		subsys-name = "AR6320";
+		vdd-wlan-supply = <&rome_vreg>;
+		vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>;
+		vdd-wlan-io-supply = <&mdm9607_l11>;
+		vdd-wlan-xtal-supply = <&mdm9607_l2>;
+		qcom,is-antenna-shared;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&cnss_sdio_active>;
+		pinctrl-1 = <&cnss_sdio_sleep>;
+		qcom,cnss-enable-bus-bandwidth;
+		qcom,msm-bus,name = "msm-cnss";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<79 512 0 0>,			/* No vote */
+				<79 512 6250 200000>,		/* 50 Mbps */
+				<79 512 25000 200000>,		/* 200 Mbps */
+				<79 512 2048000 4096000>;	/* MAX */
+	};
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index a89b834..0f40cbce 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -66,6 +66,10 @@
 - qcom,dsi-display:       Specifies dsi display is present
 - qcom,hdmi-display:      Specifies hdmi is present
 - qcom,dp-display:        Specified dp is present
+- ports:                  This video port is used when external bridge is present. The connection is modelled
+                          using the OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+                          Video port 0 is for the bridge output. The remote endpoint phandle should be
+                          mipi_dsi_device device node.
 - qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the
 					a particular "type" of DSI module. The module "types"
 					can be "core", "ctrl", and "phy". Within the same type,
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 493a1aa..7bcb2dc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi-panel
+Qualcomm Technologies, Inc. mdss-dsi-panel
 
 mdss-dsi-panel is a dsi panel device which supports panels that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 2f74f7f..8b593a9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi
+Qualcomm Technologies, Inc. mdss-dsi
 
 mdss-dsi is the master DSI device which supports multiple DSI host controllers that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index c474b88..3d649e5 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS EDP
+Qualcomm Technologies, Inc. MDSS EDP
 
 MDSS EDP is a edp driver which supports panels that are compatible with
 VESA EDP display interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index e33d358..3661221 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS MDP
+Qualcomm Technologies, Inc. MDSS MDP
 
 MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
 drive user interface to different panel interfaces. MDP driver is the core of
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index 2c193c2..6b9238c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS pll for DSI/EDP/HDMI
+Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI
 
 mdss-pll is a pll controller device which supports pll devices that are
 compatiable with MIPI display serial interface specification, HDMI and edp.
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index 7f95ed4..285a14f 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -1,4 +1,4 @@
-* Qualcomm HDMI Tx
+* Qualcomm Technologies, Inc. HDMI Tx
 
 Required properties:
 - cell-index: hdmi tx controller index
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
index b399145..c679fe6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -42,6 +42,7 @@
   currently supported names are:
   - gfx3d_user : Used for the 'normal' GPU address space.
   - gfx3d_secure : Used for the content protection address space.
+  - gfx3d_secure_alt : Used for the content protection address space for alternative SID.
   Each sub node has the following required properties:
 
 	- compatible : "qcom,smmu-kgsl-cb"
@@ -83,4 +84,9 @@
 			compatible = "qcom,smmu-kgsl-cb";
 			iommus = <&kgsl_smmu 2>;
 		};
+
+		gfx3d_secure_alt: gfx3d_secure_alt {
+			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 55cd383..375e929 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -130,6 +130,13 @@
 				mask   - mask for the relevant bits in the efuse register.
 				shift  - number of bits to right shift to get the disable_gpu
 				fuse bit value.
+
+- qcom,soc-hw-rev-efuse:	SOC hardware revision fuse information in the format
+				<offset bit_position mask>
+				offset - offset of the efuse register from the base.
+				bit_position - hardware revision starting bit in the efuse register.
+				mask - mask for the relevant bits in the efuse register.
+
 - qcom,highest-bank-bit:
 				Specify the bit of the highest DDR bank. This
 				is programmed into protected registers and also
@@ -200,6 +207,9 @@
 - qcom,gpu-quirk-limit-uche-gbif-rw:
 				Limit number of read and write transactions from UCHE block to
 				GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC.
+- qcom,gpu-quirk-mmu-secure-cb-alt:
+				Select alternate secure context bank to generate SID1 for
+				secure playback.
 
 KGSL Memory Pools:
 - qcom,gpu-mempools:		Container for sets of GPU mempools.Multiple sets
@@ -230,7 +240,7 @@
 		Defines a SOC hardware revision.
 
 Properties:
-- reg:
+-  qcom,soc-hw-revision:
 		Identifier for the hardware revision - must match the value read
 		from the hardware.
 - qcom,chipid:
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
index 176f9e1..169f848 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -182,6 +182,10 @@
 				  be edge triggered. Otherwise, it is level triggered.
 - qcom,hw-strobe-active-low	: Boolean property to select strobe signal polarity. If defined, hw-strobe
 				  signal polarity is set to active-low, else it is active-high.
+- qcom,symmetry-en	: Boolean property to specify if the flash LEDs under a
+			  switch node are controlled symmetrically. This needs
+			  to be specified if a group of flash LED channels are
+			  connected to a single LED.
 Example:
 	qcom,leds@d300 {
 		compatible = "qcom,qpnp-flash-led-v2";
@@ -302,6 +306,7 @@
 			qcom,led-mask = <3>;
 			qcom,default-led-trigger =
 						"switch0_trigger";
+			qcom,symmetry-en;
 		};
 
 		pmi8998_switch1: qcom,led_switch_1 {
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index d272b7f..73cd1db 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -135,6 +135,8 @@
 - qcom,additional-mapping: specifies any addtional mapping needed for this
 				context bank. The format is <iova pa size>
 
+- qcom,ipa-q6-smem-size: specifies the Q6 SMEM partition size
+
 IPA SMP2P sub nodes
 
 -compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
index 8e17f80..65c3cb8 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -114,12 +114,6 @@
 		SOC. If this property is not specified, then auto recharge will
 		be based off battery voltage.
 
-- qcom,micro-usb
-  Usage:      optional
-  Value type: <empty>
-  Definition: Boolean flag which indicates that the platform only support
-		micro usb port.
-
 - qcom,suspend-input-on-debug-batt
   Usage:      optional
   Value type: <empty>
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67ffaed..6ff6e9b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -19,6 +19,7 @@
 	       should be "qcom,sdm630-tsens" for 630 TSENS driver.
 	       should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
 	       should be "qcom,tsens24xx" for 2.4 TSENS controller.
+	       should be "qcom,msm8937-tsens" for 8937 TSENS driver.
 	       The compatible property is used to identify the respective controller to use
 	       for the corresponding SoC.
 - reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index c51581d..8f6af4c 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,7 +1,9 @@
 
 dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \
 	sdxpoorwills-cdp.dtb \
-	sdxpoorwills-mtp.dtb
+	sdxpoorwills-mtp.dtb \
+	sdxpoorwills-pcie-ep-cdp.dtb \
+	sdxpoorwills-pcie-ep-mtp.dtb
 
 targets += dtbs
 targets += $(addprefix ../, $(dtb-y))
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 261829f..38137a2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -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
@@ -12,10 +12,7 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
@@ -23,132 +20,3 @@
 		"qcom,sdxpoorwills", "qcom,cdp";
 	qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
 };
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
new file mode 100644
index 0000000..b5944d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
@@ -0,0 +1,144 @@
+/* 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.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index cba6262..a0bcdc9 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -12,10 +12,7 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
@@ -23,132 +20,3 @@
 		"qcom,sdxpoorwills", "qcom,mtp";
 	qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
 };
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
new file mode 100644
index 0000000..63cc3a4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
@@ -0,0 +1,144 @@
+/* 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.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
index 194bfeb..8339f9a 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -13,12 +12,11 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP CDP";
+	compatible = "qcom,sdxpoorwills-cdp",
+		"qcom,sdxpoorwills", "qcom,cdp";
+	qcom,board-id = <1 0x1>, <1 0x101>;
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
index 194bfeb..2240133 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -13,12 +12,11 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP MTP";
+	compatible = "qcom,sdxpoorwills-mtp",
+		"qcom,sdxpoorwills", "qcom,mtp";
+	qcom,board-id = <8 0x1>, <8 0x101>;
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index deed94d..6c172c1 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -984,6 +984,44 @@
 			};
 		};
 
+		pcie_ep {
+			pcie_ep_clkreq_default: pcie_ep_clkreq_default {
+				mux {
+					pins = "gpio56";
+					function = "pcie_clkreq";
+				};
+				config {
+					pins = "gpio56";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			pcie_ep_perst_default: pcie_ep_perst_default {
+				mux {
+					pins = "gpio57";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio57";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			pcie_ep_wake_default: pcie_ep_wake_default {
+				mux {
+					pins = "gpio53";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio53";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		wcd9xxx_intr {
 			wcd_intr_default: wcd_intr_default{
 				mux {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index c9a5d1b..c23d48b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -283,6 +283,142 @@
 		reg = <0x00137004 0x4>;
 	};
 
+	pcie_ep: qcom,pcie@40002000 {
+		compatible = "qcom,pcie-ep";
+
+		reg = <0x40002000 0x1000>,
+			<0x40000000 0xf1d>,
+			<0x40000f20 0xa8>,
+			<0x40001000 0x1000>,
+			<0x01c00000 0x2000>,
+			<0x01c02000 0x1000>,
+			<0x01c04000 0x1000>;
+		reg-names = "msi", "dm_core", "elbi", "iatu", "parf",
+				"phy", "mmio";
+
+		#address-cells = <0>;
+		interrupt-parent = <&pcie_ep>;
+		interrupts = <0>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 140 0>;
+		interrupt-names = "int_global";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie_ep_clkreq_default &pcie_ep_perst_default
+			&pcie_ep_wake_default>;
+
+		clkreq-gpio = <&tlmm 56 0>;
+		perst-gpio = <&tlmm 57 0>;
+		wake-gpio = <&tlmm 53 0>;
+
+		gdsc-vdd-supply = <&gdsc_pcie>;
+		vreg-1.8-supply = <&pmxpoorwills_l1>;
+		vreg-0.9-supply = <&pmxpoorwills_l4>;
+
+		qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+		qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+
+		clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>,
+			<&clock_gcc GCC_PCIE_CFG_AHB_CLK>,
+			<&clock_gcc GCC_PCIE_MSTR_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_AUX_CLK>,
+			<&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+			<&clock_gcc GCC_PCIE_SLEEP_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>;
+
+		clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk",
+				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+				"pcie_0_aux_clk", "pcie_0_ldo",
+				"pcie_0_sleep_clk",
+				"pcie_0_slv_q2a_axi_clk";
+
+		resets = <&clock_gcc GCC_PCIE_BCR>,
+			<&clock_gcc GCC_PCIE_PHY_BCR>;
+
+		reset-names = "pcie_0_core_reset",
+				"pcie_0_phy_reset";
+
+		qcom,msm-bus,name = "pcie-ep";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<45 512 0 0>,
+				<45 512 500 800>;
+
+		qcom,pcie-link-speed = <2>;
+		qcom,pcie-phy-ver = <6>;
+		qcom,pcie-active-config;
+		qcom,pcie-aggregated-irq;
+		qcom,pcie-mhi-a7-irq;
+		qcom,phy-status-reg = <0x814>;
+
+		qcom,phy-init = <0x840 0x001 0x0 0x1
+				0x094 0x000 0x0 0x1
+				0x058 0x00f 0x0 0x1
+				0x0a4 0x042 0x0 0x1
+				0x110 0x024 0x0 0x1
+				0x1bc 0x011 0x0 0x1
+				0x0bc 0x019 0x0 0x1
+				0x0b0 0x004 0x0 0x1
+				0x0ac 0x0ff 0x0 0x1
+				0x158 0x001 0x0 0x1
+				0x074 0x028 0x0 0x1
+				0x07c 0x00d 0x0 0x1
+				0x084 0x000 0x0 0x1
+				0x1b0 0x01d 0x0 0x1
+				0x1ac 0x056 0x0 0x1
+				0x04c 0x007 0x0 0x1
+				0x050 0x007 0x0 0x1
+				0x0f0 0x003 0x0 0x1
+				0x0ec 0x0fb 0x0 0x1
+				0x00c 0x002 0x0 0x1
+				0x29c 0x012 0x0 0x1
+				0x284 0x005 0x0 0x1
+				0x234 0x0d9 0x0 0x1
+				0x238 0x0cc 0x0 0x1
+				0x51c 0x003 0x0 0x1
+				0x518 0x01c 0x0 0x1
+				0x524 0x014 0x0 0x1
+				0x4ec 0x00e 0x0 0x1
+				0x4f0 0x04a 0x0 0x1
+				0x4f4 0x00f 0x0 0x1
+				0x5b4 0x004 0x0 0x1
+				0x434 0x07f 0x0 0x1
+				0x444 0x070 0x0 0x1
+				0x510 0x017 0x0 0x1
+				0x4d8 0x001 0x0 0x1
+				0x598 0x0e0 0x0 0x1
+				0x59c 0x0c8 0x0 0x1
+				0x5a0 0x0c8 0x0 0x1
+				0x5a4 0x009 0x0 0x1
+				0x5a8 0x0b1 0x0 0x1
+				0x584 0x024 0x0 0x1
+				0x588 0x0e4 0x0 0x1
+				0x58c 0x0ec 0x0 0x1
+				0x590 0x039 0x0 0x1
+				0x594 0x036 0x0 0x1
+				0x570 0x0ef 0x0 0x1
+				0x574 0x0ef 0x0 0x1
+				0x578 0x02f 0x0 0x1
+				0x57c 0x0d3 0x0 0x1
+				0x580 0x040 0x0 0x1
+				0x4fc 0x000 0x0 0x1
+				0x4f8 0x0c0 0x0 0x1
+				0x9a4 0x001 0x0 0x1
+				0x840 0x001 0x0 0x1
+				0x848 0x001 0x0 0x1
+				0x8a0 0x011 0x0 0x1
+				0x988 0x088 0x0 0x1
+				0x998 0x008 0x0 0x1
+				0x8dc 0x00d 0x0 0x1
+				0x800 0x000 0x0 0x1
+				0x844 0x003 0x0 0x1>;
+
+		status = "disabled";
+	};
+
 	gdsc_emac: qcom,gdsc@147004 {
 		compatible = "qcom,gdsc";
 		regulator-name = "gdsc_emac";
@@ -606,8 +742,6 @@
 		qcom,mhi-event-ring-id-limits = <9 10>; /* start and end */
 		qcom,modem-cfg-emb-pipe-flt;
 		qcom,use-ipa-pm;
-		qcom,arm-smmu;
-		qcom,smmu-fast-map;
 		qcom,bandwidth-vote-for-ipa;
 		qcom,msm-bus,name = "ipa";
 		qcom,msm-bus,num-cases = <5>;
@@ -746,30 +880,6 @@
 			compatible = "qcom,smp2pgpio-map-ipa-1-in";
 			gpios = <&smp2pgpio_ipa_1_in 0 0>;
 		};
-
-		ipa_smmu_ap: ipa_smmu_ap {
-			compatible = "qcom,ipa-smmu-ap-cb";
-			iommus = <&apps_smmu 0x5E0 0x0>;
-			qcom,iova-mapping = <0x20000000 0x40000000>;
-			qcom,additional-mapping =
-			/* modem tables in IMEM */
-			<0x14686000 0x14686000 0x3000>;
-			qcom,ipa-q6-smem-size = <16384>;
-		};
-
-		ipa_smmu_wlan: ipa_smmu_wlan {
-			compatible = "qcom,ipa-smmu-wlan-cb";
-			iommus = <&apps_smmu 0x5E1 0x0>;
-			qcom,additional-mapping =
-			/* ipa-uc ram */
-			<0x1E60000 0x1E60000 0xA000>;
-		};
-
-		ipa_smmu_uc: ipa_smmu_uc {
-			compatible = "qcom,ipa-smmu-uc-cb";
-			iommus = <&apps_smmu 0x5E2 0x0>;
-			qcom,iova-mapping = <0x40000000 0x20000000>;
-		};
 	};
 
 	qmp_aop: qcom,qmp-aop@c300000 {
@@ -801,6 +911,11 @@
 		qcom,bark-time = <11000>;
 		qcom,pet-time = <10000>;
 	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>;
+	};
 };
 
 #include "pmxpoorwills.dtsi"
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 98c0aa6..d1dc88e 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -302,6 +302,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -351,6 +352,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -358,7 +360,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -367,6 +395,21 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_PARANOID_SD_INIT=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 38e79f5..2029932 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -312,6 +312,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -362,6 +363,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -369,7 +371,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -378,6 +406,21 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 865406f..1cde900 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -387,6 +387,7 @@
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_DEBUG_USER=y
 CONFIG_CORESIGHT=y
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 28dcd44..dad9fcb 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/sched_energy.h>
 
 #include <asm/cputype.h>
 #include <asm/topology.h>
@@ -505,125 +506,31 @@
 	update_cpu_capacity(cpuid);
 }
 
-/*
- * ARM TC2 specific energy cost model data. There are no unit requirements for
- * the data. Data can be normalized to any reference point, but the
- * normalization must be consistent. That is, one bogo-joule/watt must be the
- * same quantity for all data, but we don't care what it is.
- */
-static struct idle_state idle_states_cluster_a7[] = {
-	 { .power = 25 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 25 }, /* WFI */
-	 { .power = 10 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_cluster_a15[] = {
-	 { .power = 70 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 70 }, /* WFI */
-	 { .power = 25 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_cluster_a7[] = {
-	/* Cluster only power */
-	 { .cap =  150, .power = 2967, }, /*  350 MHz */
-	 { .cap =  172, .power = 2792, }, /*  400 MHz */
-	 { .cap =  215, .power = 2810, }, /*  500 MHz */
-	 { .cap =  258, .power = 2815, }, /*  600 MHz */
-	 { .cap =  301, .power = 2919, }, /*  700 MHz */
-	 { .cap =  344, .power = 2847, }, /*  800 MHz */
-	 { .cap =  387, .power = 3917, }, /*  900 MHz */
-	 { .cap =  430, .power = 4905, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_cluster_a15[] = {
-	/* Cluster only power */
-	 { .cap =  426, .power =  7920, }, /*  500 MHz */
-	 { .cap =  512, .power =  8165, }, /*  600 MHz */
-	 { .cap =  597, .power =  8172, }, /*  700 MHz */
-	 { .cap =  682, .power =  8195, }, /*  800 MHz */
-	 { .cap =  768, .power =  8265, }, /*  900 MHz */
-	 { .cap =  853, .power =  8446, }, /* 1000 MHz */
-	 { .cap =  938, .power = 11426, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 15200, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_cluster_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a7),
-	  .idle_states    = idle_states_cluster_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a7),
-	  .cap_states     = cap_states_cluster_a7,
-};
-
-static struct sched_group_energy energy_cluster_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a15),
-	  .idle_states    = idle_states_cluster_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a15),
-	  .cap_states     = cap_states_cluster_a15,
-};
-
-static struct idle_state idle_states_core_a7[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_core_a15[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_core_a7[] = {
-	/* Power per cpu */
-	 { .cap =  150, .power =  187, }, /*  350 MHz */
-	 { .cap =  172, .power =  275, }, /*  400 MHz */
-	 { .cap =  215, .power =  334, }, /*  500 MHz */
-	 { .cap =  258, .power =  407, }, /*  600 MHz */
-	 { .cap =  301, .power =  447, }, /*  700 MHz */
-	 { .cap =  344, .power =  549, }, /*  800 MHz */
-	 { .cap =  387, .power =  761, }, /*  900 MHz */
-	 { .cap =  430, .power = 1024, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_core_a15[] = {
-	/* Power per cpu */
-	 { .cap =  426, .power = 2021, }, /*  500 MHz */
-	 { .cap =  512, .power = 2312, }, /*  600 MHz */
-	 { .cap =  597, .power = 2756, }, /*  700 MHz */
-	 { .cap =  682, .power = 3125, }, /*  800 MHz */
-	 { .cap =  768, .power = 3524, }, /*  900 MHz */
-	 { .cap =  853, .power = 3846, }, /* 1000 MHz */
-	 { .cap =  938, .power = 5177, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 6997, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_core_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a7),
-	  .idle_states    = idle_states_core_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a7),
-	  .cap_states     = cap_states_core_a7,
-};
-
-static struct sched_group_energy energy_core_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a15),
-	  .idle_states    = idle_states_core_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a15),
-	  .cap_states     = cap_states_core_a15,
-};
-
 /* sd energy functions */
 static inline
 const struct sched_group_energy * const cpu_cluster_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_cluster_a7 :
-			&energy_cluster_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline
 const struct sched_group_energy * const cpu_core_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_core_a7 :
-			&energy_core_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline int cpu_corepower_flags(void)
@@ -688,4 +595,5 @@
 
 	/* Set scheduler topology descriptor */
 	set_sched_topology(arm_topology);
+	init_sched_energy_costs();
 }
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 32a80d6..cf5311f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -432,6 +432,20 @@
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_1024718
+	bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+	default y
+	help
+	  This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+	  Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+	  update of the hardware dirty bit when the DBM/AP bits are updated
+	  without a break-before-make. The work around is to disable the usage
+	  of hardware DBM locally on the affected cores. CPUs not affected by
+	  erratum will continue to use the feature.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b7640d3..1de858e 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -181,6 +181,24 @@
 	  This enables support for the sdm632 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
 
+config ARCH_SDM429
+	bool "Enable Support for Qualcomm Technologies Inc. SDM429"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm429 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
+config ARCH_SDM439
+	bool "Enable Support for Qualcomm Technologies Inc. SDM439"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm439 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
 	bool "Rockchip Platforms"
 	select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 1390a7b..7e5cdf2 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -34,12 +34,14 @@
 		sda845-v2-mtp-overlay.dtbo \
 		sda845-v2-qrd-overlay.dtbo \
 		sda845-v2-hdk-overlay.dtbo \
+		sda845-v2-svr-overlay.dtbo \
 		sda845-v2-4k-panel-mtp-overlay.dtbo \
 		sda845-v2-4k-panel-cdp-overlay.dtbo \
 		sda845-v2-4k-panel-qrd-overlay.dtbo \
 		sda845-v2.1-cdp-overlay.dtbo \
 		sda845-v2.1-mtp-overlay.dtbo \
 		sda845-v2.1-qrd-overlay.dtbo \
+		sda845-v2.1-svr-overlay.dtbo \
 		sda845-v2.1-4k-panel-cdp-overlay.dtbo \
 		sda845-v2.1-4k-panel-mtp-overlay.dtbo \
 		sda845-v2.1-4k-panel-qrd-overlay.dtbo \
@@ -77,12 +79,14 @@
 sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-hdk-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-svr-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2.1-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-svr-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb
@@ -169,7 +173,7 @@
 qcs605-cdp-overlay.dtbo-base := qcs605.dtb
 qcs605-mtp-overlay.dtbo-base := qcs605.dtb
 qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
-qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb
 qcs605-360camera-overlay.dtbo-base := qcs605.dtb
 
 else
@@ -201,8 +205,7 @@
 	qcs605-360camera.dtb \
 	qcs605-mtp.dtb \
 	qcs605-cdp.dtb \
-	qcs605-external-codec-mtp.dtb \
-	qcs605-lc-mtp.dtb
+	qcs605-external-codec-mtp.dtb
 endif
 
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
index bf9e2f2..6bb67c3 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "apq8053.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
new file mode 100644
index 0000000..77f2a1d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -0,0 +1,133 @@
+/* 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_hx8399c_truly_vid: qcom,mdss_dsi_hx8399c_truly_video{
+		qcom,mdss-dsi-panel-name =
+			"hx8399c video mode dsi truly panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <2160>;
+		qcom,mdss-dsi-h-front-porch = <24>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <40>;
+		qcom,mdss-dsi-v-front-porch = <36>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		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-on-command = [
+			39 01 00 00 00 00 04
+				b9 ff 83 99
+			39 01 00 00 00 00 02
+				d2 88
+			39 01 00 00 00 00 10
+				b1 02 04 74 94 01 32 33
+				11 11 e6 5d 56 73 02 02
+			39 01 00 00 00 00 10
+				b2 00 80 80 cc 05 07 5a
+				11 10 10 00 1e 70 03 D4
+			39 01 00 00 00 00 2d
+				b4 00 ff 59 59 0c ac 00
+				00 0c 00 07 0a 00 28 07
+				08 0c 21 03 00 00 00 ae
+				87 59 59 0c ac 00 00 0c
+				00 07 0a 00 28 07 08 0c
+				01 00 00 ae 01
+			39 01 00 00 05 00 22
+				d3 00 00 01 01 00 00 10
+				10 00 00 03 00 03 00 08
+				78 08 78 00 00 00 00 00
+				24 02 05 05 03 00 00 00
+				05 40
+			39 01 00 00 05 00 21
+				d5 20 20 19 19 18 18 02
+				03 00 01 24 24 18 18 18
+				18 24 24 00 00 00 00 00
+				00 00 00 2f 2f 30 30 31
+				31
+			39 01 00 00 05 00 21
+				d6 24 24 18 18 19 19 01
+				00 03 02 24 24 18 18 18
+				18 20 20 40 40 40 40 40
+				40 40 40 2f 2f 30 30 31
+				31
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 00 00 11
+				d8 aa aa aa aa aa aa aa
+				aa aa ba aa aa aa ba aa
+				aa
+			39 01 00 00 00 00 02
+				bd 01
+			39 01 00 00 00 00 11
+				d8 82 ea aa aa 82 ea aa
+				aa 82 ea aa aa 82 ea aa
+				aa
+			39 01 00 00 00 00 02
+				bd 02
+			39 01 00 00 00 00 09
+				d8 ff ff c0 3f ff ff c0
+				3f
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 05 00 37
+				e0 08 2a 39 35 74 7c 87
+				7f 84 8a 8e 91 93 96 9b
+				9c 9e a5 a6 ae a1 af b2
+				5c 58 63 74 08 2a 39 35
+				74 7c 87 7f 84 8a 8e 91
+				93 96 9b 9c 9e a5 a6 ae
+				a1 af b2 5c 58 63 74
+			39 01 00 00 00 00 03
+				b6 7e 7e
+			39 01 00 00 00 00 02
+				cc 08
+			39 01 00 00 00 00 06
+				c7 00 08 00 01 08
+			39 01 00 00 00 00 03
+				c0 25 5a
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 14 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		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-t-clk-post = <0x0e>;
+		qcom,mdss-dsi-t-clk-pre = <0x31>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
new file mode 100644
index 0000000..3a5d272
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
@@ -0,0 +1,50 @@
+/* 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_dual_test_cmd: qcom,mdss_dsi_test_oled_cmd {
+		qcom,mdss-dsi-panel-name =
+			"Dual test cmd mode DSI amoled non-DSC panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <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-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		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,adjust-timer-wakeup-ms = <1>;
+		qcom,mdss-dsi-reset-sequence = <1 2>, <0 2>, <1 2>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-hfp-power-mode;
+		qcom,mdss-dsi-hbp-power-mode;
+		qcom,mdss-dsi-hsa-power-mode;
+		qcom,mdss-dsi-display-timings {
+			timing@0{
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
new file mode 100644
index 0000000..5c379d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+qcom,fg-gen3-batterydata-demo-3600mah {
+	qcom,faschg-current-ma = <5000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,nom-batt-capacity-mah = <3600>;
+	qcom,batt-id-kohm = <100>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "fg-gen3-batterydata-demo-3600mah";
+	qcom,checksum = <0xA401>;
+	qcom,gui-version = "PMI8998GUI - 2.0.0.54";
+	qcom,fg-profile-data = [
+		B2 1F 79 05
+		86 0A 36 06
+		8D 1D 6F F4
+		39 12 9A 14
+		DC 18 91 22
+		26 3C EB 4B
+		5D 00 00 00
+		11 00 00 00
+		00 00 78 BC
+		26 CD 48 C2
+		1E 00 08 00
+		78 C5 64 E5
+		95 FC 1D F3
+		E1 F5 ED 0B
+		33 FD 8C 2B
+		1E 06 09 20
+		27 00 14 00
+		D8 1F 77 05
+		8B 0A 57 FC
+		59 1D 8B 00
+		33 03 78 0C
+		0F 19 ED 22
+		6B 45 21 53
+		5A 00 00 00
+		0E 00 00 00
+		00 00 F7 07
+		55 C2 AA AA
+		1A 00 00 00
+		B1 EA 64 E5
+		7C 06 93 F2
+		71 FD 9E 03
+		80 0A 7A 22
+		CF 33 CC FF
+		07 10 00 00
+		6F 0E 99 45
+		1A 00 40 00
+		13 01 0A FA
+		FF 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
index d0eff96..3da16e4 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -33,11 +33,11 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
diff --git a/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
new file mode 100644
index 0000000..d5537e9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
@@ -0,0 +1,229 @@
+/* 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.
+ */
+&soc {
+	qcom,smp2p-modem@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from wcnss. */
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to wcnss */
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 285727d..baa6ad5 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -121,6 +121,7 @@
 #include "msm8937-pinctrl.dtsi"
 #include "msm8937-cpu.dtsi"
 #include "msm8937-ion.dtsi"
+#include "msm8937-smp2p.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -234,6 +235,174 @@
 		qcom,pipe-attr-ee;
 	};
 
+	thermal_zones: thermal-zones {
+		aoss0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 0>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		mdm-core-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 1>;
+			trips {
+				active-config0 {
+						temperature = <125000>;
+						hysteresis = <1000>;
+						type = "passive";
+				};
+			};
+		};
+
+		mdss-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 2>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		camera-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 3>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		cpuss-0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 4>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu1-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 5>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu2-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 6>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu3-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 7>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu4-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 8>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc0_cpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 9>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		gpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 10>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+	};
+
+	tsens0: tsens@4a8000 {
+		compatible = "qcom,msm8937-tsens";
+		reg = <0x4a8000 0x1000>,
+			<0x4a9000 0x1000>,
+			<0xa4000  0x1000>;
+		reg-names = "tsens_srot_physical",
+			"tsens_tm_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		interrupt-names = "tsens-upper-lower";
+		#thermal-sensor-cells = <1>;
+	};
+
 	slim_msm: slim@c140000{
 		cell-index = <1>;
 		compatible = "qcom,slim-ngd";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
index 34004b0..00203a2 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -32,5 +32,11 @@
 			memory-region = <&qseecom_mem>;
 			qcom,ion-heap-type = "DMA";
 		};
+
+		qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+			reg = <19>;
+			memory-region = <&qseecom_ta_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index 4fa5cd1..28a6b74 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -23,6 +23,7 @@
 #include "dsi-panel-truly-wuxga-video.dtsi"
 #include "dsi-panel-lt8912-480p-video.dtsi"
 #include "dsi-panel-lt8912-1080p-video.dtsi"
+#include "dsi-panel-hx8399c-fhd-plus-video.dtsi"
 
 &soc {
 	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -55,6 +56,9 @@
 		23 1e 08 09 05 03 04 a0
 		23 1e 08 09 05 03 04 a0
 		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+
 };
 
 &dsi_truly_1080_cmd {
@@ -63,6 +67,8 @@
 		23 1e 08 09 05 03 04 a0
 		23 1e 08 09 05 03 04 a0
 		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
 };
 
 &dsi_r69006_1080p_video {
@@ -81,6 +87,27 @@
 		24 1b 08 09 05 03 04 a0];
 };
 
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+	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_lp_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-panel-max-error-count = <3>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+};
+
 &dsi_adv7533_1080p {
 	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
 		24 1f 08 09 05 03 04 a0
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
index 49956df..c6ae512 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -20,3 +20,21 @@
 	model = "MTP";
 	qcom,board-id = <8 0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index b53f7b8..97c6db3 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -33,16 +33,12 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
 };
-
-&usb3 {
-	extcon = <&pmi8950_charger>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
index a9f64a4..5ec92ae 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
index a208e1a..80050c4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
@@ -24,10 +24,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8937_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8937_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
index e9c80a0d..ba5c3c7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
index 28fc0d7..c36dd1b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
@@ -24,7 +24,7 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8940_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
 &labibb {
@@ -36,7 +36,7 @@
 	qcom,qpnp-ibb-discharge-resistor = <32>;
 };
 
-&pmi8940_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index 139ef1e..d81a0a5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -29,10 +29,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8950_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
@@ -46,23 +46,3 @@
 	lab-supply = <&lab_regulator>;
 	ibb-supply = <&ibb_regulator>;
 };
-
-&dsi_panel_pwr_supply {
-		qcom,panel-supply-entry@2 {
-			reg = <2>;
-			qcom,supply-name = "lab";
-			qcom,supply-min-voltage = <4600000>;
-			qcom,supply-max-voltage = <6000000>;
-			qcom,supply-enable-load = <100000>;
-			qcom,supply-disable-load = <100>;
-		};
-		qcom,panel-supply-entry@3 {
-			reg = <3>;
-			qcom,supply-name = "ibb";
-			qcom,supply-min-voltage = <4600000>;
-			qcom,supply-max-voltage = <6000000>;
-			qcom,supply-enable-load = <100000>;
-			qcom,supply-disable-load = <100>;
-			qcom,supply-post-on-sleep = <10>;
-		};
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
new file mode 100644
index 0000000..e82e2c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
@@ -0,0 +1,227 @@
+/* Copyright (c) 2015-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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+&soc {
+	qcom,smp2p-modem@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
new file mode 100644
index 0000000..cb8cdf2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
@@ -0,0 +1,197 @@
+/* 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.
+ */
+
+&soc {
+	qcom,vidc@1d00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0x01d00000 0xff000>,
+			<0x000a4124 0x4>,
+			<0x000a0164 0x4>;
+		reg-names = "vidc", "efuse", "efuse2";
+		qcom,platform-version = <0x00180000 0x13>;
+		qcom,capability-version = <0x00002000 0x0d>;
+		interrupts = <0 44 0>;
+		/* Regulators */
+		venus-supply = <&gdsc_venus>;
+		venus-core0-supply = <&gdsc_venus_core0>;
+		/* Clocks */
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_ahb_clk>,
+			<&clock_gcc clk_gcc_venus0_axi_clk>;
+		clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+		qcom,clock-configs = <0x1 0x0 0x0 0x0 0x0>;
+		qcom,hfi = "venus";
+		qcom,hfi-version = "3xx";
+		qcom,reg-presets = <0xe0020 0x05555556>,
+			<0xe0024 0x05555556>,
+			<0x80124 0x00000003>;
+		qcom,qdss-presets = <0x825000 0x1000>,
+			<0x826000 0x1000>,
+			<0x821000 0x1000>,
+			<0x802000 0x1000>,
+			<0x9180000 0x1000>,
+			<0x9181000 0x1000>;
+		qcom,max-hw-load = <1044480>; /* 4096 x 2176 @ 30 fps */
+		qcom,slave-side-cp;
+		qcom,sw-power-collapse;
+		qcom,firmware-name = "venus";
+		qcom,pm-qos-latency-us = <213>;
+		qcom,dcvs-tbl =
+			/* Dec UHD@30 H.264, HEVC, VP8, VP9 - NOM to NOM+*/
+			<816000 816000 979200 0x3f00000c>,
+
+			/* Enc 3840x1920@30 H.264/HEVC Turbo to Nom+ */
+			<855000 821100 979200 0x4000004>,
+
+			/* Enc True4K@24 H.264/HEVC Nom to Nom+ */
+			<816000 720000 835584 0x4000004>;
+		qcom,dcvs-limit =
+			<28800 24>, /* Encoder 3840x1920 */
+			<32400 24>; /* Decoder UHD */
+		qcom,allowed-clock-rates = <465000000 400000000
+			360000000 310000000 228570000 114290000>;
+		qcom,clock-freq-tbl {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,cycles-per-mb = <863>;
+				qcom,low-power-mode-factor = <35616>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xf3ffffff>;
+				qcom,cycles-per-mb = <355>;
+			};
+			qcom,profile-hevcdec {
+				qcom,codec-mask = <0x0c000000>;
+				qcom,cycles-per-mb = <400>;
+			};
+		};
+
+		/* MMUs */
+		non_secure_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_ns";
+			iommus = <&apps_iommu 0x800 0x01>,
+				<&apps_iommu 0x807 0x00>,
+				<&apps_iommu 0x808 0x07>,
+				<&apps_iommu 0x810 0x01>,
+				<&apps_iommu 0x828 0x01>,
+				<&apps_iommu 0x82c 0x01>,
+				<&apps_iommu 0x821 0x10>;
+			buffer-types = <0xfff>;
+			virtual-addr-pool = <0x5dc00000 0x7f000000
+				0xdcc00000 0x1000000>;
+		};
+
+		secure_bitstream_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_bitstream";
+			 iommus = <&apps_iommu 0x900 0x0>,
+				<&apps_iommu 0x902 0x8>,
+				<&apps_iommu 0x909 0x2>,
+				<&apps_iommu 0x90e 0x0>,
+				<&apps_iommu 0x926 0x0>,
+				<&apps_iommu 0x929 0x2>;
+			buffer-types = <0x241>;
+			virtual-addr-pool = <0x4b000000 0x12c00000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_pixel";
+			iommus = <&apps_iommu 0x904 0x8>,
+				<&apps_iommu 0x910 0x0>,
+				<&apps_iommu 0x92c 0x0>;
+			buffer-types = <0x106>;
+			virtual-addr-pool = <0x25800000 0x25800000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_non_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_non_pixel";
+			iommus = <&apps_iommu 0x908 0x0>,
+				<&apps_iommu 0x905 0xa>,
+				<&apps_iommu 0x925 0x8>,
+				<&apps_iommu 0x928 0x0>;
+			buffer-types = <0x480>;
+			virtual-addr-pool = <0x1000000 0x24800000>;
+			qcom,secure-context-bank;
+		};
+
+		/* Buses */
+		venus_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "venus-ddr-gov";
+			qcom,bus-range-kbps = <1000 2365000>;
+		};
+
+		arm9_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-arm9-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "performance";
+			qcom,bus-range-kbps = <1 1>;
+		};
+	};
+
+	venus-ddr-gov {
+		compatible = "qcom,msm-vidc,governor,table";
+		name = "venus-ddr-gov";
+		status = "ok";
+		qcom,bus-freq-table {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,load-busfreq-tbl =
+					<979200 1044000>,  /* UHD30E     */
+					<864000 887000>,   /* 720p240LPE */
+					<489600 666000>,   /* 1080p60E   */
+					<432000 578000>,   /* 720p120E   */
+					<244800 346000>,   /* 1080p30E   */
+					<216000 293000>,   /* 720p60E    */
+					<108000 151000>,   /* 720p30E    */
+					<0 0>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,load-busfreq-tbl =
+					<979200 2365000>,  /* UHD30D     */
+					<864000 1978000>,  /* 720p240D   */
+					<489600 1133000>,  /* 1080p60D   */
+					<432000 994000>,   /* 720p120D   */
+					<244800 580000>,   /* 1080p30D   */
+					<216000 501000>,   /* 720p60E    */
+					<108000 255000>,   /* 720p30D    */
+					<0 0>;
+			};
+			qcom,profile-dec-ubwc {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,ubwc-mode;
+				qcom,load-busfreq-tbl =
+					<979200 1892000>,  /* UHD30D     */
+					<864000 1554000>,  /* 720p240D   */
+					<489600 895000>,   /* 1080p60D   */
+					<432000 781000>,   /* 720p120D   */
+					<244800 460000>,   /* 1080p30D   */
+					<216000 301000>,   /* 720p60E    */
+					<108000 202000>,   /* 720p30D    */
+					<0 0>;
+			};
+		};
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
index ddf2218..2f6cbc4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 2861fd5..90eb0bb 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -103,6 +103,14 @@
 			compatible = "shared-dma-pool";
 			reusable;
 			alignment = <0 0x400000>;
+			size = <0 0x0400000>;
+		};
+
+		qseecom_ta_mem: qseecom_ta_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
 			size = <0 0x1000000>;
 		};
 
@@ -164,9 +172,11 @@
 #include "msm8953-coresight.dtsi"
 #include "msm8953-ion.dtsi"
 #include "msm-arm-smmu-8953.dtsi"
+#include "msm8953-vidc.dtsi"
 #include "msm8953-gpu.dtsi"
 #include "msm8953-mdss.dtsi"
 #include "msm8953-mdss-pll.dtsi"
+#include "msm8953-smp2p.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -1160,6 +1170,11 @@
 			reg = <0x94c 200>;
 
 		};
+
+		diag_dload@c8 {
+			compatible = "qcom,msm-imem-diag-dload";
+			reg = <0xc8 200>;
+		};
 	};
 
 	qcom,memshare {
@@ -1876,6 +1891,11 @@
 		qcom,wcnss-adc_tm = <&pm8953_adc_tm>;
 	};
 
+	ssc_sensors: qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		status = "ok";
+	};
+
 };
 
 #include "pm8953-rpm-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index e5963ef..3561656 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -214,6 +214,151 @@
 			#gpio-cells = <2>;
 			qcom,gpios-disallowed = <1>;
 		};
+
+		pmi632_charger: qcom,qpnp-smb5 {
+			compatible = "qcom,qpnp-smb5";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,pmic-revid = <&pmi632_revid>;
+			dpdm-supply = <&qusb_phy>;
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =
+					<0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x10 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "chgr-error",
+						  "chg-state-change",
+						  "step-chg-state-change",
+						  "step-chg-soc-update-fail",
+						  "step-chg-soc-update-req",
+						  "fg-fvcal-qualified",
+						  "vph-alarm",
+						  "vph-drop-prechg";
+			};
+
+			qcom,dcdc@1100 {
+				reg = <0x1100 0x100>;
+				interrupts =
+					<0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "otg-fail",
+						  "otg-oc-disable-sw",
+						  "otg-oc-hiccup",
+						  "bsm-active",
+						  "high-duty-cycle",
+						  "input-current-limiting",
+						  "concurrent-mode-disable",
+						  "switcher-power-ok";
+			};
+
+			qcom,batif@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =
+					<0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "bat-temp",
+						  "all-chnl-conv-done",
+						  "bat-ov",
+						  "bat-low",
+						  "bat-therm-or-id-missing",
+						  "bat-terminal-missing",
+						  "buck-oc",
+						  "vph-ov";
+			};
+
+			qcom,usb@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =
+					<0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x5 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "usbin-collapse",
+						  "usbin-vashdn",
+						  "usbin-uv",
+						  "usbin-ov",
+						  "usbin-plugin",
+						  "usbin-revi-change",
+						  "usbin-src-change",
+						  "usbin-icl-change";
+			};
+
+			qcom,typec@1500 {
+				reg = <0x1500 0x100>;
+				interrupts =
+					<0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x1 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "typec-or-rid-detect-change",
+						  "typec-vpd-detect",
+						  "typec-cc-state-change",
+						  "typec-vconn-oc",
+						  "typec-vbus-change",
+						  "typec-attach-detach",
+						  "typec-legacy-cable-detect",
+						  "typec-try-snk-src-detect";
+			};
+
+			qcom,misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts =
+					<0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x2 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+					<0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "wdog-snarl",
+						  "wdog-bark",
+						  "aicl-fail",
+						  "aicl-done",
+						  "smb-en",
+						  "imp-trigger",
+						  "temp-change",
+						  "temp-change-smb";
+			};
+
+			smb5_vbus: qcom,smb5-vbus {
+				regulator-name = "smb5-vbus";
+			};
+		};
 	};
 
 	pmi632_3: qcom,pmi632@3 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index a7aa08a..c72225d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -153,7 +153,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8937_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -268,7 +268,7 @@
 			};
 		};
 
-		pmi8937_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index c6d5c87..d83145c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -152,7 +152,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8940_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -264,7 +264,7 @@
 			};
 		};
 
-		pmi8940_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 4e82cfe..e3388c1 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -168,7 +168,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8950_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -284,7 +284,7 @@
 			};
 		};
 
-		pmi8950_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
index 01471b6..1429880 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-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-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
index ea10fa0..6c6012e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.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/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
index 025d9a2..d0b5bf3 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -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
@@ -10,196 +10,16 @@
  * GNU General Public License for more details.
  */
 
-#include "pm8005.dtsi"
-#include "sdm670-pmic-overlay.dtsi"
-#include "qcs605-pm660-pm8005-regulator.dtsi"
+#include "qcs605-lc-pmic-overlay.dtsi"
 
-/ {
-	cpus {
-		/delete-node/ cpu@200;
-		/delete-node/ cpu@300;
-		/delete-node/ cpu@400;
-		/delete-node/ cpu@500;
-
-		cpu-map {
-			cluster0 {
-				/delete-node/ core2;
-				/delete-node/ core3;
-				/delete-node/ core4;
-				/delete-node/ core5;
-			};
-		};
-	};
-
-
+&qupv3_se9_2uart {
+	status = "disabled";
 };
 
-&soc {
-	/delete-node/ jtagmm@7240000;
-	/delete-node/ jtagmm@7340000;
-	/delete-node/ jtagmm@7440000;
-	/delete-node/ jtagmm@7540000;
-	/delete-node/ cti@7220000;
-	/delete-node/ cti@7320000;
-	/delete-node/ cti@7420000;
-	/delete-node/ cti@7520000;
-	/delete-node/ etm@7240000;
-	/delete-node/ etm@7340000;
-	/delete-node/ etm@7440000;
-	/delete-node/ etm@7540000;
-	cpuss_dump {
-		/delete-node/ qcom,l1_i_cache200;
-		/delete-node/ qcom,l1_i_cache300;
-		/delete-node/ qcom,l1_i_cache400;
-		/delete-node/ qcom,l1_i_cache500;
-		/delete-node/ qcom,l1_d_cache200;
-		/delete-node/ qcom,l1_d_cache300;
-		/delete-node/ qcom,l1_d_cache400;
-		/delete-node/ qcom,l1_d_cache500;
-		/delete-node/ qcom,l1_tlb_dump200;
-		/delete-node/ qcom,l1_tlb_dump300;
-		/delete-node/ qcom,l1_tlb_dump400;
-		/delete-node/ qcom,l1_tlb_dump500;
-	};
-
-	devfreq_memlat_0: qcom,cpu0-memlat-mon {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-
-	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-	devfreq_compute0: qcom,devfreq-compute0 {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-
-	funnel_apss: funnel@7800000 {
-		ports {
-			/delete-node/ port@3;
-			/delete-node/ port@4;
-			/delete-node/ port@5;
-			/delete-node/ port@6;
-		};
-	};
-
-	qcom,lpm-levels {
-		qcom,pm-cluster@0 {
-			qcom,pm-cpu@0 {
-				qcom,cpu = <&CPU0 &CPU1>;
-			};
-		};
-	};
+&qupv3_se12_2uart {
+	status = "ok";
 };
 
-&pm660_temp_alarm {
-	cooling-maps {
-		/delete-node/ trip0_cpu2;
-		/delete-node/ trip0_cpu3;
-		/delete-node/ trip0_cpu4;
-		/delete-node/ trip0_cpu5;
-		/delete-node/ trip1_cpu2;
-		/delete-node/ trip1_cpu3;
-		/delete-node/ trip1_cpu4;
-		/delete-node/ trip1_cpu5;
-	};
-};
-
-&thermal_zones {
-
-	xo-therm-cpu-step {
-		cooling-maps {
-			/delete-node/ skin_cpu2;
-			/delete-node/ skin_cpu3;
-			/delete-node/ skin_cpu4;
-			/delete-node/ skin_cpu5;
-		};
-	};
-};
-
-&spmi_bus {
-	/delete-node/ qcom,pm660l@2;
-	/delete-node/ qcom,pm660l@3;
-};
-
-&thermal_zones {
-	pm660l_tz {
-		/delete-property/ thermal-sensors;
-	};
-};
-
-&soc {
-	qcom,turing@8300000 {
-		/delete-property/ vdd_cx-supply;
-	};
-
-	qcom,lpass@62400000 {
-		/delete-property/ vdd_cx-supply;
-	};
-};
-
-&clock_cpucc {
-	/delete-property/ vdd_l3_mx_ao-supply;
-	/delete-property/ vdd_pwrcl_mx_ao-supply;
-};
-
-&clock_gcc {
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_cx_ao-supply;
-};
-
-&clock_videocc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_camcc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_dispcc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_gpucc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&pil_modem {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_mss-supply;
-};
-
-&clock_gfx {
-	/delete-property/ vdd_gfx-supply;
-};
-
-&gpu_gx_gdsc {
-	/delete-property/ parent-supply;
-};
-
-&mdss_dsi_phy0 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&mdss_dsi_phy1 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&sde_dp {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&qusb_phy0 {
-	/delete-property/ vdd-supply;
-	/delete-property/ vdda33-supply;
-};
-
-&usb_qmp_dp_phy {
-	/delete-property/ vdd-supply;
-};
-
-&pm660_pdphy {
-	/delete-property/ vdd-pdphy-supply;
+&qupv3_se8_spi {
+	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
new file mode 100644
index 0000000..2436687
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
@@ -0,0 +1,260 @@
+/* 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.
+ */
+
+&pm660_0 {
+	pm660_charger: qcom,qpnp-smb2 {
+		compatible = "qcom,qpnp-smb2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#cooling-cells = <2>;
+
+		qcom,pmic-revid = <&pm660_revid>;
+
+		io-channels = <&pm660_rradc 8>,
+			      <&pm660_rradc 10>,
+			      <&pm660_rradc 3>,
+			      <&pm660_rradc 4>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max",
+				   "usbin_i",
+				   "usbin_v";
+
+		qcom,wipower-max-uw = <5000000>;
+
+		dpdm-supply = <&qusb_phy0>;
+
+		qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+		qcom,auto-recharge-soc;
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =
+				<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "chg-error",
+					  "chg-state-change",
+					  "step-chg-state-change",
+					  "step-chg-soc-update-fail",
+					  "step-chg-soc-update-request";
+		};
+
+		qcom,otg@1100 {
+			reg = <0x1100 0x100>;
+			interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "otg-fail",
+					  "otg-overcurrent",
+					  "otg-oc-dis-sw-sts",
+					  "testmode-change-detect";
+		};
+
+		qcom,bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =
+				<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "bat-temp",
+					  "bat-ocp",
+					  "bat-ov",
+					  "bat-low",
+					  "bat-therm-or-id-missing",
+					  "bat-terminal-missing";
+		};
+
+		qcom,usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =
+				<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "usbin-collapse",
+					  "usbin-lt-3p6v",
+					  "usbin-uv",
+					  "usbin-ov",
+					  "usbin-plugin",
+					  "usbin-src-change",
+					  "usbin-icl-change",
+					  "type-c-change";
+		};
+
+		qcom,dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =
+				<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "dcin-collapse",
+					  "dcin-lt-3p6v",
+					  "dcin-uv",
+					  "dcin-ov",
+					  "dcin-plugin",
+					  "div2-en-dg",
+					  "dcin-icl-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts =
+				<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+				<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "wdog-snarl",
+					  "wdog-bark",
+					  "aicl-fail",
+					  "aicl-done",
+					  "high-duty-cycle",
+					  "input-current-limiting",
+					  "temperature-change",
+					  "switcher-power-ok";
+		};
+		smb2_vbus: qcom,smb2-vbus {
+			regulator-name = "smb2-vbus";
+		};
+
+		smb2_vconn: qcom,smb2-vconn {
+			regulator-name = "smb2-vconn";
+		};
+	};
+
+	pm660_rradc: rradc@4500 {
+		compatible = "qcom,rradc";
+		reg = <0x4500 0x100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#io-channel-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+	};
+
+	pm660_fg: qpnp,fg {
+		compatible = "qcom,fg-gen3";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+		io-channels = <&pm660_rradc 0>,
+			      <&pm660_rradc 7>;
+		io-channel-names = "rradc_batt_id",
+				   "rradc_die_temp";
+		qcom,rradc-base = <0x4500>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
+		qcom,fg-esr-timer-charging = <0 96>;
+		qcom,cycle-counter-en;
+		qcom,hold-soc-while-full;
+		qcom,fg-auto-recharge-soc;
+		qcom,fg-recharge-soc-thr = <98>;
+		status = "okay";
+
+		qcom,fg-batt-soc@4000 {
+			status = "okay";
+			reg = <0x4000 0x100>;
+			interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x2
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x3
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x5
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "soc-update",
+					  "soc-ready",
+					  "bsoc-delta",
+					  "msoc-delta",
+					  "msoc-low",
+					  "msoc-empty",
+					  "msoc-high",
+					  "msoc-full";
+		};
+
+		qcom,fg-batt-info@4100 {
+			status = "okay";
+			reg = <0x4100 0x100>;
+			interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "vbatt-pred-delta",
+					  "vbatt-low",
+					  "esr-delta",
+					  "batt-missing",
+					  "batt-temp-delta";
+		};
+
+		qcom,fg-memif@4400 {
+			status = "okay";
+			reg = <0x4400 0x100>;
+			interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "ima-rdy",
+					  "mem-xcp",
+					  "dma-grant";
+		};
+	};
+};
+
+&pm660_1 {
+	pm660_haptics: qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pm660_revid>;
+		qcom,pmic-misc = <&pm660_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <0>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,lra-high-z = "opt0";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
similarity index 67%
rename from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
rename to arch/arm64/boot/dts/qcom/qcs605-lc.dts
index 194bfeb..88d838e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.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
@@ -13,12 +13,10 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "qcs605-lc.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+	model = "Qualcomm Technologies, Inc. QCS605 LC SoC";
+	compatible = "qcom,qcs605";
 	qcom,board-id = <8 4>;
-
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
new file mode 100644
index 0000000..2db6129
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#include "qcs605.dtsi"
+#include "pm8005.dtsi"
+#include "qcs605-pm660-pm8005-regulator.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QCS605 SoC";
+	compatible = "qcom,qcs605";
+
+	cpus {
+		/delete-node/ cpu@200;
+		/delete-node/ cpu@300;
+		/delete-node/ cpu@400;
+		/delete-node/ cpu@500;
+
+		cpu-map {
+			cluster0 {
+				/delete-node/ core2;
+				/delete-node/ core3;
+				/delete-node/ core4;
+				/delete-node/ core5;
+			};
+		};
+	};
+};
+
+&soc {
+	/delete-node/ jtagmm@7240000;
+	/delete-node/ jtagmm@7340000;
+	/delete-node/ jtagmm@7440000;
+	/delete-node/ jtagmm@7540000;
+	/delete-node/ cti@7220000;
+	/delete-node/ cti@7320000;
+	/delete-node/ cti@7420000;
+	/delete-node/ cti@7520000;
+	/delete-node/ etm@7240000;
+	/delete-node/ etm@7340000;
+	/delete-node/ etm@7440000;
+	/delete-node/ etm@7540000;
+	cpuss_dump {
+		/delete-node/ qcom,l1_i_cache200;
+		/delete-node/ qcom,l1_i_cache300;
+		/delete-node/ qcom,l1_i_cache400;
+		/delete-node/ qcom,l1_i_cache500;
+		/delete-node/ qcom,l1_d_cache200;
+		/delete-node/ qcom,l1_d_cache300;
+		/delete-node/ qcom,l1_d_cache400;
+		/delete-node/ qcom,l1_d_cache500;
+		/delete-node/ qcom,l1_tlb_dump200;
+		/delete-node/ qcom,l1_tlb_dump300;
+		/delete-node/ qcom,l1_tlb_dump400;
+		/delete-node/ qcom,l1_tlb_dump500;
+	};
+
+	devfreq_memlat_0: qcom,cpu0-memlat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+	devfreq_compute0: qcom,devfreq-compute0 {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	funnel_apss: funnel@7800000 {
+		ports {
+			/delete-node/ port@3;
+			/delete-node/ port@4;
+			/delete-node/ port@5;
+			/delete-node/ port@6;
+		};
+	};
+
+	qcom,lpm-levels {
+		qcom,pm-cluster@0 {
+			qcom,pm-cpu@0 {
+				qcom,cpu = <&CPU0 &CPU1>;
+			};
+		};
+	};
+};
+
+&pm660_temp_alarm {
+	cooling-maps {
+		/delete-node/ trip0_cpu2;
+		/delete-node/ trip0_cpu3;
+		/delete-node/ trip0_cpu4;
+		/delete-node/ trip0_cpu5;
+		/delete-node/ trip1_cpu2;
+		/delete-node/ trip1_cpu3;
+		/delete-node/ trip1_cpu4;
+		/delete-node/ trip1_cpu5;
+	};
+};
+
+&thermal_zones {
+
+	xo-therm-cpu-step {
+		cooling-maps {
+			/delete-node/ skin_cpu2;
+			/delete-node/ skin_cpu3;
+			/delete-node/ skin_cpu4;
+			/delete-node/ skin_cpu5;
+		};
+	};
+};
+
+&spmi_bus {
+	/delete-node/ qcom,pm660l@2;
+	/delete-node/ qcom,pm660l@3;
+};
+
+&thermal_zones {
+	pm660l_tz {
+		/delete-property/ thermal-sensors;
+	};
+};
+
+&soc {
+	qcom,turing@8300000 {
+		/delete-property/ vdd_cx-supply;
+	};
+
+	qcom,lpass@62400000 {
+		/delete-property/ vdd_cx-supply;
+	};
+};
+
+&clock_cpucc {
+	/delete-property/ vdd_l3_mx_ao-supply;
+	/delete-property/ vdd_pwrcl_mx_ao-supply;
+};
+
+&clock_gcc {
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_cx_ao-supply;
+};
+
+&clock_videocc {
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_camcc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_dispcc {
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_gpucc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+};
+
+&pil_modem {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_mss-supply;
+};
+
+&clock_gfx {
+	/delete-property/ vdd_gfx-supply;
+};
+
+&gpu_gx_gdsc {
+	/delete-property/ parent-supply;
+};
+
+&mdss_dsi_phy0 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&mdss_dsi_phy1 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&sde_dp {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&qusb_phy0 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+	/delete-property/ vdd-supply;
+};
+
+&pm660_pdphy {
+	/delete-property/ vdd-pdphy-supply;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..c76ef2b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
@@ -0,0 +1,97 @@
+/* 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.
+ */
+
+&cam_sensor_mclk0_active{
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-disable; /* No PULL */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_mclk0_suspend {
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_active {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_suspend {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
+
+&cam_sensor_front_active{
+	/* RESET  AVDD_LDO*/
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_front_suspend{
+	/* RESET */
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
new file mode 100644
index 0000000..fa82be2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -0,0 +1,548 @@
+/* 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.
+ */
+
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+#include "sda845-svr-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-svr.dtsi"
+#include "smb1355.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+&vendor {
+	bluetooth: bt_wcn3990 {
+		compatible = "qca,wcn3990";
+		qca,bt-vdd-io-supply = <&pm8998_s3>;
+		qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+		qca,bt-vdd-core-supply = <&pm8998_l7>;
+		qca,bt-vdd-pa-supply = <&pm8998_l17>;
+		qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+		qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+		qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+		qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+		qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+		qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+		qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+	};
+
+	svr_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-demo-3600mah.dtsi"
+	};
+};
+
+&pmi8998_pdphy {
+	vbus-supply = <&smb2_vbus>;
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&pmi8998_fg {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,fg-bmd-en-delay-ms = <300>;
+};
+
+&pmi8998_charger {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,sw-jeita-enable;
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&smb1355_charger_0 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&smb1355_charger_1 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&soc {
+	qcom,qbt1000 {
+		status = "disabled";
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_vol_up_default
+				&key_home_default
+				&key_cam_focus_default>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		home {
+			label = "home"; /* BACK Key*/
+			gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <158>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+		key_cam_focus {
+			label = "Confirm"; /* Confirm Key*/
+			gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+
+	dsi_panel_pwr_supply_amoled: dsi_panel_pwr_supply_amoled {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1880000>;
+			qcom,supply-max-voltage = <1880000>;
+			qcom,supply-enable-load = <62000>;
+			qcom,supply-disable-load = <80>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "lab";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@2 {
+			reg = <2>;
+			qcom,supply-name = "ibb";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+		qcom,panel-supply-entry@3 {
+			reg = <3>;
+			qcom,supply-name = "oled-vdda";
+			qcom,supply-min-voltage = <3312000>;
+			qcom,supply-max-voltage = <3312000>;
+			qcom,supply-enable-load = <857000>;
+			qcom,supply-disable-load = <0>;
+			qcom,supply-post-on-sleep = <0>;
+		};
+	};
+};
+
+&sde_rscc {
+	status = "disabled";
+};
+
+&mdss_dsi0 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&mdss_dsi1 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&pmi8998_wled {
+	status = "ok";
+	qcom,disp-type-amoled;
+	qcom,avdd-target-voltage-mv = <7600>;
+};
+
+&labibb {
+	status = "ok";
+	qcom,qpnp-labibb-mode = "amoled";
+	qcom,swire-control;
+};
+
+&ibb_regulator {
+	status = "ok";
+	qcom,qpnp-ibb-init-amoled-voltage = <4600000>;
+	qcom,qpnp-ibb-discharge-resistor = <300>;
+};
+
+&lab_regulator {
+	status = "ok";
+	qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+};
+
+&mdss_mdp {
+	connectors = <&sde_wb &sde_dp>;
+};
+
+&dsi_dual_test_cmd {
+	qcom,mdss-dsi-t-clk-post = <0x0e>;
+	qcom,mdss-dsi-t-clk-pre = <0x35>;
+	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];
+			qcom,display-topology = <2 0 2>,
+						<2 0 2>;
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
+
+&dsi_dual_test_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply_amoled>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <255>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_dual_test_cmd_display {
+	qcom,dsi-display-active;
+};
+
+&snd_934x {
+	qcom,msm-mbhc-hphl-swh = <0>;
+};
+
+&pmi8998_haptics {
+	qcom,vmax-mv = <2400>;
+	qcom,lra-auto-mode;
+	status = "okay";
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8998_l21>;
+	qcom,vdd-voltage-level = <2950000 2960000>;
+	qcom,vdd-current-level = <200 800000>;
+
+	vdd-io-supply = <&pm8998_l13>;
+	qcom,vdd-io-voltage-level = <1808000 2960000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep", "ds_400KHz",
+			"ds_50MHz", "ds_100MHz", "ds_200MHz";
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on &storage_cd>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>;
+	pinctrl-2 = <&sdc2_clk_ds_400KHz
+			&sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>;
+	pinctrl-3 = <&sdc2_clk_ds_50MHz
+			&sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>;
+	pinctrl-4 = <&sdc2_clk_ds_100MHz
+			&sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>;
+	pinctrl-5 = <&sdc2_clk_ds_200MHz
+			&sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>;
+
+	cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+
+	status = "ok";
+};
+
+&pmi8998_switch1 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_switch2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_iris_en>;
+	pinctrl-1 = <&flash_led3_iris_dis>;
+};
+
+&vendor {
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		vbus-gpio = <&pmi8998_gpios 8 GPIO_ACTIVE_HIGH>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_vbus_det_default>;
+	};
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&qupv3_se8_spi {
+	status = "ok";
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&usb1 {
+	status = "okay";
+	extcon = <&extcon_usb1>;
+};
+
+&qusb_phy1 {
+	status = "okay";
+};
+
+&ext_5v_boost {
+	status = "ok";
+};
+
+&usb_qmp_phy {
+	status = "okay";
+};
+
+&pm8998_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@85 {
+		label = "vcoin";
+		reg = <0x85>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm8998_adc_tm {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,btm-channel-number = <0x60>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x70>;
+		qcom,thermal-node;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x78>;
+		qcom,thermal-node;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x80>;
+		qcom,thermal-node;
+	};
+};
+
+&thermal_zones {
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	msm-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4d>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm1-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4f>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	quiet-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x51>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
new file mode 100644
index 0000000..1c6db6f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
@@ -0,0 +1,31 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
similarity index 60%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
index 194bfeb..1d7bf7d 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -11,14 +10,16 @@
  * GNU General Public License for more details.
  */
 
+
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sda845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sda845-svr.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
new file mode 100644
index 0000000..b4326a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
@@ -0,0 +1,32 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2.1 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20001>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 040b4ba..5744390 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -24,3 +24,21 @@
 	qcom,board-id = <8 0>;
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
index 700e950..eb6a692 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
index f50d177..cfdd4e9 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 0a98528..9e2981a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -12,8 +12,98 @@
  */
 
 #include "msm8953-qrd.dtsi"
+#include "msm8953-mdss-panels.dtsi"
+
+&qusb_phy {
+	qcom,qusb-phy-init-seq = <0x78 0x80
+				0xb3 0x84
+				0x83 0x88
+				0xc7 0x8c
+				0x14 0x9c
+				0x30 0x08
+				0x79 0x0c
+				0x21 0x10
+				0x00 0x90
+				0x9f 0x1c
+				0x00 0x18>;
+};
 
 &i2c_3 {
 	status = "disabled";
 };
 
+&tlmm {
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+	};
+};
+
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+		qcom,supply-post-on-sleep = <10>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+	/delete-property/ vdd-supply;
+
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
index b829b81..6cdf897 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
index 7ab99a3..c8f7ac0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
@@ -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
@@ -22,6 +22,16 @@
 		status = "ok";
 	};
 
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
 	actuator_regulator: gpio-regulator@0 {
 		compatible = "regulator-fixed";
 		reg = <0x00 0x00>;
@@ -386,7 +396,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
-		led-flash-src = <&led_flash_rear>;
+		led-flash-src = <&led_flash_rear_aux>;
 		actuator-src = <&actuator_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&cam_iovdd_gpio_regulator>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 75a2762..9acef75 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -134,6 +134,28 @@
 
 		qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
 
+		qcom,soc-hw-rev-efuse = <0x414c 28 0x3>;
+
+		qcom,soc-hw-revisions {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "qcom,soc-hw-revisions";
+
+			qcom,soc-hw-revision-0 {
+				qcom,soc-hw-revision = <0>;
+				qcom,chipid = <0x06010500>;
+				qcom,gpu-quirk-hfi-use-reg;
+				qcom,gpu-quirk-limit-uche-gbif-rw;
+				qcom,gpu-quirk-mmu-secure-cb-alt;
+			};
+
+			qcom,soc-hw-revision-1 {
+				qcom,soc-hw-revision = <1>;
+				qcom,chipid = <0x06010501>;
+				qcom,gpu-quirk-hfi-use-reg;
+			};
+		};
+
 		qcom,gpu-coresights {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -485,6 +507,11 @@
 
 		gfx3d_secure: gfx3d_secure {
 			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>;
+		};
+
+		gfx3d_secure_alt: gfx3d_secure_alt {
+			compatible = "qcom,smmu-kgsl-cb";
 			iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index 5bf8df7..c54b8db 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -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
@@ -186,7 +186,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 6b24593..9d3f37d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -684,6 +684,5 @@
 		regulator-enable-ramp-delay = <5>;
 		proxy-supply = <&refgen>;
 		qcom,proxy-consumer-enable;
-		regulator-always-on;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index 007f937..a3f7b8e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -831,7 +831,7 @@
 	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-command-state = "dsi_lp_mode";
 	qcom,mdss-dsi-panel-status-value = <0x9c>;
 	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
 	qcom,mdss-dsi-panel-status-read-length = <1>;
@@ -849,6 +849,18 @@
 &dsi_hx8399_truly_cmd {
 	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,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+	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_lp_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
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index f6fa948..9903d19 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -138,7 +138,8 @@
 			 0x254 /* QUSB2PHY_TEST1 */
 			 0x198 /* PLL_BIAS_CONTROL_2 */
 			 0x228 /* QUSB2PHY_SQ_CTRL1 */
-			 0x22c>; /* QUSB2PHY_SQ_CTRL2 */
+			 0x22c /* QUSB2PHY_SQ_CTRL2 */
+			 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
 
 		qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..365b383
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
@@ -0,0 +1,377 @@
+/*
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>,
+			<&tlmm 27 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vaf = <3>;
+		gpio-req-tbl-num = <0 1 2 3>;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0",
+					"CAM_VAF";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-position = <1>;
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	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_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
new file mode 100644
index 0000000..d387f93
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
@@ -0,0 +1,479 @@
+/*
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	led_flash_iris: qcom,camera-flash@3 {
+		cell-index = <3>;
+		reg = <0x03 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch2>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	qcom,cam-res-mgr {
+		compatible = "qcom,cam-res-mgr";
+		status = "ok";
+		shared-gpios = <9>;
+		pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
+		pinctrl-0 = <&cam_res_mgr_active>;
+		pinctrl-1 = <&cam_res_mgr_suspend>;
+	};
+
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_rear_aux: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0 2800000>;
+		rgltr-max-voltage = <1050000 0 3600000 0 2800000>;
+		rgltr-load-current = <105000 0 80000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 28 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA2";
+		sensor-position = <1>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_l9>;
+		cam_vio-supply = <&pm8998_l8>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1704000 1200000>;
+		rgltr-max-voltage = <0 3600000 2928000 1248000>;
+		rgltr-load-current = <0 80000 105000 1200000>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 8 0>,
+			<&tlmm 115 0>,
+			<&tlmm 95 0 >,
+			<&tlmm 97 0>;
+		gpio-reset = <1>;
+		gpio-vio = <2>;
+		gpio-vana = <3>;
+		gpio-vdig = <4>;
+		gpio-req-tbl-num = <0 1 2 3 4>;
+		gpio-req-tbl-flags = <1 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VIO",
+					"CAM_VANA",
+					"CAM_VDIG";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		actuator-src = <&actuator_rear_aux>;
+		led-flash-src = <&led_flash_rear_aux>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "disabled";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_lvs1>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1800000 0>;
+		rgltr-max-voltage = <0 3600000 1800000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 26 0>,
+			<&tlmm 132 0>,
+			<&tlmm 133 0>,
+			<&tlmm 90 0>,
+			<&tlmm 40 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-vio = <4>;
+		gpio-standby = <5>;
+		gpio-req-tbl-num = <0 1 2 3 4 5>;
+		gpio-req-tbl-flags = <1 0 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET2",
+					"CAM_VANA2",
+					"CAM_VDIG2",
+					"CAM_VIO2",
+					"CAM_STANDBY2";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@3 {
+		cell-index = <3>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x03>;
+		csiphy-sd-index = <3>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		led-flash-src = <&led_flash_iris>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk3_active
+				 &cam_sensor_iris_active>;
+		pinctrl-1 = <&cam_sensor_mclk3_suspend
+				 &cam_sensor_iris_suspend>;
+		gpios = <&tlmm 16 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK3",
+					"CAM_RESET3",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 1c7269a..d6be6d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -72,6 +72,13 @@
 	ibb-supply = <&lcdb_ncp_vreg>;
 };
 
+&dsi_dual_test_cmd_display {
+	/delete-property/ vddio-supply;
+	/delete-property/ lab-supply;
+	/delete-property/ ibb-supply;
+	/delete-property/ oled-vdda-supply;
+};
+
 &sde_dp {
 	status = "disabled";
 	/delete-property/ vdda-1p2-supply;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index ee10cfc..929239a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -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
@@ -140,7 +140,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index bd8ae70..6034b6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -12,6 +12,7 @@
 
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-qrd.dtsi"
 #include "smb1355.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index dd4e0b1..8b67649 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -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
@@ -28,6 +28,7 @@
 #include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
 #include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
 #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
+#include "dsi-panel-test-dualmipi-oled-cmd.dtsi"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
 &soc {
@@ -476,6 +477,31 @@
 		ibb-supply = <&ibb_regulator>;
 	};
 
+	dsi_dual_test_cmd_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_dual_test_cmd";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+		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 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
+
+		qcom,dsi-panel = <&dsi_dual_test_cmd>;
+		vddio-supply = <&pm8998_l14>;
+		lab-supply = <&lab_regulator>;
+		ibb-supply = <&ibb_regulator>;
+		oled-vdda-supply = <&pm8998_l22>;
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 532bfac..4f4f1ae 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -55,6 +55,8 @@
 CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -322,6 +324,7 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
 CONFIG_MSM_APM=y
@@ -356,14 +359,19 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -428,6 +436,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -470,6 +479,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index ede64f0..50f3754 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -59,6 +59,8 @@
 CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -332,6 +334,7 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
 CONFIG_MSM_APM=y
@@ -366,8 +369,8 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
@@ -375,6 +378,11 @@
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
 CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -439,6 +447,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -482,6 +491,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 667377f..2c4366b 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -524,6 +524,7 @@
 CONFIG_MSM_GLADIATOR_ERP=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QPNP_PBS=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_MINIDUMP=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 11c95ea..ff3bb70 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -573,6 +573,8 @@
 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
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 6aa09e5..af1dd30 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -524,6 +524,7 @@
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
@@ -590,6 +591,8 @@
 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
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 46d0448..88a4d1e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -25,6 +25,7 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/cpufeature.h>
+#include <asm/cputype.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
@@ -452,4 +453,43 @@
 	mrs	\rd, sp_el0
 	.endm
 
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ *	model:		MIDR_CPU_MODEL of CPU
+ *	rv_min:		Minimum of MIDR_CPU_VAR_REV()
+ *	rv_max:		Maximum of MIDR_CPU_VAR_REV()
+ *	res:		Result register.
+ *	tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns:  0, if the CPU id doesn't match. Non-zero otherwise
+ */
+	.macro	cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+	mrs		\res, midr_el1
+	mov_q		\tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+	mov_q		\tmp2, MIDR_CPU_MODEL_MASK
+	and		\tmp3, \res, \tmp2	// Extract model
+	and		\tmp1, \res, \tmp1	// rev & variant
+	mov_q		\tmp2, \model
+	cmp		\tmp3, \tmp2
+	cset		\res, eq
+	cbz		\res, .Ldone\@		// Model matches ?
+
+	.if (\rv_min != 0)			// Skip min check if rv_min == 0
+	mov_q		\tmp3, \rv_min
+	cmp		\tmp1, \tmp3
+	cset		\res, ge
+	.endif					// \rv_min != 0
+	/* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+	.if ((\rv_min != \rv_max) || \rv_min == 0)
+	mov_q		\tmp2, \rv_max
+	cmp		\tmp1, \tmp2
+	cset		\tmp2, le
+	and		\res, \res, \tmp2
+	.endif
+.Ldone\@:
+	.endm
+
 #endif	/* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ddbf3b1..c088c4f 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -56,6 +56,9 @@
 	(0xf			<< MIDR_ARCHITECTURE_SHIFT) | \
 	((partnum)		<< MIDR_PARTNUM_SHIFT))
 
+#define MIDR_CPU_VAR_REV(var, rev) \
+	(((var)	<< MIDR_VARIANT_SHIFT) | (rev))
+
 #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
 			     MIDR_ARCHITECTURE_MASK)
 
@@ -79,7 +82,9 @@
 #define ARM_CPU_PART_CORTEX_A53		0xD03
 #define ARM_CPU_PART_CORTEX_A73		0xD09
 #define ARM_CPU_PART_CORTEX_A75		0xD0A
+#define ARM_CPU_PART_KRYO3S		0x803
 #define ARM_CPU_PART_KRYO3G		0x802
+#define ARM_CPU_PART_CORTEX_A55		0xD05
 
 #define APM_CPU_PART_POTENZA		0x000
 
@@ -93,7 +98,9 @@
 #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
 #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
 #define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+#define MIDR_KRYO3S	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3S)
 #define MIDR_KRYO3G	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3G)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 653359b..c7b3ba68 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -180,8 +180,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 832075",
 		.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_834220
@@ -189,8 +190,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 834220",
 		.capability = ARM64_WORKAROUND_834220,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_845719
@@ -214,8 +216,9 @@
 	/* Cavium ThunderX, T88 pass 1.x - 2.1 */
 		.desc = "Cavium erratum 27456",
 		.capability = ARM64_WORKAROUND_CAVIUM_27456,
-		MIDR_RANGE(MIDR_THUNDERX, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 1),
+		MIDR_RANGE(MIDR_THUNDERX,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 1)),
 	},
 	{
 	/* Cavium ThunderX, T81 pass 1.0 */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 80ff3df5..5cf4c64 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -722,13 +722,11 @@
 static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
 {
 	u32 midr = read_cpuid_id();
-	u32 rv_min, rv_max;
 
 	/* Cavium ThunderX pass 1.x and 2.x */
-	rv_min = 0;
-	rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
-
-	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
+		MIDR_CPU_VAR_REV(0, 0),
+		MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
 }
 
 static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 28bedd7..2e69a14 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -293,6 +293,12 @@
 	cbz	x9, 2f
 	cmp	x9, #2
 	b.lt	1f
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+	/* Disable hardware DBM on Kryo3S */
+	cpu_midr_match MIDR_KRYO3S, MIDR_CPU_VAR_REV(7, 12), \
+			MIDR_CPU_VAR_REV(7, 13), x1, x2, x3, x4
+	cbnz	x1, 1f
+#endif
 	orr	x10, x10, #TCR_HD		// hardware Dirty flag update
 1:	orr	x10, x10, #TCR_HA		// hardware Access flag update
 2:
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 23cf293..a469eb9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1163,18 +1163,31 @@
 	struct list_head *start, *temp;
 	struct diag_dci_client_tbl *entry = NULL;
 
-	length = *(uint16_t *)(buf + 1); /* total length of event series */
-	if (length == 0) {
-		pr_err("diag: Incoming dci event length is invalid\n");
+	if (!buf) {
+		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
 	/*
-	 * Move directly to the start of the event series. 1 byte for
-	 * event code and 2 bytes for the length field.
+	 * 1 byte for event code and 2 bytes for the length field.
 	 * The length field indicates the total length removing the cmd_code
 	 * and the length field. The event parsing in that case should happen
 	 * till the end.
 	 */
+	if (len < 3) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
+	length = *(uint16_t *)(buf + 1); /* total length of event series */
+	if ((length == 0) || (len != (length + 3))) {
+		pr_err("diag: Incoming dci event length: %d is invalid\n",
+			length);
+		return;
+	}
+	/*
+	 * Move directly to the start of the event series.
+	 * The event parsing should happen from start of event
+	 * series till the end.
+	 */
 	temp_len = 3;
 	while (temp_len < length) {
 		event_id_packet = *(uint16_t *)(buf + temp_len);
@@ -1191,30 +1204,60 @@
 			 * necessary.
 			 */
 			timestamp_len = 8;
-			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
+			if ((temp_len + timestamp_len + 2) <= len)
+				memcpy(timestamp, buf + temp_len + 2,
+					timestamp_len);
+			else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
 		}
 		/* 13th and 14th bit represent the payload length */
 		if (((event_id_packet & 0x6000) >> 13) == 3) {
 			payload_len_field = 1;
-			payload_len = *(uint8_t *)
+			if ((temp_len + timestamp_len + 3) <= len) {
+				payload_len = *(uint8_t *)
 					(buf + temp_len + 2 + timestamp_len);
-			if (payload_len < (MAX_EVENT_SIZE - 13)) {
-				/* copy the payload length and the payload */
+			} else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
+			if ((payload_len < (MAX_EVENT_SIZE - 13)) &&
+			((temp_len + timestamp_len + payload_len + 3) <= len)) {
+				/*
+				 * Copy the payload length and the payload
+				 * after skipping temp_len bytes for already
+				 * parsed packet, timestamp_len for timestamp
+				 * buffer, 2 bytes for event_id_packet.
+				 */
 				memcpy(event_data + 12, buf + temp_len + 2 +
 							timestamp_len, 1);
 				memcpy(event_data + 13, buf + temp_len + 2 +
 					timestamp_len + 1, payload_len);
 			} else {
-				pr_err("diag: event > %d, payload_len = %d\n",
-					(MAX_EVENT_SIZE - 13), payload_len);
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 13), payload_len, temp_len);
 				return;
 			}
 		} else {
 			payload_len_field = 0;
 			payload_len = (event_id_packet & 0x6000) >> 13;
-			/* copy the payload */
-			memcpy(event_data + 12, buf + temp_len + 2 +
+			/*
+			 * Copy the payload after skipping temp_len bytes
+			 * for already parsed packet, timestamp_len for
+			 * timestamp buffer, 2 bytes for event_id_packet.
+			 */
+			if ((payload_len < (MAX_EVENT_SIZE - 12)) &&
+			((temp_len + timestamp_len + payload_len + 2) <= len))
+				memcpy(event_data + 12, buf + temp_len + 2 +
 						timestamp_len, payload_len);
+			else {
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 12), payload_len, temp_len);
+				return;
+			}
 		}
 
 		/* Before copying the data to userspace, check if we are still
@@ -1340,19 +1383,19 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
-
-	/* The first six bytes for the incoming log packet contains
-	 * Command code (2), the length of the packet (2) and the length
-	 * of the log (2)
+	/*
+	 * The first eight bytes for the incoming log packet contains
+	 * Command code (2), the length of the packet (2), the length
+	 * of the log (2) and log code (2)
 	 */
-	log_code = *(uint16_t *)(buf + 6);
-	read_bytes += sizeof(uint16_t) + 6;
-	if (read_bytes > len) {
-		pr_err("diag: Invalid length in %s, len: %d, read: %d",
-						__func__, len, read_bytes);
+	if (len < 8) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
 		return;
 	}
 
+	log_code = *(uint16_t *)(buf + 6);
+	read_bytes += sizeof(uint16_t) + 6;
+
 	/* parse through log mask table of each client and check mask */
 	mutex_lock(&driver->dci_mutex);
 	list_for_each_safe(start, temp, &driver->dci_client_list) {
@@ -1379,6 +1422,10 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
+	if (len < (EXT_HDR_LEN + sizeof(uint8_t))) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
 
 	version = *(uint8_t *)buf + 1;
 	if (version < EXT_HDR_VERSION)  {
@@ -1390,10 +1437,6 @@
 	pkt = buf + EXT_HDR_LEN;
 	pkt_cmd_code = *(uint8_t *)pkt;
 	len -= EXT_HDR_LEN;
-	if (len < 0) {
-		pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
-		return;
-	}
 
 	switch (pkt_cmd_code) {
 	case LOG_CMD_CODE:
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b..70e8414 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -149,6 +149,32 @@
 EXPORT_SYMBOL(drm_bridge_detach);
 
 /**
+ * drm_bridge_connector_init - call bridge's connector_init callback to allow
+ *                     the bridge to update connector's behavior.
+ * @bridge: bridge control structure
+ * @connector: connector control structure
+ *
+ * Calls ->connector_init() &drm_bridge_funcs op for the bridge.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector)
+{
+	int ret = 0;
+
+	if (!bridge || !connector)
+		return -EINVAL;
+
+	if (bridge->funcs->connector_init)
+		ret = bridge->funcs->connector_init(bridge, connector);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_bridge_connector_init);
+
+/**
  * DOC: bridge callbacks
  *
  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index 1fd10d9..fa80317 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -239,8 +239,7 @@
  *
  * return: error code in case of failure or 0 for success.
  */
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state);
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state);
 
 /**
  * dsi_clk_set_link_frequencies() - set frequencies for link clks
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 38eba8d..bff8627 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -1071,8 +1071,7 @@
 
 DEFINE_MUTEX(dsi_mngr_clk_mutex);
 
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
 {
 	int rc = 0;
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 6fb7105..0113c83 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -401,6 +401,21 @@
 	return rc;
 }
 
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl)
+{
+	struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
+
+	if (!state) {
+		pr_err("Invalid host state for DSI controller\n");
+		return -EINVAL;
+	}
+
+	if (!state->host_initialized)
+		return true;
+
+	return false;
+}
+
 static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl,
 				  enum dsi_ctrl_driver_ops op,
 				  u32 op_state)
@@ -1072,10 +1087,10 @@
 
 		cmdbuf = (u8 *)(dsi_ctrl->vaddr);
 
+		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		for (cnt = 0; cnt < length; cnt++)
 			cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt];
 
-		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		dsi_ctrl->cmd_len += length;
 
 		if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
@@ -3294,6 +3309,25 @@
 	return misr;
 }
 
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl)
+{
+	if (!dsi_ctrl || !dsi_ctrl->hw.ops.error_intr_ctrl
+			|| !dsi_ctrl->hw.ops.clear_error_status) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	/*
+	 * Mask DSI error status interrupts and clear error status
+	 * register
+	 */
+	mutex_lock(&dsi_ctrl->ctrl_lock);
+	dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false);
+	dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					DSI_ERROR_INTERRUPT_COUNT);
+	mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
 /**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 537bdc3..9636dbe 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -549,6 +549,16 @@
 				  enum dsi_engine_state state);
 
 /**
+ * dsi_ctrl_validate_host_state() - validate DSI ctrl host state
+ * @dsi_ctrl:            DSI Controller handle.
+ *
+ * Validate DSI cotroller host state
+ *
+ * Return: boolean indicating whether host is not initalized.
+ */
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_set_vid_engine_state() - set video engine state
  * @dsi_ctrl:            DSI Controller handle.
  * @state:               Engine state.
@@ -713,6 +723,13 @@
 void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
 
 /**
+ * dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status
+ *                                           interrupts
+ * @dsi_ctrl:              DSI controller handle.
+ */
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
  * @dsi_ctrl:              DSI controller handle.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index c8edb09..fd18905 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -16,6 +16,7 @@
 
 #include <linux/list.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/err.h>
 
 #include "msm_drv.h"
@@ -51,6 +52,40 @@
 
 static struct dsi_display *main_display;
 
+static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_mask_error_status_interrupts(ctrl->ctrl);
+	}
+}
+
+static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_irq_update(ctrl->ctrl, en);
+	}
+}
+
 void dsi_rect_intersect(const struct dsi_rect *r1,
 		const struct dsi_rect *r2,
 		struct dsi_rect *result)
@@ -88,8 +123,11 @@
 
 	panel = dsi_display->panel;
 
-	if (!dsi_panel_initialized(panel))
-		return -EINVAL;
+	mutex_lock(&panel->panel_lock);
+	if (!dsi_panel_initialized(panel)) {
+		rc = -EINVAL;
+		goto error;
+	}
 
 	panel->bl_config.bl_level = bl_lvl;
 
@@ -124,6 +162,7 @@
 	}
 
 error:
+	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -390,9 +429,17 @@
 	struct dsi_cmd_desc *cmds;
 	u32 flags = 0;
 
-	if (!panel)
+	if (!panel || !ctrl || !ctrl->ctrl)
 		return -EINVAL;
 
+	/*
+	 * When DSI controller is not in initialized state, we do not want to
+	 * report a false ESD failure and hence we defer until next read
+	 * happen.
+	 */
+	if (dsi_ctrl_validate_host_state(ctrl->ctrl))
+		return 1;
+
 	/* acquire panel_lock to make sure no commands are in progress */
 	dsi_panel_acquire_panel_lock(panel);
 
@@ -497,6 +544,11 @@
 		}
 	}
 exit:
+	if (rc <= 0) {
+		dsi_display_ctrl_irq_update(display, false);
+		dsi_display_mask_ctrl_error_interrupts(display);
+	}
+
 	dsi_display_cmd_engine_disable(display);
 done:
 	return rc;
@@ -865,6 +917,62 @@
 	return rc;
 }
 
+static ssize_t debugfs_esd_trigger_check(struct file *file,
+				  const char __user *user_buf,
+				  size_t user_len,
+				  loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	char *buf;
+	int rc = 0;
+	u32 esd_trigger;
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (user_len > sizeof(u32))
+		return -EINVAL;
+
+	buf = kzalloc(user_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, user_len)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	buf[user_len] = '\0'; /* terminate the string */
+
+	if (kstrtouint(buf, 10, &esd_trigger)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (esd_trigger != 1) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	display->esd_trigger = esd_trigger;
+
+	if (display->esd_trigger) {
+		rc = dsi_panel_trigger_esd_attack(display->panel);
+		if (rc) {
+			pr_err("Failed to trigger ESD attack\n");
+			return rc;
+		}
+	}
+
+	rc = user_len;
+error:
+	kfree(buf);
+	return rc;
+}
+
 static ssize_t debugfs_misr_read(struct file *file,
 				 char __user *user_buf,
 				 size_t user_len,
@@ -941,6 +1049,11 @@
 	.write = debugfs_misr_setup,
 };
 
+static const struct file_operations esd_trigger_fops = {
+	.open = simple_open,
+	.write = debugfs_esd_trigger_check,
+};
+
 static int dsi_display_debugfs_init(struct dsi_display *display)
 {
 	int rc = 0;
@@ -968,6 +1081,18 @@
 		goto error_remove_dir;
 	}
 
+	dump_file = debugfs_create_file("esd_trigger",
+					0644,
+					dir,
+					display,
+					&esd_trigger_fops);
+	if (IS_ERR_OR_NULL(dump_file)) {
+		rc = PTR_ERR(dump_file);
+		pr_err("[%s] debugfs for esd trigger file failed, rc=%d\n",
+		       display->name, rc);
+		goto error_remove_dir;
+	}
+
 	misr_data = debugfs_create_file("misr_data",
 					0600,
 					dir,
@@ -2162,15 +2287,111 @@
 	return rc;
 }
 
+/* initialize dsi_panel using ext bridge's setting */
+static int dsi_display_populate_ext_bridge_config(struct dsi_display *display,
+	struct mipi_dsi_device *dsi)
+{
+	struct dsi_panel *panel = display->panel;
+
+	if (!panel) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("DSI[%s]: channel=%d, lanes=%d, format=%d, mode_flags=%lx\n",
+		dsi->name, dsi->channel, dsi->lanes,
+		dsi->format, dsi->mode_flags);
+
+	panel->host_config.data_lanes = 0;
+	if (dsi->lanes > 0)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_0;
+	if (dsi->lanes > 1)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_1;
+	if (dsi->lanes > 2)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_2;
+	if (dsi->lanes > 3)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_3;
+
+	switch (dsi->format) {
+	case MIPI_DSI_FMT_RGB888:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB888;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666_LOOSE;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+	default:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB565;
+		break;
+	}
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		panel->panel_mode = DSI_OP_VIDEO_MODE;
+
+		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_BURST_MODE;
+		else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_PULSES;
+		else
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS;
+
+		panel->video_config.hsa_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA;
+		panel->video_config.hbp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP;
+		panel->video_config.hfp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP;
+		panel->video_config.pulse_mode_hsa_he =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE;
+		panel->video_config.bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BLLP;
+		panel->video_config.eof_bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+	} else {
+		panel->panel_mode = DSI_OP_CMD_MODE;
+		pr_err("command mode not supported by ext bridge\n");
+		return -ENOTSUPP;
+	}
+
+	/* TODO: add calc for these 2 values */
+	panel->host_config.t_clk_post = 0x03;
+	panel->host_config.t_clk_pre = 0x24;
+
+	panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN;
+
+	return 0;
+}
+
 static int dsi_host_attach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
-	return 0;
+	struct dsi_display *display = to_dsi_display(host);
+	int ret = 0;
+
+	if (!host || !dsi) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("host attach\n");
+
+	if (dsi_display_has_ext_bridge(display))
+		ret = dsi_display_populate_ext_bridge_config(display, dsi);
+
+	return ret;
 }
 
+
 static int dsi_host_detach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
+	pr_debug("host detach\n");
 	return 0;
 }
 
@@ -2468,23 +2689,6 @@
 	}
 }
 
-static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
-{
-	int i;
-	struct dsi_display_ctrl *ctrl;
-
-	if (!display)
-		return;
-
-	for (i = 0; (i < display->ctrl_count) &&
-			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
-		ctrl = &display->ctrl[i];
-		if (!ctrl)
-			continue;
-		dsi_ctrl_irq_update(ctrl->ctrl, en);
-	}
-}
-
 int dsi_pre_clkoff_cb(void *priv,
 			   enum dsi_clk_type clk,
 			   enum dsi_clk_state new_state)
@@ -2847,11 +3051,31 @@
 	of_node = of_parse_phandle(display->pdev->dev.of_node,
 				   "qcom,dsi-panel", 0);
 	if (!of_node) {
-		pr_err("No Panel device present\n");
-		rc = -ENODEV;
-		goto error;
+		struct device_node *endpoint;
+
+		endpoint = of_graph_get_next_endpoint(
+				display->pdev->dev.of_node, NULL);
+		if (!endpoint) {
+			pr_err("no endpoint for ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+
+		of_node = of_graph_get_remote_port_parent(endpoint);
+		of_node_put(endpoint);
+		if (!of_node) {
+			pr_err("no valid ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+		of_node_put(of_node);
+
+		display->panel_of = of_node;
+		/* TODO: split support */
+		display->type = DSI_DISPLAY_EXT_BRIDGE;
 	} else {
 		display->panel_of = of_node;
+		display->type = DSI_DISPLAY_SINGLE;
 	}
 
 error:
@@ -2863,6 +3087,8 @@
 	int rc = 0;
 	int i;
 	struct dsi_display_ctrl *ctrl;
+	enum dsi_panel_type panel_type =
+		dsi_display_has_ext_bridge(display) ? EXT_BRIDGE : DSI_PANEL;
 
 	for (i = 0; i < display->ctrl_count; i++) {
 		ctrl = &display->ctrl[i];
@@ -2885,7 +3111,8 @@
 	}
 
 	display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
-						display->cmdline_topology);
+					display->cmdline_topology, panel_type);
+
 	if (IS_ERR_OR_NULL(display->panel)) {
 		rc = PTR_ERR(display->panel);
 		pr_err("failed to get panel, rc=%d\n", rc);
@@ -3300,9 +3527,9 @@
 	struct dsi_display_mode_priv_info *priv_info;
 
 	priv_info = mode->priv_info;
-	if (!priv_info) {
+	if (!dsi_display_has_ext_bridge(display) && !priv_info) {
 		pr_err("[%s] failed to get private info of the display mode",
-			display->name);
+				display->name);
 		return -EINVAL;
 	}
 
@@ -3339,7 +3566,8 @@
 		}
 	}
 
-	if (priv_info->phy_timing_len) {
+	/* ext bridge calculates these timing params by phy driver */
+	if (priv_info && priv_info->phy_timing_len) {
 		for (i = 0; i < display->ctrl_count; i++) {
 			ctrl = &display->ctrl[i];
 			 rc = dsi_phy_set_timing_params(ctrl->phy,
@@ -3424,6 +3652,12 @@
 {
 	int rc = 0;
 
+	/* Continuous splash not supported by external bridge */
+	if (dsi_display_has_ext_bridge(display)) {
+		display->is_cont_splash_enabled = false;
+		return 0;
+	}
+
 	/* Vote for gdsc required to read register address space */
 
 	display->cont_splash_client = sde_power_client_create(display->phandle,
@@ -3436,7 +3670,9 @@
 		return -EINVAL;
 	}
 
-	/* Verify whether continuous splash is enabled or not */
+	/*
+	 * Verify whether continuous splash is enabled or not.
+	 */
 	display->is_cont_splash_enabled =
 		dsi_display_get_cont_splash_status(display);
 	if (!display->is_cont_splash_enabled) {
@@ -4029,7 +4265,7 @@
 	}
 
 	if (display->bridge) {
-		pr_err("display is already initialize\n");
+		pr_err("display is already initialized\n");
 		goto error;
 	}
 
@@ -4048,6 +4284,56 @@
 	return rc;
 }
 
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector)
+{
+	int rc = 0;
+	struct drm_bridge *ext_bridge;
+	struct msm_drm_private *priv = NULL;
+
+	if (!display || !display->drm_dev || !enc) {
+		pr_err("invalid param(s)\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+	priv = display->drm_dev->dev_private;
+
+	if (!priv) {
+		pr_err("Private data is not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!display->bridge) {
+		pr_err("dsi bridge is not initialize\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	ext_bridge = of_drm_find_bridge(display->panel_of);
+	if (!ext_bridge) {
+		pr_err("ext brige not found\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* update connector ops in ext bridge */
+	drm_bridge_connector_init(ext_bridge, connector);
+
+	/* insert ext bridge to the bridge chain */
+	display->bridge->base.next = ext_bridge;
+	ext_bridge->encoder = enc;
+	priv->bridges[priv->num_bridges++] = ext_bridge;
+
+	drm_bridge_attach(display->drm_dev, ext_bridge);
+
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+
+}
+
 int dsi_display_drm_bridge_deinit(struct dsi_display *display)
 {
 	int rc = 0;
@@ -4127,6 +4413,44 @@
 	return rc;
 }
 
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp)
+{
+	struct dsi_display *display;
+	int i;
+
+	if (!info || !disp) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	display = disp;
+	if (!display->panel) {
+		pr_err("invalid display panel\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	memset(info, 0, sizeof(struct msm_display_info));
+
+	info->intf_type = DRM_MODE_CONNECTOR_DSI;
+	info->num_of_h_tiles = display->ctrl_count;
+	for (i = 0; i < info->num_of_h_tiles; i++)
+		info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
+
+	/*
+	 * TODO: these info need come from ext bridge.
+	 * using drm_connector->status, connector->polled.
+	 */
+	info->is_connected = true;
+	info->is_primary = true;
+	info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
+		MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
+
+	mutex_unlock(&display->display_lock);
+	return 0;
+}
+
 static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
 			u32 *count)
 {
@@ -4851,12 +5175,15 @@
 	mode = display->panel->cur_mode;
 
 	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+		if (display->is_cont_splash_enabled) {
+			pr_err("DMS is not supposed to be set on first frame\n");
+			return -EINVAL;
+		}
 		/* update dsi ctrl for new mode */
 		rc = dsi_display_pre_switch(display);
 		if (rc)
 			pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
-				   display->name, rc);
-
+					display->name, rc);
 		goto error;
 	}
 
@@ -4990,6 +5317,9 @@
 	struct dsi_rect req_roi = { 0 };
 	int rc = 0;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5043,6 +5373,9 @@
 	if (!display || !rois || !display->panel)
 		return -EINVAL;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5197,7 +5530,7 @@
 		}
 	}
 
-	if (mode->priv_info->dsc_enabled) {
+	if (mode->priv_info && mode->priv_info->dsc_enabled) {
 		mode->priv_info->dsc.pic_width *= display->ctrl_count;
 		rc = dsi_panel_update_pps(display->panel);
 		if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 4cfd4a9..53004e4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation.All rights reserved.
+ * 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
@@ -160,6 +160,7 @@
  * @root:             Debugfs root directory
  * @misr_enable       Frame MISR enable/disable
  * @misr_frame_count  Number of frames to accumulate the MISR value
+ * @esd_trigger       field indicating ESD trigger through debugfs
  */
 struct dsi_display {
 	struct platform_device *pdev;
@@ -218,6 +219,7 @@
 
 	bool misr_enable;
 	u32 misr_frame_count;
+	u32 esd_trigger;
 	/* multiple dsi error handlers */
 	struct workqueue_struct *err_workq;
 	struct work_struct fifo_underflow_work;
@@ -225,6 +227,18 @@
 	struct work_struct lp_rx_timeout_work;
 };
 
+/**
+ * dsi_display_has_ext_bridge() - check whether display has ext bridge
+ *                                connected.
+ *
+ * Return: True - ext bridge, False - no ext bridge.
+ */
+static inline bool dsi_display_has_ext_bridge(const struct dsi_display *display)
+{
+	return display->type == DSI_DISPLAY_EXT_BRIDGE ||
+		display->type == DSI_DISPLAY_SPLIT_EXT_BRIDGE;
+}
+
 int dsi_display_dev_probe(struct platform_device *pdev);
 int dsi_display_dev_remove(struct platform_device *pdev);
 
@@ -288,6 +302,19 @@
 int dsi_display_drm_bridge_deinit(struct dsi_display *display);
 
 /**
+ * dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge
+ * @display:            Handle to the display.
+ * @enc:                Pointer to the encoder object which is connected to the
+ *			display.
+ * @connector:          Pointer to the connector object which is connected to
+ *                      the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector);
+
+/**
  * dsi_display_get_info() - returns the display properties
  * @info:             Pointer to the structure where info is stored.
  * @disp:             Handle to the display.
@@ -297,6 +324,15 @@
 int dsi_display_get_info(struct msm_display_info *info, void *disp);
 
 /**
+ * dsi_display_ext_bridge_get_info() - returns the ext bridge's display info
+ * @info:             Pointer to the structure where info is stored.
+ * @disp:             Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp);
+
+/**
  * dsi_display_get_mode_count() - get number of modes supported by the display
  * @display:            Handle to display.
  * @count:              Number of modes supported
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index a1e4685..5b47865 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -63,6 +63,11 @@
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
 	if (msm_is_mode_seamless_vrr(drm_mode))
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+
+	dsi_mode->timing.h_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
+	dsi_mode->timing.v_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
 }
 
 void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -101,6 +106,11 @@
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
 		drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
 
+	if (dsi_mode->timing.h_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	if (dsi_mode->timing.v_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
 	drm_mode_set_name(drm_mode);
 }
 
@@ -288,17 +298,23 @@
 
 	convert_to_dsi_mode(mode, &dsi_mode);
 
-	/*
-	 * retrieve dsi mode from dsi driver's cache since not safe to take
-	 * the drm mode config mutex in all paths
-	 */
-	rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
-	if (rc)
-		return rc;
+	/* external bridge doesn't use priv_info and dsi_mode_flags */
+	if (!dsi_display_has_ext_bridge(display)) {
+		/*
+		 * retrieve dsi mode from dsi driver's cache since not safe to
+		 * take the drm mode config mutex in all paths
+		 */
+		rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+		if (rc)
+			return rc;
 
-	/* propagate the private info to the adjusted_mode derived dsi mode */
-	dsi_mode.priv_info = panel_dsi_mode->priv_info;
-	dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+		/*
+		 * propagate the private info to the adjusted_mode derived dsi
+		 * mode
+		 */
+		dsi_mode.priv_info = panel_dsi_mode->priv_info;
+		dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+	}
 
 	rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
 			DSI_VALIDATE_FLAG_ALLOW_ADJUST);
@@ -377,6 +393,35 @@
 	return 0;
 }
 
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info,
+	u32 max_mixer_width, void *display)
+{
+	struct msm_display_topology *topology;
+	struct dsi_display_mode dsi_mode;
+	struct dsi_mode_info *timing;
+
+	if (!drm_mode || !mode_info)
+		return -EINVAL;
+
+	convert_to_dsi_mode(drm_mode, &dsi_mode);
+
+	memset(mode_info, 0, sizeof(*mode_info));
+
+	timing = &dsi_mode.timing;
+	mode_info->frame_rate = dsi_mode.timing.refresh_rate;
+	mode_info->vtotal = DSI_V_TOTAL(timing);
+
+	topology = &mode_info->topology;
+	topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? 2 : 1;
+	topology->num_enc = 0;
+	topology->num_intf = topology->num_lm;
+
+	mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
+	return 0;
+}
+
 static const struct drm_bridge_funcs dsi_bridge_ops = {
 	.attach       = dsi_bridge_attach,
 	.mode_fixup   = dsi_bridge_mode_fixup,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index ec58479..2bad8c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -86,6 +86,18 @@
 	void *display);
 
 /**
+ * dsi_conn_ext_bridge_get_mode_info - retrieve information on the mode selected
+ * @drm_mode: Display mode set for the display
+ * @mode_info: Out parameter. information of the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info, u32 max_mixer_width,
+	void *display);
+
+/**
  * dsi_conn_mode_valid - callback to determine if specified mode is valid
  * @connector: Pointer to drm connector structure
  * @mode: Pointer to drm mode structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index eaeeb52..d8b90e3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -32,6 +32,7 @@
 #define MAX_TOPOLOGY 5
 
 #define DSI_PANEL_DEFAULT_LABEL  "Default dsi panel"
+#define EXT_BRIDGE_DEFAULT_LABEL  "Default ext bridge"
 
 #define DEFAULT_MDP_TRANSFER_TIME 14000
 
@@ -321,6 +322,30 @@
 	return rc;
 }
 
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel)
+{
+	struct dsi_panel_reset_config *r_config;
+
+	if (!panel) {
+		pr_err("Invalid panel param\n");
+		return -EINVAL;
+	}
+
+	r_config = &panel->reset_config;
+	if (!r_config) {
+		pr_err("Invalid panel reset configuration\n");
+		return -EINVAL;
+	}
+
+	if (gpio_is_valid(r_config->reset_gpio)) {
+		gpio_set_value(r_config->reset_gpio, 0);
+		pr_info("GPIO pulled low to simulate ESD\n");
+		return 0;
+	}
+	pr_err("failed to pull down gpio\n");
+	return -EINVAL;
+}
+
 static int dsi_panel_reset(struct dsi_panel *panel)
 {
 	int rc = 0;
@@ -480,6 +505,9 @@
 	if (!panel || !panel->cur_mode)
 		return -EINVAL;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mode = panel->cur_mode;
 
 	cmds = mode->priv_info->cmd_sets[type].cmds;
@@ -610,13 +638,10 @@
 
 	dsi = &panel->mipi_device;
 
-	mutex_lock(&panel->panel_lock);
-
 	rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl);
 	if (rc < 0)
 		pr_err("failed to update dcs backlight:%d\n", bl_lvl);
 
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -625,13 +650,16 @@
 	int rc = 0;
 	struct dsi_backlight_config *bl = &panel->bl_config;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl);
 	switch (bl->type) {
 	case DSI_BACKLIGHT_WLED:
 		led_trigger_event(bl->wled, bl_lvl);
 		break;
 	case DSI_BACKLIGHT_DCS:
-		dsi_panel_update_backlight(panel, bl_lvl);
+		rc = dsi_panel_update_backlight(panel, bl_lvl);
 		break;
 	default:
 		pr_err("Backlight type(%d) not supported\n", bl->type);
@@ -2713,7 +2741,8 @@
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override)
+				int topology_override,
+				enum dsi_panel_type type)
 {
 	struct dsi_panel *panel;
 	int rc = 0;
@@ -2722,68 +2751,85 @@
 	if (!panel)
 		return ERR_PTR(-ENOMEM);
 
-	panel->name = of_get_property(of_node, "qcom,mdss-dsi-panel-name",
-				      NULL);
-	if (!panel->name)
-		panel->name = DSI_PANEL_DEFAULT_LABEL;
+	if (type == DSI_PANEL) {
+		panel->name = of_get_property(of_node,
+			"qcom,mdss-dsi-panel-name", NULL);
+		if (!panel->name)
+			panel->name = DSI_PANEL_DEFAULT_LABEL;
 
-	rc = dsi_panel_parse_host_config(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse host configuration, rc=%d\n", rc);
+		rc = dsi_panel_parse_host_config(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse host configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_panel_mode(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse panel mode configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps,
+			of_node, panel->name);
+		if (rc)
+			pr_err("failed to parse dfps configuration, rc=%d\n",
+				rc);
+
+		rc = dsi_panel_parse_phy_props(&panel->phy_props,
+			of_node, panel->name);
+		if (rc) {
+			pr_err("failed to parse panel physical dimension, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
+		if (rc)
+			pr_err("failed to parse power config, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_gpios(panel, of_node);
+		if (rc)
+			pr_err("failed to parse panel gpios, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_bl_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse backlight config, rc=%d\n", rc);
+
+
+		rc = dsi_panel_parse_misc_features(panel, of_node);
+		if (rc)
+			pr_err("failed to parse misc features, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_hdr_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse hdr config, rc=%d\n", rc);
+
+		rc = dsi_panel_get_mode_count(panel, of_node);
+		if (rc) {
+			pr_err("failed to get mode count, rc=%d\n", rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dms_info(panel, of_node);
+		if (rc)
+			pr_debug("failed to get dms info, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_esd_config(panel, of_node);
+		if (rc)
+			pr_debug("failed to parse esd config, rc=%d\n", rc);
+
+		panel->type = DSI_PANEL;
+	} else if (type == EXT_BRIDGE) {
+		panel->name = EXT_BRIDGE_DEFAULT_LABEL;
+		panel->type = EXT_BRIDGE;
+	} else {
+		pr_err("invalid panel type\n");
+		rc = -ENOTSUPP;
 		goto error;
 	}
 
-	rc = dsi_panel_parse_panel_mode(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse panel mode configuration, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps, of_node, panel->name);
-	if (rc)
-		pr_err("failed to parse dfps configuration, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_phy_props(&panel->phy_props, of_node, panel->name);
-	if (rc) {
-		pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
-	if (rc)
-		pr_err("failed to parse power config, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_gpios(panel, of_node);
-	if (rc)
-		pr_err("failed to parse panel gpios, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_bl_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse backlight config, rc=%d\n", rc);
-
-
-	rc = dsi_panel_parse_misc_features(panel, of_node);
-	if (rc)
-		pr_err("failed to parse misc features, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_hdr_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse hdr config, rc=%d\n", rc);
-
-	rc = dsi_panel_get_mode_count(panel, of_node);
-	if (rc) {
-		pr_err("failed to get mode count, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dms_info(panel, of_node);
-	if (rc)
-		pr_debug("failed to get dms info, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_esd_config(panel, of_node);
-	if (rc)
-		pr_debug("failed to parse esd config, rc=%d\n", rc);
-
 	panel->panel_of_node = of_node;
 	drm_panel_init(&panel->drm_panel);
 	mutex_init(&panel->panel_lock);
@@ -2797,7 +2843,8 @@
 void dsi_panel_put(struct dsi_panel *panel)
 {
 	/* free resources allocated for ESD check */
-	dsi_panel_esd_config_deinit(&panel->esd_config);
+	if (panel->type == DSI_PANEL)
+		dsi_panel_esd_config_deinit(&panel->esd_config);
 
 	kfree(panel);
 }
@@ -2813,6 +2860,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	dev = &panel->mipi_device;
@@ -2877,6 +2927,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_bl_unregister(panel);
@@ -3005,6 +3058,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL);
@@ -3112,10 +3168,12 @@
 
 	memcpy(&config->video_timing, &mode->timing,
 	       sizeof(config->video_timing));
-	config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
-	config->video_timing.dsc = &mode->priv_info->dsc;
 
-	config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	if (mode->priv_info) {
+		config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
+		config->video_timing.dsc = &mode->priv_info->dsc;
+		config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	}
 	config->esc_clk_rate_hz = 19200000;
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -3130,6 +3188,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	/* If LP11_INIT is set, panel will be powered up during prepare() */
@@ -3158,6 +3219,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	priv_info = panel->cur_mode->priv_info;
@@ -3193,6 +3257,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
 	if (rc)
@@ -3211,6 +3278,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
 	if (rc)
@@ -3229,6 +3299,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
 	if (rc)
@@ -3247,6 +3320,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (panel->lp11_init) {
@@ -3357,6 +3433,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	priv_info = panel->cur_mode->priv_info;
 	set = &priv_info->cmd_sets[DSI_CMD_SET_ROI];
 
@@ -3392,6 +3471,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
@@ -3412,6 +3494,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH);
@@ -3432,6 +3517,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON);
@@ -3453,6 +3541,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_ON);
@@ -3475,6 +3566,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF);
@@ -3498,6 +3592,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF);
@@ -3522,6 +3619,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_OFF);
@@ -3553,6 +3653,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (!panel->lp11_init) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 06199f4..3b226b0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -140,8 +140,15 @@
 	u32 groups;
 };
 
+enum dsi_panel_type {
+	DSI_PANEL = 0,
+	EXT_BRIDGE,
+	DSI_PANEL_TYPE_MAX,
+};
+
 struct dsi_panel {
 	const char *name;
+	enum dsi_panel_type type;
 	struct device_node *panel_of_node;
 	struct mipi_dsi_device mipi_device;
 
@@ -204,7 +211,10 @@
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override);
+				int topology_override,
+				enum dsi_panel_type type);
+
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel);
 
 void dsi_panel_put(struct dsi_panel *panel);
 
@@ -269,4 +279,10 @@
 
 void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
 
+struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent,
+				struct device_node *of_node,
+				int topology_override);
+
+void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
+
 #endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 655390b..21b67d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -68,6 +68,7 @@
 	struct sde_connector *c_conn;
 	int bl_lvl;
 	struct drm_event event;
+	int rc = 0;
 
 	brightness = bd->props.brightness;
 
@@ -93,10 +94,10 @@
 		event.length = sizeof(u32);
 		msm_mode_object_event_notify(&c_conn->base.base,
 				c_conn->base.dev, &event, (u8 *)&brightness);
-		c_conn->ops.set_backlight(c_conn->display, bl_lvl);
+		rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl);
 	}
 
-	return 0;
+	return rc;
 }
 
 static int sde_backlight_device_get_brightness(struct backlight_device *bd)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 1ee75c4..8d2f115 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -4581,10 +4581,13 @@
 {
 	struct drm_encoder *encoder;
 	struct sde_crtc_state *cstate;
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_smmu_state_data *smmu_state;
 	uint32_t secure;
 	uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
 	int encoder_cnt = 0, i;
 	int rc;
+	bool is_video_mode = false;
 
 	if (!crtc || !state) {
 		SDE_ERROR("invalid arguments\n");
@@ -4642,6 +4645,37 @@
 
 		}
 	}
+
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		is_video_mode |= sde_encoder_check_mode(encoder,
+						MSM_DISPLAY_CAP_VID_MODE);
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+	smmu_state = &sde_crtc->smmu_state;
+	/*
+	 * In video mode check for null commit before transition
+	 * from secure to non secure and vice versa
+	 */
+	if (is_video_mode && smmu_state &&
+		state->plane_mask && crtc->state->plane_mask &&
+		((fb_sec_dir && ((smmu_state->state == ATTACHED) &&
+				(secure == SDE_DRM_SEC_ONLY))) ||
+			(fb_ns && ((smmu_state->state == DETACHED) ||
+				(smmu_state->state == DETACH_ALL_REQ))))) {
+
+		SDE_EVT32(DRMID(&sde_crtc->base), fb_ns, fb_sec_dir,
+		  smmu_state->state, crtc->state->plane_mask,
+			crtc->state->plane_mask);
+		SDE_DEBUG("crtc %d, Invalid secure transition %x\n",
+				crtc->base.id, smmu_state->state);
+		return -EINVAL;
+
+	}
+
 	SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);
 
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 6ccf957..02d593b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -474,6 +474,7 @@
 	struct sde_hw_blk_reg_map hw;
 
 	memset(&hw, 0, sizeof(hw));
+	msm_gem_sync(cfg->dma_buf->buf);
 	cmd1 = (cfg->op == REG_DMA_READ) ?
 		(dspp_read_sel[cfg->block_select] << 30) : 0;
 	cmd1 |= (cfg->last_command) ? BIT(24) : 0;
@@ -481,7 +482,6 @@
 	cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0;
 	cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ);
 
-	msm_gem_sync(cfg->dma_buf->buf);
 	SET_UP_REG_DMA_REG(hw, reg_dma);
 	SDE_REG_WRITE(&hw, REG_DMA_OP_MODE_OFF, BIT(0));
 	SDE_REG_WRITE(&hw, reg_dma_clear_status_off,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 5d3835c..5895a4d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -952,6 +952,17 @@
 		.config_hdr = dp_connector_config_hdr,
 		.cmd_transfer = NULL,
 	};
+	static const struct sde_connector_ops ext_bridge_ops = {
+		.set_info_blob = dsi_conn_set_info_blob,
+		.mode_valid = dsi_conn_mode_valid,
+		.get_info = dsi_display_ext_bridge_get_info,
+		.soft_reset = dsi_display_soft_reset,
+		.clk_ctrl = dsi_display_clk_ctrl,
+		.get_mode_info = dsi_conn_ext_bridge_get_mode_info,
+		.get_dst_format = dsi_display_get_dst_format,
+		.enable_event = dsi_conn_enable_event,
+		.cmd_transfer = NULL,
+	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;
 	void *display, *connector;
@@ -976,39 +987,95 @@
 		display = sde_kms->dsi_displays[i];
 		encoder = NULL;
 
-		memset(&info, 0x0, sizeof(info));
-		rc = dsi_display_get_info(&info, display);
-		if (rc) {
-			SDE_ERROR("dsi get_info %d failed\n", i);
-			continue;
-		}
+		if (!dsi_display_has_ext_bridge(display)) {
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("dsi get_info %d failed\n", i);
+				continue;
+			}
 
-		encoder = sde_encoder_init(dev, &info);
-		if (IS_ERR_OR_NULL(encoder)) {
-			SDE_ERROR("encoder init failed for dsi %d\n", i);
-			continue;
-		}
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for dsi %d\n",
+					i);
+				continue;
+			}
 
-		rc = dsi_display_drm_bridge_init(display, encoder);
-		if (rc) {
-			SDE_ERROR("dsi bridge %d init failed, %d\n", i, rc);
-			sde_encoder_destroy(encoder);
-			continue;
-		}
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed, %d\n",
+					i, rc);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 
-		connector = sde_connector_init(dev,
-					encoder,
-					0,
-					display,
-					&dsi_ops,
-					DRM_CONNECTOR_POLL_HPD,
-					DRM_MODE_CONNECTOR_DSI);
-		if (connector) {
-			priv->encoders[priv->num_encoders++] = encoder;
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&dsi_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("dsi %d connector init failed\n", i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+			}
 		} else {
-			SDE_ERROR("dsi %d connector init failed\n", i);
-			dsi_display_drm_bridge_deinit(display);
-			sde_encoder_destroy(encoder);
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_ext_bridge_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("ext get_info %d failed\n", i);
+				continue;
+			}
+
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for ext %d\n",
+					i);
+				continue;
+			}
+
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed for ext\n",
+					i);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&ext_bridge_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("connector init %d failed for ext\n",
+					i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			rc = dsi_display_drm_ext_bridge_init(display,
+				encoder, connector);
+			if (rc) {
+				struct drm_connector *conn = connector;
+
+				SDE_ERROR("ext bridge %d init failed, %d\n",
+					i, rc);
+				conn->funcs->destroy(connector);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f7f3e9e..ab9f203 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,7 +19,6 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <soc/qcom/scm.h>
-#include <linux/nvmem-consumer.h>
 
 #include <linux/msm-bus-board.h>
 #include <linux/msm-bus.h>
@@ -745,64 +744,33 @@
 	{ ADRENO_QUIRK_SECVID_SET_ONCE, "qcom,gpu-quirk-secvid-set-once" },
 	{ ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW,
 			"qcom,gpu-quirk-limit-uche-gbif-rw" },
+	{ ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" },
 };
 
-#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
 static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
+adreno_get_soc_hw_revision_node(struct adreno_device *adreno_dev,
+	struct platform_device *pdev)
 {
 	struct device_node *node, *child;
-	struct nvmem_cell *cell;
-	ssize_t len;
-	u32 *buf, hw_rev, rev;
+	unsigned int rev;
 
 	node = of_find_node_by_name(pdev->dev.of_node, "qcom,soc-hw-revisions");
 	if (node == NULL)
-		goto err;
-
-	/* read the soc hw revision and select revision node */
-	cell = nvmem_cell_get(&pdev->dev, "minor_rev");
-	if (IS_ERR_OR_NULL(cell)) {
-		if (PTR_ERR(cell) == -EPROBE_DEFER)
-			return (void *)cell;
-
-		KGSL_CORE_ERR("Unable to get nvmem cell: ret=%ld\n",
-				PTR_ERR(cell));
-		goto err;
-	}
-
-	buf = nvmem_cell_read(cell, &len);
-	nvmem_cell_put(cell);
-
-	if (IS_ERR_OR_NULL(buf)) {
-		KGSL_CORE_ERR("Unable to read nvmem cell: ret=%ld\n",
-				PTR_ERR(buf));
-		goto err;
-	}
-
-	hw_rev = *buf;
-	kfree(buf);
+		return NULL;
 
 	for_each_child_of_node(node, child) {
-		if (of_property_read_u32(child, "reg", &rev))
+		if (of_property_read_u32(child, "qcom,soc-hw-revision", &rev))
 			continue;
 
-		if (rev == hw_rev)
+		if (rev == adreno_dev->soc_hw_rev)
 			return child;
 	}
 
-err:
-	/* fall back to parent node */
-	return pdev->dev.of_node;
+	KGSL_DRV_WARN(KGSL_DEVICE(adreno_dev),
+		"No matching SOC HW revision found for efused HW rev=%u\n",
+		adreno_dev->soc_hw_rev);
+	return NULL;
 }
-#else
-static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
-{
-	return pdev->dev.of_node;
-}
-#endif
-
 
 static int adreno_update_soc_hw_revision_quirks(
 		struct adreno_device *adreno_dev, struct platform_device *pdev)
@@ -810,9 +778,9 @@
 	struct device_node *node;
 	int i;
 
-	node = adreno_get_soc_hw_revision_node(pdev);
-	if (IS_ERR(node))
-		return PTR_ERR(node);
+	node = adreno_get_soc_hw_revision_node(adreno_dev, pdev);
+	if (node == NULL)
+		node = pdev->dev.of_node;
 
 	/* get chip id, fall back to parent if revision node does not have it */
 	if (of_property_read_u32(node, "qcom,chipid", &adreno_dev->chipid))
@@ -1131,6 +1099,36 @@
 		KGSL_DRV_WARN(device, "cx_dbgc ioremap failed\n");
 }
 
+static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev)
+{
+	unsigned int val;
+	unsigned int soc_hw_rev[3];
+	int ret;
+
+	if (of_property_read_u32_array(
+		KGSL_DEVICE(adreno_dev)->pdev->dev.of_node,
+		"qcom,soc-hw-rev-efuse", soc_hw_rev, 3))
+		return;
+
+	ret = adreno_efuse_map(adreno_dev);
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to map hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	ret = adreno_efuse_read_u32(adreno_dev, soc_hw_rev[0], &val);
+	adreno_efuse_unmap(adreno_dev);
+
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to read hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	adreno_dev->soc_hw_rev = (val >> soc_hw_rev[1]) & soc_hw_rev[2];
+}
+
 static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev)
 {
 	unsigned int row0;
@@ -1179,11 +1177,10 @@
 		return -ENODEV;
 	}
 
-	status = adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
-	if (status) {
-		device->pdev = NULL;
-		return status;
-	}
+	/* Identify SOC hardware revision to be used */
+	adreno_efuse_read_soc_hw_rev(adreno_dev);
+
+	adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
 
 	/* Get the chip ID from the DT and set up target specific parameters */
 	adreno_identify_gpu(adreno_dev);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 82b06fe..8785d62 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -150,6 +150,8 @@
  * between GBIF, SMMU and MEMNOC.
  */
 #define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8)
+/* Select alternate secure context bank for mmu */
+#define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9)
 
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0
@@ -465,6 +467,7 @@
  * @gpuhtw_llc_slice: GPU pagetables system cache slice descriptor
  * @gpuhtw_llc_slice_enable: To enable the GPUHTW system cache slice or not
  * @zap_loaded: Used to track if zap was successfully loaded or not
+ * @soc_hw_rev: Indicate which SOC hardware revision to use
  */
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
@@ -537,6 +540,7 @@
 	void *gpuhtw_llc_slice;
 	bool gpuhtw_llc_slice_enable;
 	unsigned int zap_loaded;
+	unsigned int soc_hw_rev;
 };
 
 /**
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 472f78e..9a878fb 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -2253,6 +2253,14 @@
 
 	atomic_add(halt, &adreno_dev->halt);
 
+	/*
+	 * At this point it is safe to assume that we recovered. Setting
+	 * this field allows us to take a new snapshot for the next failure
+	 * if we are prioritizing the first unrecoverable snapshot.
+	 */
+	if (device->snapshot)
+		device->snapshot->recovered = true;
+
 	return 1;
 }
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5168d9e..a8075fe 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -261,7 +261,8 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-	int i, status;
+	int i;
+	int status = -ENOMEM;
 
 	if (!adreno_is_a3xx(adreno_dev)) {
 		status = kgsl_allocate_global(device, &device->scratch,
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7c3bff7..b6a2edb 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -303,6 +303,7 @@
 
 	u32 snapshot_faultcount;	/* Total number of faults since boot */
 	bool force_panic;		/* Force panic after snapshot dump */
+	bool prioritize_unrecoverable;	/* Overwrite with new GMU snapshots */
 
 	/* Use CP Crash dumper to get GPU snapshot*/
 	bool snapshot_crashdumper;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 60c56a06..c4296c8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -2527,6 +2527,7 @@
 } kgsl_iommu_cbs[] = {
 	{ KGSL_IOMMU_CONTEXT_USER, "gfx3d_user", },
 	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure" },
+	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure_alt" },
 };
 
 static int _kgsl_iommu_cb_probe(struct kgsl_device *device,
@@ -2534,12 +2535,20 @@
 {
 	struct platform_device *pdev = of_find_device_by_node(node);
 	struct kgsl_iommu_context *ctx = NULL;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(kgsl_iommu_cbs); i++) {
 		if (!strcmp(node->name, kgsl_iommu_cbs[i].name)) {
 			int id = kgsl_iommu_cbs[i].id;
 
+			if (ADRENO_QUIRK(adreno_dev,
+				ADRENO_QUIRK_MMU_SECURE_CB_ALT)) {
+				if (!strcmp(node->name, "gfx3d_secure"))
+					continue;
+			} else if (!strcmp(node->name, "gfx3d_secure_alt"))
+				continue;
+
 			ctx = &iommu->ctx[id];
 			ctx->id = id;
 			ctx->cb_num = -1;
@@ -2550,8 +2559,8 @@
 	}
 
 	if (ctx == NULL) {
-		KGSL_CORE_ERR("dt: Unknown context label %s\n", node->name);
-		return -EINVAL;
+		KGSL_CORE_ERR("dt: Unused context label %s\n", node->name);
+		return 0;
 	}
 
 	if (ctx->id == KGSL_IOMMU_CONTEXT_SECURE)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7509ceb..2cd132e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2222,7 +2222,7 @@
 
 int kgsl_pwrctrl_init(struct kgsl_device *device)
 {
-	int i, k, m, n = 0, result;
+	int i, k, m, n = 0, result, freq;
 	struct platform_device *pdev = device->pdev;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct device_node *ocmem_bus_node;
@@ -2269,7 +2269,7 @@
 	pwr->wakeup_maxpwrlevel = 0;
 
 	for (i = 0; i < pwr->num_pwrlevels; i++) {
-		unsigned int freq = pwr->pwrlevels[i].gpu_freq;
+		freq = pwr->pwrlevels[i].gpu_freq;
 
 		if (freq > 0)
 			freq = clk_round_rate(pwr->grp_clks[0], freq);
@@ -2282,11 +2282,10 @@
 
 	kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
 
-	if (pwr->grp_clks[6] != NULL)
+	freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
+	if (freq > 0)
 		kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[6],
-			clk_round_rate(pwr->grp_clks[6],
-			KGSL_RBBMTIMER_CLK_FREQ),
-			clocks[6]);
+			freq, clocks[6]);
 
 	_isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1);
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 33ce60d..5e41611 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -663,7 +663,8 @@
 	 * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
 	 */
 	if (device->snapshot != NULL) {
-		if (!gmu_fault || !device->snapshot->recovered)
+		if (!device->prioritize_unrecoverable ||
+				!device->snapshot->recovered)
 			return;
 
 		/*
@@ -954,6 +955,28 @@
 	return (ssize_t) ret < 0 ? ret : count;
 }
 
+/* Show the prioritize_unrecoverable status */
+static ssize_t prioritize_unrecoverable_show(
+		struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			device->prioritize_unrecoverable);
+}
+
+/* Store the priority value to prioritize unrecoverable */
+static ssize_t prioritize_unrecoverable_store(
+		struct kgsl_device *device, const char *buf, size_t count)
+{
+	unsigned int val = 0;
+	int ret = 0;
+
+	ret = kgsl_sysfs_store(buf, &val);
+	if (!ret && device)
+		device->prioritize_unrecoverable = (bool) val;
+
+	return (ssize_t) ret < 0 ? ret : count;
+}
+
 /* Show the snapshot_crashdumper request status */
 static ssize_t snapshot_crashdumper_show(struct kgsl_device *device, char *buf)
 {
@@ -1026,6 +1049,8 @@
 static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
 static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
 static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
+static SNAPSHOT_ATTR(prioritize_unrecoverable, 0644,
+		prioritize_unrecoverable_show, prioritize_unrecoverable_store);
 static SNAPSHOT_ATTR(snapshot_crashdumper, 0644, snapshot_crashdumper_show,
 	snapshot_crashdumper_store);
 static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show,
@@ -1110,6 +1135,7 @@
 	device->snapshot = NULL;
 	device->snapshot_faultcount = 0;
 	device->force_panic = 0;
+	device->prioritize_unrecoverable = true;
 	device->snapshot_crashdumper = 1;
 	device->snapshot_legacy = 0;
 
@@ -1135,6 +1161,11 @@
 	if (ret)
 		goto done;
 
+	ret = sysfs_create_file(&device->snapshot_kobj,
+			&attr_prioritize_unrecoverable.attr);
+	if (ret)
+		goto done;
+
 	ret  = sysfs_create_file(&device->snapshot_kobj,
 			&attr_snapshot_crashdumper.attr);
 	if (ret)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 85df514..868be8b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -4396,8 +4396,12 @@
 	smmu->arch_ops = data->arch_ops;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res)
-		smmu->phys_addr = res->start;
+	if (res == NULL) {
+		dev_err(dev, "no MEM resource info\n");
+		return -EINVAL;
+	}
+
+	smmu->phys_addr = res->start;
 	smmu->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(smmu->base))
 		return PTR_ERR(smmu->base);
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index f3f9a1a..abb695d 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -171,6 +171,7 @@
 };
 
 enum flash_led_type {
+	FLASH_LED_TYPE_UNKNOWN,
 	FLASH_LED_TYPE_FLASH,
 	FLASH_LED_TYPE_TORCH,
 };
@@ -204,13 +205,13 @@
 	int				prev_current_ma;
 	u8				duration;
 	u8				id;
-	u8				type;
 	u8				ires_idx;
 	u8				default_ires_idx;
 	u8				hdrm_val;
 	u8				current_reg_val;
 	u8				strobe_ctrl;
 	u8				strobe_sel;
+	enum flash_led_type		type;
 	bool				led_on;
 };
 
@@ -225,6 +226,7 @@
 	int				led_mask;
 	bool				regulator_on;
 	bool				enabled;
+	bool				symmetry_en;
 };
 
 /*
@@ -1091,6 +1093,71 @@
 	return 0;
 }
 
+static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+	int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
+	enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id)) {
+			if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_FLASH;
+
+			if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_TORCH;
+		}
+	}
+
+	if (type == FLASH_LED_TYPE_UNKNOWN) {
+		pr_err("Incorrect type possibly because of no active LEDs\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+			(led->fnode[i].type == type)) {
+			total_curr_ma += led->fnode[i].current_ma;
+			num_leds++;
+		}
+	}
+
+	if (num_leds > 0 && total_curr_ma > 0) {
+		prgm_current_ma = total_curr_ma / num_leds;
+	} else {
+		pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
+			num_leds, total_curr_ma);
+		return -EINVAL;
+	}
+
+	if (prgm_current_ma == 0) {
+		pr_warn("prgm_curr_ma cannot be 0\n");
+		return 0;
+	}
+
+	pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
+		total_curr_ma, prgm_current_ma);
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id) &&
+			led->fnode[i].current_ma != prgm_current_ma &&
+			led->fnode[i].type == type) {
+			qpnp_flash_led_node_set(&led->fnode[i],
+				prgm_current_ma);
+			pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
+				(type == FLASH_LED_TYPE_FLASH) ?
+					"flash" : "torch",
+				led->fnode[i].id, prgm_current_ma,
+				led->fnode[i].current_reg_val,
+				led->fnode[i].ires_ua);
+		}
+	}
+
+	return 0;
+}
+
 static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
 {
 	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
@@ -1109,6 +1176,15 @@
 	}
 
 	/* Iterate over all active leds for this switch node */
+	if (snode->symmetry_en) {
+		rc = qpnp_flash_led_symmetry_config(snode);
+		if (rc < 0) {
+			pr_err("Failed to configure current symmetrically, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
 	val = 0;
 	for (i = 0; i < led->num_fnodes; i++)
 		if (led->fnode[i].led_on &&
@@ -1707,6 +1783,8 @@
 		return rc;
 	}
 
+	snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
 	if (snode->led_mask < 1 || snode->led_mask > 7) {
 		pr_err("Invalid value for led-mask\n");
 		return -EINVAL;
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
index fad36ea..764657a 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -482,7 +482,8 @@
 {
 	int rc = 0;
 	u32 delay_us = HAPTICS_BACK_EMF_DELAY_US;
-	u8 val, auto_res_mode_qwd;
+	u8 val;
+	bool auto_res_mode_qwd;
 
 	if (chip->act_type != HAP_LRA)
 		return 0;
@@ -496,7 +497,7 @@
 
 	/*
 	 * Do not enable auto resonance if auto mode is enabled and auto
-	 * resonance mode is QWD, meaning short pattern.
+	 * resonance mode is QWD, meaning long pattern.
 	 */
 	if (chip->lra_auto_mode && auto_res_mode_qwd && enable) {
 		pr_debug("auto_mode enabled, not enabling auto_res\n");
@@ -1232,7 +1233,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 0;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
 		}
@@ -1242,16 +1243,13 @@
 		if (rc < 0)
 			return rc;
 
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for buffer mode */
 		if (chip->play_irq >= 0 && !chip->play_irq_en) {
 			enable_irq(chip->play_irq);
 			chip->play_irq_en = true;
 		}
 
+		brake_pat[0] = BRAKE_VMAX;
 		chip->play_mode = HAP_BUFFER;
 		chip->wave_shape = HAP_WAVE_SQUARE;
 	} else {
@@ -1264,7 +1262,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 1;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
 			ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
@@ -1275,11 +1273,6 @@
 		if (rc < 0)
 			return rc;
 
-		brake_pat[0] = 0x3;
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for direct mode */
 		if (chip->play_irq >= 0 && chip->play_irq_en) {
 			disable_irq(chip->play_irq);
@@ -1303,6 +1296,10 @@
 		return rc;
 	}
 
+	rc = qpnp_haptics_brake_config(chip, brake_pat);
+	if (rc < 0)
+		return rc;
+
 	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
 			HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
 	if (rc < 0)
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
index df50ca5..82e3b40 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
@@ -22,11 +22,16 @@
 #include "venus_boot.h"
 #include "soc/qcom/secure_buffer.h"
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
 
 enum clock_properties {
 	CLOCK_PROP_HAS_SCALING = 1 << 0,
 };
 
+struct regulator *gdsc_venus;
+struct regulator *gdsc_venus_core0;
+
 static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 {
 	return NULL;
@@ -59,6 +64,118 @@
 	return 0;
 }
 
+static int venus_regulator_setup(struct msm_vidc_platform_resources *res)
+{
+	const char *reg_name = "venus";
+	const char *reg_name_core0 = "venus-core0";
+	int rc = 0;
+
+	gdsc_venus = devm_regulator_get(&res->pdev->dev, reg_name);
+	if (IS_ERR(gdsc_venus))
+		dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+
+	rc = regulator_enable(gdsc_venus);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus GDSC enable failed\n");
+
+	gdsc_venus_core0 = devm_regulator_get(&res->pdev->dev, reg_name_core0);
+	if (IS_ERR(gdsc_venus_core0))
+		dprintk(VIDC_ERR, "Failed to get Venus-Core0 GDSC\n");
+
+	rc = regulator_enable(gdsc_venus_core0);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus-Core0 GDSC enable failed\n");
+
+	dprintk(VIDC_DBG, "Vensu, Venus-Core0 GDSC's are enabled\n");
+	return rc;
+}
+
+
+static int venus_clock_setup(struct msm_vidc_platform_resources *res,
+		unsigned long rate)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+	cl = &res->clock_set.clock_tbl[i];
+		if (!cl->has_scaling)
+			continue;
+
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_set_rate(clk, clk_round_rate(clk, rate));
+
+		if (rc)
+			dprintk(VIDC_ERR,
+				"%s: Failed to set clock rate %s: %d\n",
+				__func__, cl->name, rc);
+
+		dprintk(VIDC_DBG, "%s clock set clock rate to %lu\n",
+				cl->name, rate);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static int venus_clock_prepare_enable(struct msm_vidc_platform_resources *res)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_prepare_enable(clk);
+
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to enable %s clock\n",
+					cl->name);
+			for (i--; i >= 0; i--) {
+				cl = &res->clock_set.clock_tbl[i];
+				clk = clk_get(&res->pdev->dev, cl->name);
+				clk_disable_unprepare(clk);
+				dprintk(VIDC_ERR, "clock %s unprepared\n",
+						cl->name);
+			}
+			return rc;
+		}
+		dprintk(VIDC_DBG, " Clock : %s enabled\n", cl->name);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static void venus_clk_disable_unprepare(struct msm_vidc_platform_resources *res)
+{
+	int i;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		dprintk(VIDC_DBG, "clock %s unprepared\n", cl->name);
+		clk_disable_unprepare(clk);
+	}
+
+	if (gdsc_venus) {
+		regulator_disable(gdsc_venus);
+		dprintk(VIDC_DBG, "Venus Regulator disabled\n");
+		gdsc_venus = NULL;
+	}
+	if (gdsc_venus_core0) {
+		regulator_disable(gdsc_venus_core0);
+		dprintk(VIDC_DBG, "Venus-Core0 Regulator disabled\n");
+		gdsc_venus_core0 = NULL;
+	}
+}
+
 static inline enum imem_type read_imem_type(struct platform_device *pdev)
 {
 	bool is_compatible(char *compat)
@@ -843,6 +960,8 @@
 	bus->dev = dev;
 	dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n",
 			bus->name, bus->master, bus->slave, bus->governor);
+
+	venus_clk_disable_unprepare(res);
 err_bus:
 	return rc;
 }
@@ -1232,6 +1351,12 @@
 	of_property_read_u32(pdev->dev.of_node,
 			"qcom,max-secure-instances",
 			&res->max_secure_inst_count);
+
+	venus_regulator_setup(res);
+	venus_clock_setup(res, 0);
+	venus_clock_prepare_enable(res);
+	venus_clock_setup(res, 1);
+
 	return rc;
 
 err_setup_legacy_cb:
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index eab93cc..a86d9f1 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -2216,13 +2216,24 @@
 	}
 
 	*data->hdcp_ctx = handle;
-	/* Cache the client ctx to be used later
-	 * HDCP driver probe happens earlier than
+
+	/* Cache the client ctx to be used later if
+	 * Misc HDCP driver probe happens later than
 	 * SDE driver probe hence caching it to
 	 * be used later.
 	 */
-
 	drv_client_handle = handle;
+
+	/* if misc HDCP driver probe happens earlier
+	 * than SDE driver probe store the client
+	 * handle to be used to sysfs notifications.
+	 */
+
+	if (hdcp_drv_mgr && !hdcp_drv_mgr->handle) {
+		if (drv_client_handle)
+			hdcp_drv_mgr->handle = drv_client_handle;
+	}
+
 	handle->thread = kthread_run(kthread_worker_fn,
 				     &handle->worker, "hdcp_tz_lib");
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b5ad125..232b4ae 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1848,7 +1848,7 @@
 	return ret;
 }
 
-static int __qseecom_process_blocked_on_listener_legacy(
+static int __qseecom_process_reentrancy_blocked_on_listener(
 				struct qseecom_command_scm_resp *resp,
 				struct qseecom_registered_app_list *ptr_app,
 				struct qseecom_dev_handle *data)
@@ -1857,10 +1857,11 @@
 	int ret = 0;
 	struct qseecom_continue_blocked_request_ireq ireq;
 	struct qseecom_command_scm_resp continue_resp;
-	bool found_app = false;
-	unsigned long flags;
+	unsigned int session_id;
 	sigset_t new_sigset;
 	sigset_t old_sigset;
+	unsigned long flags;
+	bool found_app = false;
 
 	if (!resp || !data) {
 		pr_err("invalid resp or data pointer\n");
@@ -1891,140 +1892,81 @@
 		}
 	}
 
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-	ptr_app->blocked_on_listener_id = resp->data;
-
-	/* sleep until listener is available */
-	sigfillset(&new_sigset);
-	sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
 	do {
-		qseecom.app_block_ref_cnt++;
-		ptr_app->app_blocked = true;
-		mutex_unlock(&app_access_lock);
-		wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use);
-		mutex_lock(&app_access_lock);
-		ptr_app->app_blocked = false;
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
-
-	sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-	ptr_app->blocked_on_listener_id = 0;
-	/* notify the blocked app that listener is available */
-	pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n",
-		resp->data, data->client.app_id,
-		data->client.app_name);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = data->client.app_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n",
-			data->client.app_id,
-			data->client.app_name, ret);
-		goto exit;
-	}
-	/*
-	 * After TZ app is unblocked, then continue to next case
-	 * for incomplete request processing
-	 */
-	resp->result = QSEOS_RESULT_INCOMPLETE;
-exit:
-	return ret;
-}
-
-static int __qseecom_process_blocked_on_listener_smcinvoke(
-			struct qseecom_command_scm_resp *resp, uint32_t app_id)
-{
-	struct qseecom_registered_listener_list *list_ptr;
-	int ret = 0;
-	struct qseecom_continue_blocked_request_ireq ireq;
-	struct qseecom_command_scm_resp continue_resp;
-	unsigned int session_id;
-	sigset_t new_sigset;
-	sigset_t old_sigset;
-
-	if (!resp) {
-		pr_err("invalid resp pointer\n");
-		ret = -EINVAL;
-		goto exit;
-	}
-	session_id = resp->resp_type;
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-
-	/* sleep until listener is available */
-	sigfillset(&new_sigset);
-	sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
-	do {
-		qseecom.app_block_ref_cnt++;
-		mutex_unlock(&app_access_lock);
-		wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use);
-		mutex_lock(&app_access_lock);
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
-
-	sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-	/* notify TZ that listener is available */
-	pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
-			resp->data, session_id);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = session_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		/* retry with legacy cmd */
-		qseecom.smcinvoke_support = false;
-		ireq.app_or_session_id = app_id;
-		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-		qseecom.smcinvoke_support = true;
-		if (ret) {
-			pr_err("cont block req for app %d or session %d fail\n",
-				app_id, session_id);
+		session_id = resp->resp_type;
+		list_ptr = __qseecom_find_svc(resp->data);
+		if (!list_ptr) {
+			pr_err("Invalid listener ID %d\n", resp->data);
+			ret = -ENODATA;
 			goto exit;
 		}
+		ptr_app->blocked_on_listener_id = resp->data;
+
+		pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
+			resp->data, list_ptr->listener_in_use,
+			session_id, data->client.app_id);
+
+		/* sleep until listener is available */
+		sigfillset(&new_sigset);
+		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+		do {
+			qseecom.app_block_ref_cnt++;
+			ptr_app->app_blocked = true;
+			mutex_unlock(&app_access_lock);
+			wait_event_freezable(
+				list_ptr->listener_block_app_wq,
+				!list_ptr->listener_in_use);
+			mutex_lock(&app_access_lock);
+			ptr_app->app_blocked = false;
+			qseecom.app_block_ref_cnt--;
+		}  while (list_ptr->listener_in_use);
+
+		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+
+		ptr_app->blocked_on_listener_id = 0;
+		pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
+			resp->data, session_id, data->client.app_id);
+
+		/* notify TZ that listener is available */
+		ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
+
+		if (qseecom.smcinvoke_support)
+			ireq.app_or_session_id = session_id;
+		else
+			ireq.app_or_session_id = data->client.app_id;
+
+		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+					&ireq, sizeof(ireq),
+					&continue_resp, sizeof(continue_resp));
+		if (ret && qseecom.smcinvoke_support) {
+			/* retry with legacy cmd */
+			qseecom.smcinvoke_support = false;
+			ireq.app_or_session_id = data->client.app_id;
+			ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+				&ireq, sizeof(ireq),
+				&continue_resp, sizeof(continue_resp));
+			qseecom.smcinvoke_support = true;
+			if (ret) {
+				pr_err("unblock app %d or session %d fail\n",
+					data->client.app_id, session_id);
+				goto exit;
+			}
+		}
+		resp->result = continue_resp.result;
+		resp->resp_type = continue_resp.resp_type;
+		resp->data = continue_resp.data;
+		pr_debug("unblock resp = %d\n", resp->result);
+	} while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
+
+	if (resp->result != QSEOS_RESULT_INCOMPLETE) {
+		pr_err("Unexpected unblock resp %d\n", resp->result);
+		ret = -EINVAL;
 	}
-	resp->result = QSEOS_RESULT_INCOMPLETE;
 exit:
 	return ret;
 }
 
-static int __qseecom_process_reentrancy_blocked_on_listener(
-				struct qseecom_command_scm_resp *resp,
-				struct qseecom_registered_app_list *ptr_app,
-				struct qseecom_dev_handle *data)
-{
-	if (!qseecom.smcinvoke_support)
-		return __qseecom_process_blocked_on_listener_legacy(
-			resp, ptr_app, data);
-	else
-		return __qseecom_process_blocked_on_listener_smcinvoke(
-			resp, data->client.app_id);
-}
 static int __qseecom_reentrancy_process_incomplete_cmd(
 					struct qseecom_dev_handle *data,
 					struct qseecom_command_scm_resp *resp)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5ed9b72..0abc7a3 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1916,7 +1916,11 @@
 			err = PTR_ERR(buf);
 		}
 	} else {
-		val = *buf;
+		/*
+		 * 30 bits from bit offset 0 would be read.
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
 		kfree(buf);
 	}
 
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 75faeb1..bb2270b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -108,20 +108,8 @@
 	 for it's internal usage and release it to back to pre allocated pool.
 	 This memory is allocated at the cold boot time.
 
-config CLD_LL_CORE
-       tristate "QTI core WLAN driver for QCA6174 chipset"
-       select NL80211_TESTMODE
-       select WEXT_CORE
-       select WEXT_PRIV
-       select WEXT_SPY
-       select WIRELESS_EXT
-       ---help---
-         This section contains the necessary modules needed to enable the
-	 core WLAN driver for QTI QCA6174 chipset.
-	 Select Y to compile the driver in order to have WLAN functionality
-	 support.
-
 source "drivers/net/wireless/cnss2/Kconfig"
+source "drivers/net/wireless/cnss/Kconfig"
 source "drivers/net/wireless/cnss_utils/Kconfig"
 source "drivers/net/wireless/cnss_genl/Kconfig"
 
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4ffbd10..5c33140 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -27,8 +27,7 @@
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
 
 obj-$(CONFIG_CNSS2)	+= cnss2/
-
+obj-$(CONFIG_CNSS)              += cnss/
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
-
 obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig
new file mode 100644
index 0000000..0b37af6
--- /dev/null
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -0,0 +1,116 @@
+config CNSS
+	tristate "CNSS driver for wifi module"
+	select CNSS_UTILS
+	select CRYPTO
+	select CRYPTO_HASH
+	select CRYPTO_BLKCIPHER
+	---help---
+	 This module adds support for the CNSS connectivity subsystem used
+	 for wifi devices based on the QCA AR6320 chipset.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework.
+
+config CNSS_SDIO
+	bool "Enable/disable cnss sdio platform driver for wifi module"
+	depends on CNSS
+	depends on MMC
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with SDIO bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a SDIO client device.
+
+config CNSS_PCI
+	bool "Enable/disable cnss pci platform driver for wifi module"
+	depends on CNSS
+	depends on PCI
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with PCIe bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a PCIe client device.
+
+config CNSS_ASYNC
+	bool "Enable/disable cnss pci platform driver asynchronous probe"
+	depends on CNSS_PCI
+	---help---
+	 If enabled, CNSS PCI platform driver would do asynchronous probe.
+	 Using asynchronous probe will allow CNSS PCI platform driver to
+	 probe in parallel with other device drivers and will help to
+	 reduce kernel boot time.
+
+config CNSS_MAC_BUG
+	bool "Enable/disable 0-4K memory initialization for QCA6174"
+	depends on CNSS
+	---help---
+	  If enabled, 0-4K memory is reserved for QCA6174 to address
+	  a MAC HW bug. MAC would do an invalid pointer fetch based on
+	  the data, that was read from 0 to 4K. So fill it with zero's;
+	  to an address for which PCIe root complex would honor the read
+	  without any errors.
+
+config CLD_DEBUG
+	bool "Enable/disable CLD debug features"
+	help
+	 WLAN CLD driver uses this config to enable certain debug features.
+	 Some of the debug features may affect performance or may compromise
+	 on security.
+
+	  Say N, if you are building a release kernel for production use.
+	  Only say Y, if you are building a kernel with debug support.
+
+config CLD_HL_SDIO_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface"
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	select WEXT_CORE
+	select WEXT_SPY
+	select NL80211_TESTMODE
+	depends on ARCH_QCOM
+	depends on MMC
+
+config CLD_LL_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver"
+	select NL80211_TESTMODE
+	select WEXT_CORE
+	select WEXT_PRIV
+	select WEXT_SPY
+	select WIRELESS_EXT
+	---help---
+	  This section contains the necessary modules needed to enable the
+	  core WLAN driver for Qualcomm Technologies Inc QCA6174 chipset.
+	  Select Y to compile the driver in order to have WLAN functionality
+	  support.
+
+config CNSS_SECURE_FW
+	bool "Enable/Disable Memory Allocation for Secure Firmware Feature"
+	depends on CNSS
+	---help---
+	  CLD Driver can use this for holding local copy of firmware
+	  binaries which is used for sha crypto computation.
+	  The Memory Allocation is done only if this Config Parameter is
+	  enabled
+
+config BUS_AUTO_SUSPEND
+	bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+	depends on CNSS
+	depends on PCI
+	---help---
+	  Runtime Power Management is supported for PCIe based WLAN Drivers.
+	  The features enable cld wlan driver to suspend pcie bus when APPS
+	  is awake based on the driver inactivity with the Firmware.
+	  The Feature uses runtime power management framework from kernel to
+	  track bus access clients and to synchronize the driver activity
+	  during system pm.
+	  This config flag controls the feature per target based. The feature
+	  requires CNSS driver support.
+
+source "drivers/net/wireless/cnss/logger/Kconfig"
+
+config WLAN_FEATURE_RX_WAKELOCK
+	bool "Enable RX wake lock feature"
+	help
+	Enable WLAN_FEATURE_HOLD_RX_WAKELOCK which is required to take rx
+	wakelock when driver receives packets from fw.
diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile
new file mode 100644
index 0000000..38ad562
--- /dev/null
+++ b/drivers/net/wireless/cnss/Makefile
@@ -0,0 +1,6 @@
+# Makefile for CNSS platform driver
+
+obj-$(CONFIG_CNSS_PCI)	+= cnss_pci.o
+obj-$(CONFIG_CNSS_SDIO)	+= cnss_sdio.o
+obj-$(CONFIG_CNSS)	+= cnss_common.o
+obj-$(CONFIG_CNSS_LOGGER)	+= logger/
diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c
new file mode 100644
index 0000000..a1731b0
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.c
@@ -0,0 +1,450 @@
+/* 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.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <net/cfg80211.h>
+
+#define AR6320_REV1_VERSION             0x5000000
+#define AR6320_REV1_1_VERSION           0x5000001
+#define AR6320_REV1_3_VERSION           0x5000003
+#define AR6320_REV2_1_VERSION           0x5010000
+#define AR6320_REV3_VERSION             0x5020000
+#define AR6320_REV3_2_VERSION           0x5030000
+#define AR900B_DEV_VERSION              0x1000000
+#define QCA9377_REV1_1_VERSION          0x5020001
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_1 = {
+	"qwlan11.bin", "bdwlan11.bin", "otp11.bin", "utf11.bin",
+	"utfbd11.bin", "epping11.bin", "evicted11.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_2_0 = {
+	"qwlan20.bin", "bdwlan20.bin", "otp20.bin", "utf20.bin",
+	"utfbd20.bin", "epping20.bin", "evicted20.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_3 = {
+	"qwlan13.bin", "bdwlan13.bin", "otp13.bin", "utf13.bin",
+	"utfbd13.bin", "epping13.bin", "evicted13.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+	"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+	"utfbd30.bin", "epping30.bin", "evicted30.bin"};
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+	"qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+	"utfbd.bin", "epping.bin", "evicted.bin"};
+
+enum cnss_dev_bus_type {
+	CNSS_BUS_NONE = -1,
+	CNSS_BUS_PCI,
+	CNSS_BUS_SDIO
+};
+
+static DEFINE_MUTEX(unsafe_channel_list_lock);
+static DEFINE_MUTEX(dfs_nol_info_lock);
+
+static struct cnss_unsafe_channel_list {
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+} unsafe_channel_list;
+
+static struct cnss_dfs_nol_info {
+	void *dfs_nol_info;
+	u16 dfs_nol_info_len;
+} dfs_nol_info;
+
+static enum cnss_cc_src cnss_cc_source = CNSS_SOURCE_CORE;
+
+int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	unsafe_channel_list.unsafe_ch_count = ch_count;
+
+	if (ch_count != 0) {
+		memcpy(
+			(char *)unsafe_channel_list.unsafe_ch_list,
+			(char *)unsafe_ch_list, ch_count * sizeof(u16));
+	}
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel);
+
+int cnss_get_wlan_unsafe_channel(
+			u16 *unsafe_ch_list,
+			u16 *ch_count, u16 buf_len)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if (!unsafe_ch_list || !ch_count) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -ENOMEM;
+	}
+
+	*ch_count = unsafe_channel_list.unsafe_ch_count;
+	memcpy(
+		(char *)unsafe_ch_list,
+		(char *)unsafe_channel_list.unsafe_ch_list,
+		unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);
+
+int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
+{
+	void *temp;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	temp = kmalloc(info_len, GFP_KERNEL);
+	if (!temp) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOMEM;
+	}
+
+	memcpy(temp, info, info_len);
+	dfs_info = &dfs_nol_info;
+	kfree(dfs_info->dfs_nol_info);
+
+	dfs_info->dfs_nol_info = temp;
+	dfs_info->dfs_nol_info_len = info_len;
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_set_dfs_nol);
+
+int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+	int len;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	dfs_info = &dfs_nol_info;
+
+	if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOENT;
+	}
+
+	len = min(info_len, dfs_info->dfs_nol_info_len);
+
+	memcpy(info, dfs_info->dfs_nol_info, len);
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return len;
+}
+EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);
+
+void cnss_init_work(struct work_struct *work, work_func_t func)
+{
+	INIT_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_work);
+
+void cnss_flush_work(void *work)
+{
+	struct work_struct *cnss_work = work;
+
+	cancel_work_sync(cnss_work);
+}
+EXPORT_SYMBOL(cnss_flush_work);
+
+void cnss_flush_delayed_work(void *dwork)
+{
+	struct delayed_work *cnss_dwork = dwork;
+
+	cancel_delayed_work_sync(cnss_dwork);
+}
+EXPORT_SYMBOL(cnss_flush_delayed_work);
+
+void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name)
+{
+	wakeup_source_init(ws, name);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_init);
+
+void cnss_pm_wake_lock(struct wakeup_source *ws)
+{
+	__pm_stay_awake(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock);
+
+void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec)
+{
+	__pm_wakeup_event(ws, msec);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_timeout);
+
+void cnss_pm_wake_lock_release(struct wakeup_source *ws)
+{
+	__pm_relax(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_release);
+
+void cnss_pm_wake_lock_destroy(struct wakeup_source *ws)
+{
+	wakeup_source_trash(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_destroy);
+
+void cnss_get_monotonic_boottime(struct timespec *ts)
+{
+	get_monotonic_boottime(ts);
+}
+EXPORT_SYMBOL(cnss_get_monotonic_boottime);
+
+void cnss_get_boottime(struct timespec *ts)
+{
+	ktime_get_ts(ts);
+}
+EXPORT_SYMBOL(cnss_get_boottime);
+
+void cnss_init_delayed_work(struct delayed_work *work, work_func_t func)
+{
+	INIT_DELAYED_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_delayed_work);
+
+int cnss_vendor_cmd_reply(struct sk_buff *skb)
+{
+	return cfg80211_vendor_cmd_reply(skb);
+}
+EXPORT_SYMBOL(cnss_vendor_cmd_reply);
+
+int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu)
+{
+	return set_cpus_allowed_ptr(task, cpumask_of(cpu));
+}
+EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr);
+
+/* wlan prop driver cannot invoke show_stack
+ * function directly, so to invoke this function it
+ * call wcnss_dump_stack function
+ */
+void cnss_dump_stack(struct task_struct *task)
+{
+	show_stack(task, NULL);
+}
+EXPORT_SYMBOL(cnss_dump_stack);
+
+struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev)
+{
+	if (!dev)
+		return NULL;
+	else
+		return dev->platform_data;
+}
+
+int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->request_bus_bandwidth)
+		return pf_ops->request_bus_bandwidth(bandwidth);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_request_bus_bandwidth);
+
+void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_virt_ramdump_mem)
+		return pf_ops->get_virt_ramdump_mem(size);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem);
+
+void cnss_common_device_self_recovery(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_self_recovery)
+		pf_ops->device_self_recovery();
+}
+EXPORT_SYMBOL(cnss_common_device_self_recovery);
+
+void cnss_common_schedule_recovery_work(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->schedule_recovery_work)
+		pf_ops->schedule_recovery_work();
+}
+EXPORT_SYMBOL(cnss_common_schedule_recovery_work);
+
+void cnss_common_device_crashed(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_crashed)
+		pf_ops->device_crashed();
+}
+EXPORT_SYMBOL(cnss_common_device_crashed);
+
+u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_wlan_mac_address)
+		return pf_ops->get_wlan_mac_address(num);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_wlan_mac_address);
+
+int cnss_common_set_wlan_mac_address(
+		struct device *dev, const u8 *in, u32 len)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->set_wlan_mac_address)
+		return pf_ops->set_wlan_mac_address(in, len);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_set_wlan_mac_address);
+
+int cnss_power_up(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_up)
+		return pf_ops->power_up(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_down)
+		return pf_ops->power_down(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+			       u32 size, u32 tufello_dual_fw)
+{
+	if (tufello_dual_fw)
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+	else
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+}
+EXPORT_SYMBOL(cnss_get_qca9377_fw_files);
+
+int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+				 u32 target_type, u32 target_version)
+{
+	if (!pfw_files)
+		return -ENODEV;
+
+	switch (target_version) {
+	case AR6320_REV1_VERSION:
+	case AR6320_REV1_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_1, sizeof(*pfw_files));
+		break;
+	case AR6320_REV1_3_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_3, sizeof(*pfw_files));
+		break;
+	case AR6320_REV2_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_2_0, sizeof(*pfw_files));
+		break;
+	case AR6320_REV3_VERSION:
+	case AR6320_REV3_2_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+		break;
+	default:
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+		pr_err("%s default version 0x%X 0x%X", __func__,
+		       target_type, target_version);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+void cnss_set_cc_source(enum cnss_cc_src cc_source)
+{
+	cnss_cc_source = cc_source;
+}
+EXPORT_SYMBOL(cnss_set_cc_source);
+
+enum cnss_cc_src cnss_get_cc_source(void)
+{
+	return cnss_cc_source;
+}
+EXPORT_SYMBOL(cnss_get_cc_source);
+
+const char *cnss_wlan_get_evicted_data_file(void)
+{
+	return FW_FILES_QCA6174_FW_3_0.evicted_data;
+}
+
+int cnss_common_register_tsf_captured_handler(struct device *dev,
+					      irq_handler_t handler, void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->register_tsf_captured_handler)
+		return pf_ops->register_tsf_captured_handler(handler, ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler);
+
+int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->unregister_tsf_captured_handler)
+		return pf_ops->unregister_tsf_captured_handler(ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_unregister_tsf_captured_handler);
diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h
new file mode 100644
index 0000000..7013aba
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.h
@@ -0,0 +1,65 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS_COMMON_H_
+#define _NET_CNSS_COMMON_H_
+
+/* max 20mhz channel count */
+#define CNSS_MAX_CH_NUM		45
+
+struct cnss_cap_tsf_info {
+	int irq_num;
+	void *context;
+	irq_handler_t irq_handler;
+};
+
+struct cnss_dev_platform_ops {
+	int (*request_bus_bandwidth)(int bandwidth);
+	void* (*get_virt_ramdump_mem)(unsigned long *size);
+	void (*device_self_recovery)(void);
+	void (*schedule_recovery_work)(void);
+	void (*device_crashed)(void);
+	u8 * (*get_wlan_mac_address)(u32 *num);
+	int (*set_wlan_mac_address)(const u8 *in, u32 len);
+	int (*power_up)(struct device *dev);
+	int (*power_down)(struct device *dev);
+	int (*register_tsf_captured_handler)(irq_handler_t handler,
+					     void *adapter);
+	int (*unregister_tsf_captured_handler)(void *adapter);
+};
+
+int cnss_pci_request_bus_bandwidth(int bandwidth);
+int cnss_sdio_request_bus_bandwidth(int bandwidth);
+
+void cnss_sdio_device_crashed(void);
+void cnss_pci_device_crashed(void);
+
+void cnss_pci_device_self_recovery(void);
+void cnss_sdio_device_self_recovery(void);
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
+
+void cnss_sdio_schedule_recovery_work(void);
+void cnss_pci_schedule_recovery_work(void);
+
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len);
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len);
+
+u8 *cnss_pci_get_wlan_mac_address(u32 *num);
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num);
+int cnss_sdio_power_up(struct device *dev);
+int cnss_sdio_power_down(struct device *dev);
+int cnss_pcie_power_up(struct device *dev);
+int cnss_pcie_power_down(struct device *dev);
+const char *cnss_wlan_get_evicted_data_file(void);
+#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
new file mode 100644
index 0000000..8797e68
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -0,0 +1,3835 @@
+/* Copyright (c) 2013-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.
+ */
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/esoc_client.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/log2.h>
+#include <linux/etherdevice.h>
+#include <linux/msm_pcie.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <net/cfg80211.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+#define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc)
+
+#define VREG_ON			1
+#define VREG_OFF		0
+#define WLAN_EN_HIGH		1
+#define WLAN_EN_LOW		0
+#define PCIE_LINK_UP		1
+#define PCIE_LINK_DOWN		0
+#define WLAN_BOOTSTRAP_HIGH	1
+#define WLAN_BOOTSTRAP_LOW	0
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN"
+
+#define QCA6174_VENDOR_ID	(0x168C)
+#define QCA6174_DEVICE_ID	(0x003E)
+#define BEELINER_DEVICE_ID      (0x0040)
+#define QCA6174_REV_ID_OFFSET	(0x08)
+#define QCA6174_FW_1_1	(0x11)
+#define QCA6174_FW_1_3	(0x13)
+#define QCA6174_FW_2_0	(0x20)
+#define QCA6174_FW_3_0	(0x30)
+#define QCA6174_FW_3_2	(0x32)
+#define BEELINER_FW	(0x00)
+
+#define QCA6180_VENDOR_ID	(0x168C)
+#define QCA6180_DEVICE_ID	(0x0041)
+#define QCA6180_REV_ID_OFFSET	(0x08)
+
+#define WLAN_EN_VREG_NAME	"vdd-wlan-en"
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_VREG_XTAL_AON_NAME	"vdd-wlan-xtal-aon"
+#define WLAN_VREG_CORE_NAME	"vdd-wlan-core"
+#define WLAN_VREG_SP2T_NAME	"vdd-wlan-sp2t"
+#define WLAN_SWREG_NAME		"wlan-soc-swreg"
+#define WLAN_ANT_SWITCH_NAME	"wlan-ant-switch"
+#define WLAN_EN_GPIO_NAME	"wlan-en-gpio"
+#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio"
+#define PM_OPTIONS		0
+#define PM_OPTIONS_SUSPEND_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+#define PM_OPTIONS_RESUME_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE)
+
+#define SOC_SWREG_VOLT_MAX	1200000
+#define SOC_SWREG_VOLT_MIN	1200000
+#define WLAN_ANT_SWITCH_VOLT_MAX	2700000
+#define WLAN_ANT_SWITCH_VOLT_MIN	2700000
+#define WLAN_ANT_SWITCH_CURR	20000
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define WLAN_VREG_CORE_MAX	1300000
+#define WLAN_VREG_CORE_MIN	1300000
+#define WLAN_VREG_SP2T_MAX	2700000
+#define WLAN_VREG_SP2T_MIN	2700000
+
+#define POWER_ON_DELAY		2
+#define WLAN_VREG_IO_DELAY_MIN	100
+#define WLAN_VREG_IO_DELAY_MAX	1000
+#define WLAN_ENABLE_DELAY	10
+#define PCIE_SWITCH_DELAY       20
+#define WLAN_RECOVERY_DELAY	1
+#define PCIE_ENABLE_DELAY	100
+#define WLAN_BOOTSTRAP_DELAY	10
+#define EVICT_BIN_MAX_SIZE      (512 * 1024)
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+#define FW_NAME_FIXED_LEN	(6)
+#define MAX_NUM_OF_SEGMENTS	(16)
+#define MAX_INDEX_FILE_SIZE	(512)
+#define FW_FILENAME_LENGTH	(13)
+#define TYPE_LENGTH		(4)
+#define PER_FILE_DATA		(21)
+#define MAX_IMAGE_SIZE		(2 * 1024 * 1024)
+#define FW_IMAGE_FTM		(0x01)
+#define FW_IMAGE_MISSION	(0x02)
+#define FW_IMAGE_BDATA		(0x03)
+#define FW_IMAGE_PRINT		(0x04)
+
+#define SEG_METADATA		(0x01)
+#define SEG_NON_PAGED		(0x02)
+#define SEG_LOCKED_PAGE		(0x03)
+#define SEG_UNLOCKED_PAGE	(0x04)
+#define SEG_NON_SECURE_DATA	(0x05)
+
+#define BMI_TEST_SETUP		(0x09)
+
+struct cnss_wlan_gpio_info {
+	char *name;
+	u32 num;
+	bool state;
+	bool init;
+	bool prop;
+};
+
+struct cnss_wlan_vreg_info {
+	struct regulator *wlan_en_reg;
+	struct regulator *wlan_reg;
+	struct regulator *soc_swreg;
+	struct regulator *ant_switch;
+	struct regulator *wlan_reg_io;
+	struct regulator *wlan_reg_xtal;
+	struct regulator *wlan_reg_xtal_aon;
+	struct regulator *wlan_reg_core;
+	struct regulator *wlan_reg_sp2t;
+	bool state;
+};
+
+struct segment_memory {
+	dma_addr_t dma_region;
+	void *cpu_region;
+	u32 size;
+};
+
+/* FW image descriptor lists */
+struct image_desc_hdr {
+	u8 image_id;
+	u8 reserved[3];
+	u32 segments_cnt;
+};
+
+struct segment_desc {
+	u8 segment_id;
+	u8 segment_idx;
+	u8 flags[2];
+	u32 addr_count;
+	u32 addr_low;
+	u32 addr_high;
+};
+
+struct region_desc {
+	u32 addr_low;
+	u32 addr_high;
+	u32 size;
+	u32 reserved;
+};
+
+struct index_file {
+	u32 type;
+	u32 segment_idx;
+	u8 file_name[13];
+};
+
+struct cnss_dual_wifi {
+	bool is_dual_wifi_enabled;
+};
+
+/**
+ * struct wlan_mac_addr - Structure to hold WLAN MAC Address
+ * @mac_addr: MAC address
+ */
+#define MAX_NO_OF_MAC_ADDR 4
+struct cnss_wlan_mac_addr {
+	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+	u32 no_of_mac_addr_set;
+};
+
+/* device_info is expected to be fully populated after cnss_config is invoked.
+ * The function pointer callbacks are expected to be non null as well.
+ */
+static struct cnss_data {
+	struct platform_device *pldev;
+	struct subsys_device *subsys;
+	struct subsys_desc    subsysdesc;
+	struct cnss_wlan_mac_addr wlan_mac_addr;
+	bool is_wlan_mac_set;
+	bool ramdump_dynamic;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	struct cnss_wlan_driver *driver;
+	struct pci_dev *pdev;
+	const struct pci_device_id *id;
+	struct dma_iommu_mapping *smmu_mapping;
+	dma_addr_t smmu_iova_start;
+	size_t smmu_iova_len;
+	struct cnss_wlan_vreg_info vreg_info;
+	bool wlan_en_vreg_support;
+	struct cnss_wlan_gpio_info gpio_info;
+	bool pcie_link_state;
+	bool pcie_link_down_ind;
+	bool pci_register_again;
+	bool notify_modem_status;
+	struct pci_saved_state *saved_state;
+	u16 revision_id;
+	bool recovery_in_progress;
+	atomic_t fw_available;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	/* Virtual Address of the DMA page */
+	void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
+	struct cnss_fw_files fw_files;
+	struct pm_qos_request qos_request;
+	void *modem_notify_handler;
+	int modem_current_status;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+	void *subsys_handle;
+	struct esoc_desc *esoc_desc;
+	struct cnss_platform_cap cap;
+	struct msm_pcie_register_event event_reg;
+	struct wakeup_source ws;
+	u32 recovery_count;
+	enum cnss_driver_status driver_status;
+#ifdef CONFIG_CNSS_SECURE_FW
+	void *fw_mem;
+#endif
+	u32 device_id;
+	int fw_image_setup;
+	u32 bmi_test;
+	void *fw_cpu;
+	dma_addr_t fw_dma;
+	u32 fw_dma_size;
+	u32 fw_seg_count;
+	struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
+	/* Firmware setup complete lock */
+	struct mutex fw_setup_stat_lock;
+	void *bdata_cpu;
+	dma_addr_t bdata_dma;
+	u32 bdata_dma_size;
+	u32 bdata_seg_count;
+	struct segment_memory bdata_seg_mem[MAX_NUM_OF_SEGMENTS];
+	int wlan_bootstrap_gpio;
+	atomic_t auto_suspended;
+	bool monitor_wake_intr;
+	struct cnss_dual_wifi dual_wifi_info;
+	struct cnss_dev_platform_ops platform_ops;
+} *penv;
+
+static unsigned int pcie_link_down_panic;
+module_param(pcie_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pcie_link_down_panic,
+		 "Trigger kernel panic when PCIe link down is detected");
+
+static void cnss_put_wlan_enable_gpio(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support)
+		regulator_put(vreg_info->wlan_en_reg);
+	else
+		gpio_free(gpio_info->num);
+}
+
+static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_enable_reg_core;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_enable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_enable_reg_io;
+		}
+
+		usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX);
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon enable failed\n",
+			       __func__);
+			goto error_enable_reg_xtal_aon;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_enable_reg_xtal;
+		}
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator enable failed for WLAN power\n",
+		       __func__);
+		goto error_enable;
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_enable_reg_sp2t;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_enable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator enable failed for ant_switch\n",
+			       __func__);
+			goto error_enable_ant_switch;
+		}
+	}
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator enable failed for external soc-swreg\n",
+			       __func__);
+			goto error_enable_soc_swreg;
+		}
+	}
+
+	return ret;
+
+error_enable_soc_swreg:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+error_enable_ant_switch:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+error_enable_reg_sp2t:
+	regulator_disable(vreg_info->wlan_reg);
+error_enable:
+	if (vreg_info->wlan_reg_xtal)
+		regulator_disable(vreg_info->wlan_reg_xtal);
+error_enable_reg_xtal:
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_disable(vreg_info->wlan_reg_xtal_aon);
+error_enable_reg_xtal_aon:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+error_enable_reg_io:
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+error_enable_reg_core:
+	return ret;
+}
+
+static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_disable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator disable failed for external soc-swreg\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_disable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator disable failed for ant_switch\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_disable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	ret = regulator_disable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator disable failed for WLAN power\n",
+		       __func__);
+		goto error_disable;
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon disable failed\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_disable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_disable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+error_disable:
+	return ret;
+}
+
+static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state)
+{
+	int ret = 0;
+
+	if (vreg_info->state == state) {
+		pr_debug("Already wlan vreg state is %s\n",
+			 state ? "enabled" : "disabled");
+		goto out;
+	}
+
+	if (state)
+		ret = cnss_wlan_vreg_on(vreg_info);
+	else
+		ret = cnss_wlan_vreg_off(vreg_info);
+
+	if (ret)
+		goto out;
+
+	pr_debug("%s: wlan vreg is now %s\n", __func__,
+		 state ? "enabled" : "disabled");
+	vreg_info->state = state;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_gpio_init(struct cnss_wlan_gpio_info *info)
+{
+	int ret = 0;
+
+	ret = gpio_request(info->num, info->name);
+
+	if (ret) {
+		pr_err("can't get gpio %s ret %d\n", info->name, ret);
+		goto err_gpio_req;
+	}
+
+	ret = gpio_direction_output(info->num, info->init);
+
+	if (ret) {
+		pr_err("can't set gpio direction %s ret %d\n", info->name, ret);
+		goto err_gpio_dir;
+	}
+	info->state = info->init;
+
+	return ret;
+
+err_gpio_dir:
+	gpio_free(info->num);
+
+err_gpio_req:
+
+	return ret;
+}
+
+static int cnss_wlan_bootstrap_gpio_init(void)
+{
+	int ret = 0;
+
+	ret = gpio_request(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_GPIO_NAME);
+	if (ret) {
+		pr_err("%s: Can't get GPIO %s, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		goto out;
+	}
+
+	ret = gpio_direction_output(penv->wlan_bootstrap_gpio,
+				    WLAN_BOOTSTRAP_HIGH);
+	if (ret) {
+		pr_err("%s: Can't set GPIO %s direction, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		gpio_free(penv->wlan_bootstrap_gpio);
+		goto out;
+	}
+
+	msleep(WLAN_BOOTSTRAP_DELAY);
+out:
+	return ret;
+}
+
+static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state)
+{
+	if (!info->prop)
+		return;
+
+	if (info->state == state) {
+		pr_debug("Already %s gpio is %s\n",
+			 info->name, state ? "high" : "low");
+		return;
+	}
+
+	gpio_set_value(info->num, state);
+	info->state = state;
+
+	pr_debug("%s: %s gpio is now %s\n", __func__,
+		 info->name, info->state ? "enabled" : "disabled");
+}
+
+static int cnss_configure_wlan_en_gpio(bool state)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support) {
+		if (state)
+			ret = regulator_enable(vreg_info->wlan_en_reg);
+		else
+			ret = regulator_disable(vreg_info->wlan_en_reg);
+	} else {
+		cnss_wlan_gpio_set(gpio_info, state);
+	}
+
+	msleep(WLAN_ENABLE_DELAY);
+	return ret;
+}
+
+static void cnss_disable_xtal_ldo(struct platform_device *pdev)
+{
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (info->wlan_reg_xtal) {
+		regulator_disable(info->wlan_reg_xtal);
+		regulator_put(info->wlan_reg_xtal);
+	}
+
+	if (info->wlan_reg_xtal_aon) {
+		regulator_disable(info->wlan_reg_xtal_aon);
+		regulator_put(info->wlan_reg_xtal_aon);
+	}
+}
+
+static int cnss_enable_xtal_ldo(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_AON_NAME "-supply", NULL))
+		goto enable_xtal;
+
+	info->wlan_reg_xtal_aon = regulator_get(&pdev->dev,
+						WLAN_VREG_XTAL_AON_NAME);
+	if (IS_ERR(info->wlan_reg_xtal_aon)) {
+		ret = PTR_ERR(info->wlan_reg_xtal_aon);
+		pr_err("%s: XTAL AON Regulator get failed err:%d\n", __func__,
+		       ret);
+		return ret;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal_aon);
+	if (ret) {
+		pr_err("%s: VREG_XTAL_ON enable failed\n", __func__);
+		goto end;
+	}
+
+enable_xtal:
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_NAME "-supply", NULL))
+		goto out_disable_xtal_aon;
+
+	info->wlan_reg_xtal = regulator_get(&pdev->dev, WLAN_VREG_XTAL_NAME);
+
+	if (IS_ERR(info->wlan_reg_xtal)) {
+		ret = PTR_ERR(info->wlan_reg_xtal);
+		pr_err("%s XTAL Regulator get failed err:%d\n", __func__, ret);
+		goto out_disable_xtal_aon;
+	}
+
+	ret = regulator_set_voltage(info->wlan_reg_xtal, WLAN_VREG_XTAL_MIN,
+				    WLAN_VREG_XTAL_MAX);
+	if (ret) {
+		pr_err("%s: Set wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal);
+	if (ret) {
+		pr_err("%s: Enable wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	return 0;
+
+out_put_xtal:
+	if (info->wlan_reg_xtal)
+		regulator_put(info->wlan_reg_xtal);
+
+out_disable_xtal_aon:
+	if (info->wlan_reg_xtal_aon)
+		regulator_disable(info->wlan_reg_xtal_aon);
+
+end:
+	if (info->wlan_reg_xtal_aon)
+		regulator_put(info->wlan_reg_xtal_aon);
+
+	return ret;
+}
+
+static int cnss_get_wlan_enable_gpio(
+	struct cnss_wlan_gpio_info *gpio_info,
+	struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+
+	if (!of_find_property(dev->of_node, gpio_info->name, NULL)) {
+		gpio_info->prop = false;
+		return -ENODEV;
+	}
+
+	gpio_info->prop = true;
+	ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0);
+	if (ret >= 0) {
+		gpio_info->num = ret;
+	} else {
+		if (ret == -EPROBE_DEFER)
+			pr_debug("get WLAN_EN GPIO probe defer\n");
+		else
+			pr_err(
+			"can't get gpio %s ret %d", gpio_info->name, ret);
+	}
+
+	ret = cnss_wlan_gpio_init(gpio_info);
+	if (ret)
+		pr_err("gpio init failed\n");
+
+	return ret;
+}
+
+static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device_node *node = (&pdev->dev)->of_node;
+
+	if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL))
+		return ret;
+
+	penv->wlan_bootstrap_gpio =
+		of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0);
+	if (penv->wlan_bootstrap_gpio > 0) {
+		ret = cnss_wlan_bootstrap_gpio_init();
+	} else {
+		ret = penv->wlan_bootstrap_gpio;
+		pr_err(
+		"%s: Can't get GPIO %s, ret = %d",
+		__func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+	}
+
+	return ret;
+}
+
+static int cnss_wlan_get_resources(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	struct device_node *node = pdev->dev.of_node;
+
+	if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_core = regulator_get(&pdev->dev,
+			WLAN_VREG_CORE_NAME);
+		if (IS_ERR(vreg_info->wlan_reg_core)) {
+			ret = PTR_ERR(vreg_info->wlan_reg_core);
+
+			if (ret == -EPROBE_DEFER) {
+				pr_err("%s: wlan_reg_core probe deferred\n",
+				       __func__);
+			} else {
+				pr_err("%s: Get wlan_reg_core failed\n",
+				       __func__);
+			}
+			goto err_reg_core_get;
+		}
+
+		ret = regulator_set_voltage(vreg_info->wlan_reg_core,
+					    WLAN_VREG_CORE_MIN,
+					    WLAN_VREG_CORE_MAX);
+		if (ret) {
+			pr_err("%s: Set wlan_reg_core failed\n", __func__);
+			goto err_reg_core_set;
+		}
+
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: Enable wlan_reg_core failed\n", __func__);
+			goto err_reg_core_enable;
+		}
+	}
+
+	if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_io = regulator_get(&pdev->dev,
+			WLAN_VREG_IO_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_io)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_io,
+						    WLAN_VREG_IO_MIN,
+						    WLAN_VREG_IO_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_io);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_enable;
+			}
+
+			usleep_range(WLAN_VREG_IO_DELAY_MIN,
+				     WLAN_VREG_IO_DELAY_MAX);
+		}
+	}
+
+	if (cnss_enable_xtal_ldo(pdev))
+		goto err_reg_xtal_enable;
+
+	vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
+
+	if (IS_ERR(vreg_info->wlan_reg)) {
+		if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
+			pr_err("%s: vreg probe defer\n", __func__);
+		else
+			pr_err("%s: vreg regulator get failed\n", __func__);
+		ret = PTR_ERR(vreg_info->wlan_reg);
+		goto err_reg_get;
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+
+	if (ret) {
+		pr_err("%s: vreg initial vote failed\n", __func__);
+		goto err_reg_enable;
+	}
+
+	if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_sp2t =
+			regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_sp2t)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_sp2t,
+						    WLAN_VREG_SP2T_MIN,
+						    WLAN_VREG_SP2T_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_enable;
+			}
+		}
+	}
+
+	if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) {
+		vreg_info->ant_switch =
+			regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME);
+		if (!IS_ERR(vreg_info->ant_switch)) {
+			ret = regulator_set_voltage(vreg_info->ant_switch,
+						    WLAN_ANT_SWITCH_VOLT_MIN,
+						    WLAN_ANT_SWITCH_VOLT_MAX);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch voltage failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_set_load(vreg_info->ant_switch,
+						 WLAN_ANT_SWITCH_CURR);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch current failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_enable(vreg_info->ant_switch);
+			if (ret < 0) {
+				pr_err("%s: Enable ant_switch failed\n",
+				       __func__);
+				goto err_ant_switch_enable;
+			}
+		}
+	}
+
+	if (of_find_property(node, "qcom,wlan-uart-access", NULL))
+		penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS;
+
+	if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) {
+		vreg_info->soc_swreg = regulator_get(&pdev->dev,
+			WLAN_SWREG_NAME);
+		if (IS_ERR(vreg_info->soc_swreg)) {
+			pr_err("%s: soc-swreg node not found\n",
+			       __func__);
+			goto err_reg_get2;
+		}
+		ret = regulator_set_voltage(vreg_info->soc_swreg,
+					    SOC_SWREG_VOLT_MIN,
+					    SOC_SWREG_VOLT_MAX);
+		if (ret) {
+			pr_err("%s: vreg initial voltage set failed on soc-swreg\n",
+			       __func__);
+			goto err_reg_set;
+		}
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: vreg initial vote failed\n", __func__);
+			goto err_reg_enable2;
+		}
+		penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG;
+	}
+
+	penv->wlan_en_vreg_support =
+		of_property_read_bool(node, "qcom,wlan-en-vreg-support");
+	if (penv->wlan_en_vreg_support) {
+		vreg_info->wlan_en_reg =
+			regulator_get(&pdev->dev, WLAN_EN_VREG_NAME);
+		if (IS_ERR(vreg_info->wlan_en_reg)) {
+			pr_err("%s:wlan_en vreg get failed\n", __func__);
+			ret = PTR_ERR(vreg_info->wlan_en_reg);
+			goto err_wlan_en_reg_get;
+		}
+	}
+
+	if (!penv->wlan_en_vreg_support) {
+		ret = cnss_get_wlan_enable_gpio(gpio_info, pdev);
+		if (ret) {
+			pr_err(
+			"%s:Failed to config the WLAN_EN gpio\n", __func__);
+			goto err_gpio_wlan_en;
+		}
+	}
+	vreg_info->state = VREG_ON;
+
+	ret = cnss_get_wlan_bootstrap_gpio(pdev);
+	if (ret) {
+		pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__);
+		goto err_gpio_wlan_bootstrap;
+	}
+
+	return ret;
+
+err_gpio_wlan_bootstrap:
+	cnss_put_wlan_enable_gpio();
+err_gpio_wlan_en:
+err_wlan_en_reg_get:
+	vreg_info->wlan_en_reg = NULL;
+	if (vreg_info->soc_swreg)
+		regulator_disable(vreg_info->soc_swreg);
+	vreg_info->state = VREG_OFF;
+
+err_reg_enable2:
+err_reg_set:
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+
+err_reg_get2:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+
+err_ant_switch_enable:
+err_ant_switch_set:
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+
+err_reg_sp2t_enable:
+err_reg_sp2t_set:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_disable(vreg_info->wlan_reg);
+
+err_reg_enable:
+	regulator_put(vreg_info->wlan_reg);
+err_reg_get:
+	cnss_disable_xtal_ldo(pdev);
+
+err_reg_xtal_enable:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+
+err_reg_io_enable:
+err_reg_io_set:
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+
+err_reg_core_enable:
+err_reg_core_set:
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+
+err_reg_core_get:
+	return ret;
+}
+
+static void cnss_wlan_release_resources(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_free(penv->wlan_bootstrap_gpio);
+	cnss_put_wlan_enable_gpio();
+	gpio_info->state = WLAN_EN_LOW;
+	gpio_info->prop = false;
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_put(vreg_info->wlan_reg);
+	if (vreg_info->wlan_reg_xtal)
+		regulator_put(vreg_info->wlan_reg_xtal);
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_put(vreg_info->wlan_reg_xtal_aon);
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+	vreg_info->state = VREG_OFF;
+}
+
+static u8 cnss_get_pci_dev_bus_number(struct pci_dev *pdev)
+{
+	return pdev->bus->number;
+}
+
+void cnss_setup_fw_files(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_1_1:
+		strlcpy(penv->fw_files.image_file, "qwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd11.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_1_3:
+		strlcpy(penv->fw_files.image_file, "qwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd13.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_2_0:
+		strlcpy(penv->fw_files.image_file, "qwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd20.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		strlcpy(penv->fw_files.image_file, "qwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd30.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	default:
+		strlcpy(penv->fw_files.image_file, "qwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+	}
+}
+
+int cnss_get_fw_files(struct cnss_fw_files *pfw_files)
+{
+	if (!penv || !pfw_files)
+		return -ENODEV;
+
+	*pfw_files = penv->fw_files;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+	penv->fw_mem = devm_kzalloc(&pdev->dev, MAX_FIRMWARE_SIZE, GFP_KERNEL);
+}
+#else
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+}
+#endif
+
+static int get_image_file(const u8 *index_info, u8 *file_name,
+			  u32 *type, u32 *segment_idx)
+{
+	if (!file_name || !index_info || !type)
+		return -EINVAL;
+
+	memcpy(type, index_info, TYPE_LENGTH);
+	memcpy(segment_idx, index_info + TYPE_LENGTH, TYPE_LENGTH);
+	memcpy(file_name, index_info + TYPE_LENGTH + TYPE_LENGTH,
+	       FW_FILENAME_LENGTH);
+
+	pr_debug("%u: %u: %s", *type, *segment_idx, file_name);
+
+	return PER_FILE_DATA;
+}
+
+static void print_allocated_image_table(void)
+{
+	u32 seg = 0, count = 0;
+	u8 *dump_addr;
+	struct segment_memory *pseg_mem = penv->fw_seg_mem;
+	struct segment_memory *p_bdata_seg_mem = penv->bdata_seg_mem;
+
+	pr_debug("%s: Dumping FW IMAGE\n", __func__);
+	while (seg++ < penv->fw_seg_count) {
+		dump_addr = (u8 *)pseg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < pseg_mem->size -
+				sizeof(struct region_desc); count++)
+			pr_debug("%02x", dump_addr[count]);
+
+		pseg_mem++;
+	}
+
+	seg = 0;
+	pr_debug("%s: Dumping BOARD DATA\n", __func__);
+	while (seg++ < penv->bdata_seg_count) {
+		dump_addr = (u8 *)p_bdata_seg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < p_bdata_seg_mem->size -
+			     sizeof(struct region_desc); count++)
+			pr_debug("%02x ", dump_addr[count]);
+
+		p_bdata_seg_mem++;
+	}
+}
+
+static void free_allocated_image_table(void)
+{
+	struct device *dev = &penv->pdev->dev;
+	struct segment_memory *pseg_mem;
+	u32 seg = 0;
+
+	/* free fw memroy */
+	pseg_mem = penv->fw_seg_mem;
+	while (seg++ < penv->fw_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region, pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->fw_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->fw_cpu, penv->fw_dma);
+	penv->fw_seg_count = 0;
+	penv->fw_dma = 0;
+	penv->fw_cpu = NULL;
+	penv->fw_dma_size = 0;
+
+	/* free bdata memory */
+	seg = 0;
+	pseg_mem = penv->bdata_seg_mem;
+	while (seg++ < penv->bdata_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region,
+				  pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->bdata_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->bdata_cpu, penv->bdata_dma);
+	penv->bdata_seg_count = 0;
+	penv->bdata_dma = 0;
+	penv->bdata_cpu = NULL;
+	penv->bdata_dma_size = 0;
+}
+
+static int cnss_setup_fw_image_table(int mode)
+{
+	struct image_desc_hdr *image_hdr;
+	struct segment_desc *pseg = NULL;
+	const struct firmware *fw_index, *fw_image;
+	struct device *dev = NULL;
+	char reserved[3] = "";
+	u8 image_file[FW_FILENAME_LENGTH] = "";
+	u8 index_file[FW_FILENAME_LENGTH] = "";
+	u8 index_info[MAX_INDEX_FILE_SIZE] = "";
+	size_t image_desc_size = 0, file_size = 0;
+	size_t index_pos = 0, image_pos = 0;
+	struct region_desc *reg_desc = NULL;
+	u32 type = 0;
+	u32 segment_idx = 0;
+	uintptr_t address;
+	int ret = 0;
+	dma_addr_t dma_addr;
+	void *vaddr = NULL;
+	dma_addr_t paddr;
+	struct segment_memory *pseg_mem;
+	u32 *pseg_count;
+
+	if (!penv || !penv->pdev) {
+		pr_err("cnss: invalid penv or pdev or dev\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dev = &penv->pdev->dev;
+
+	/*  meta data file has image details */
+	switch (mode) {
+	case FW_IMAGE_FTM:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qftm.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_MISSION:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qwlan.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_BDATA:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "bdwlan.bin");
+		pseg_mem = penv->bdata_seg_mem;
+		pseg_count = &penv->bdata_seg_count;
+		break;
+	default:
+		pr_err("%s: Unknown meta data file type 0x%x\n",
+		       __func__, mode);
+		ret = -EINVAL;
+	}
+	if (ret < 0)
+		goto err;
+
+	image_desc_size = sizeof(struct image_desc_hdr) +
+		sizeof(struct segment_desc) * MAX_NUM_OF_SEGMENTS;
+
+	vaddr = dma_alloc_coherent(dev, image_desc_size,
+				   &paddr, GFP_KERNEL);
+
+	if (!vaddr) {
+		pr_err("cnss: image desc allocation failure\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(vaddr, 0, image_desc_size);
+
+	image_hdr = (struct image_desc_hdr *)vaddr;
+	image_hdr->image_id = mode;
+	memcpy(image_hdr->reserved, reserved, 3);
+
+	pr_err("cnss: request meta data file %s\n", index_file);
+	ret = request_firmware(&fw_index, index_file, dev);
+	if (ret || !fw_index || !fw_index->data || !fw_index->size) {
+		pr_err("cnss: meta data file open failure %s\n", index_file);
+		goto err_free;
+	}
+
+	if (fw_index->size > MAX_INDEX_FILE_SIZE) {
+		pr_err("cnss: meta data file has invalid size %s: %zu\n",
+		       index_file, fw_index->size);
+		release_firmware(fw_index);
+		goto err_free;
+	}
+
+	memcpy(index_info, fw_index->data, fw_index->size);
+	file_size = fw_index->size;
+	release_firmware(fw_index);
+
+	while (file_size >= PER_FILE_DATA  && image_pos < image_desc_size &&
+	       image_hdr->segments_cnt < MAX_NUM_OF_SEGMENTS) {
+		ret = get_image_file(index_info + index_pos,
+				     image_file, &type, &segment_idx);
+		if (ret == -EINVAL)
+			goto err_free;
+
+		file_size -= ret;
+		index_pos += ret;
+		pseg = vaddr + image_pos +
+				sizeof(struct image_desc_hdr);
+
+		switch (type) {
+		case SEG_METADATA:
+		case SEG_NON_PAGED:
+		case SEG_LOCKED_PAGE:
+		case SEG_UNLOCKED_PAGE:
+		case SEG_NON_SECURE_DATA:
+
+			image_hdr->segments_cnt++;
+			pseg->segment_id = type;
+			pseg->segment_idx = (u8)(segment_idx & 0xff);
+			memcpy(pseg->flags, reserved, 2);
+
+			ret = request_firmware(&fw_image, image_file, dev);
+			if (ret || !fw_image || !fw_image->data ||
+			    !fw_image->size) {
+				pr_err("cnss: image file read failed %s",
+				       image_file);
+				goto err_free;
+			}
+			if (fw_image->size > MAX_IMAGE_SIZE) {
+				pr_err("cnss: %s: image file invalid size %zu\n",
+				       image_file, fw_image->size);
+				release_firmware(fw_image);
+				ret = -EINVAL;
+				goto err_free;
+			}
+			reg_desc =
+				dma_alloc_coherent(dev,
+						   sizeof(struct region_desc) +
+						   fw_image->size,
+						   &dma_addr, GFP_KERNEL);
+			if (!reg_desc) {
+				pr_err("cnss: region allocation failure\n");
+				ret = -ENOMEM;
+				release_firmware(fw_image);
+				goto err_free;
+			}
+			address = (uintptr_t)dma_addr;
+			pseg->addr_low = address & 0xFFFFFFFF;
+			pseg->addr_high = 0x00;
+			/* one region for one image file */
+			pseg->addr_count = 1;
+			memcpy((u8 *)reg_desc + sizeof(struct region_desc),
+			       fw_image->data, fw_image->size);
+			address += sizeof(struct region_desc);
+			reg_desc->addr_low = address & 0xFFFFFFFF;
+			reg_desc->addr_high = 0x00;
+			reg_desc->reserved = 0;
+			reg_desc->size = fw_image->size;
+
+			pseg_mem[*pseg_count].dma_region = dma_addr;
+			pseg_mem[*pseg_count].cpu_region = reg_desc;
+			pseg_mem[*pseg_count].size =
+				sizeof(struct region_desc) + fw_image->size;
+
+			release_firmware(fw_image);
+			(*pseg_count)++;
+			break;
+
+		default:
+			pr_err("cnss: Unknown segment %d", type);
+			ret = -EINVAL;
+			goto err_free;
+		}
+		image_pos += sizeof(struct segment_desc);
+	}
+	if (mode != FW_IMAGE_BDATA) {
+		penv->fw_cpu = vaddr;
+		penv->fw_dma = paddr;
+		penv->fw_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	} else {
+		penv->bdata_cpu = vaddr;
+		penv->bdata_dma = paddr;
+		penv->bdata_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	}
+	pr_info("%s: Mode %d: Image setup table built on host", __func__, mode);
+
+	return file_size;
+err_free:
+	free_allocated_image_table();
+err:
+	pr_err("cnss: image file setup failed %d\n", ret);
+	return ret;
+}
+
+int cnss_get_fw_image(struct image_desc_info *image_desc_info)
+{
+	if (!image_desc_info || !penv ||
+	    !penv->fw_seg_count || !penv->bdata_seg_count)
+		return -EINVAL;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	image_desc_info->fw_addr = penv->fw_dma;
+	image_desc_info->fw_size = penv->fw_dma_size;
+	image_desc_info->bdata_addr = penv->bdata_dma;
+	image_desc_info->bdata_size = penv->bdata_dma_size;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_image);
+
+static ssize_t wlan_setup_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->revision_id);
+}
+
+static DEVICE_ATTR(wlan_setup, 0400,
+			wlan_setup_show, NULL);
+
+static int cnss_wlan_is_codeswap_supported(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+static int cnss_smmu_init(struct device *dev)
+{
+	struct dma_iommu_mapping *mapping;
+	int atomic_ctx = 1;
+	int ret;
+
+	mapping = arm_iommu_create_mapping(&platform_bus_type,
+					   penv->smmu_iova_start,
+					   penv->smmu_iova_len);
+	if (IS_ERR(mapping)) {
+		ret = PTR_ERR(mapping);
+		pr_err("%s: create mapping failed, err = %d\n", __func__, ret);
+		goto map_fail;
+	}
+
+	ret = iommu_domain_set_attr(mapping->domain,
+				    DOMAIN_ATTR_ATOMIC,
+				    &atomic_ctx);
+	if (ret) {
+		pr_err("%s: set atomic_ctx attribute failed, err = %d\n",
+		       __func__, ret);
+		goto set_attr_fail;
+	}
+
+	ret = arm_iommu_attach_device(dev, mapping);
+	if (ret) {
+		pr_err("%s: attach device failed, err = %d\n", __func__, ret);
+		goto attach_fail;
+	}
+
+	penv->smmu_mapping = mapping;
+
+	return ret;
+
+attach_fail:
+set_attr_fail:
+	arm_iommu_release_mapping(mapping);
+map_fail:
+	return ret;
+}
+
+static void cnss_smmu_remove(struct device *dev)
+{
+	arm_iommu_detach_device(dev);
+	arm_iommu_release_mapping(penv->smmu_mapping);
+
+	penv->smmu_mapping = NULL;
+}
+
+#ifdef CONFIG_PCI_MSM
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return pci_store_saved_state(dev);
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return msm_pcie_pm_control(pm_opt, bus_num, pdev, NULL, options);
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return pci_load_and_free_saved_state(dev, state);
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return msm_pcie_shadow_control(dev, enable);
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_deregister_event(reg);
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return msm_pcie_recover_config(dev);
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_register_event(reg);
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return msm_pcie_enumerate(rc_idx);
+}
+#else /* !defined CONFIG_PCI_MSM */
+
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return NULL;
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return -ENODEV;
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return 0;
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return -EPROBE_DEFER;
+}
+#endif
+
+static void cnss_pcie_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth;
+	pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_pci_device_self_recovery;
+	pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work;
+	pf_ops->device_crashed = cnss_pci_device_crashed;
+	pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address;
+	pf_ops->power_up = cnss_pcie_power_up;
+	pf_ops->power_down = cnss_pcie_power_down;
+
+	dev->platform_data = pf_ops;
+}
+
+static void cnss_pcie_reset_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	dev->platform_data = NULL;
+}
+
+static int cnss_wlan_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	void *cpu_addr;
+	dma_addr_t dma_handle;
+	struct codeswap_codeseg_info *cnss_seg_info = NULL;
+	struct device *dev = &pdev->dev;
+
+	cnss_pcie_set_platform_ops(dev);
+	penv->pdev = pdev;
+	penv->id = id;
+	atomic_set(&penv->fw_available, 0);
+	penv->device_id = pdev->device;
+
+	if (penv->smmu_iova_len) {
+		ret = cnss_smmu_init(&pdev->dev);
+		if (ret) {
+			pr_err("%s: SMMU init failed, err = %d\n",
+			       __func__, ret);
+			goto smmu_init_fail;
+		}
+	}
+
+	if (penv->pci_register_again) {
+		pr_debug("%s: PCI re-registration complete\n", __func__);
+		penv->pci_register_again = false;
+		return 0;
+	}
+
+	switch (pdev->device) {
+	case QCA6180_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6180_REV_ID_OFFSET,
+				     &penv->revision_id);
+		break;
+
+	case QCA6174_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6174_REV_ID_OFFSET,
+				     &penv->revision_id);
+		cnss_setup_fw_files(penv->revision_id);
+		break;
+
+	default:
+		pr_err("cnss: unknown device found %d\n", pdev->device);
+		ret = -EPROBE_DEFER;
+		goto err_unknown;
+	}
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("Failed to shutdown PCIe link\n");
+			goto err_pcie_suspend;
+		}
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+
+	if (ret) {
+		pr_err("can't turn off wlan vreg\n");
+		goto err_pcie_suspend;
+	}
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	cnss_wlan_fw_mem_alloc(pdev);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup);
+
+	if (ret) {
+		pr_err("Can't Create Device file\n");
+		goto err_pcie_suspend;
+	}
+
+	if (cnss_wlan_is_codeswap_supported(penv->revision_id)) {
+		pr_debug("Code-swap not enabled: %d\n", penv->revision_id);
+		goto err_pcie_suspend;
+	}
+
+	cpu_addr = dma_alloc_coherent(dev, EVICT_BIN_MAX_SIZE,
+				      &dma_handle, GFP_KERNEL);
+	if (!cpu_addr || !dma_handle) {
+		pr_err("cnss: Memory Alloc failed for codeswap feature\n");
+		goto err_pcie_suspend;
+	}
+
+	memset(cpu_addr, 0, EVICT_BIN_MAX_SIZE);
+	cnss_seg_info = devm_kzalloc(dev, sizeof(*cnss_seg_info),
+				     GFP_KERNEL);
+	if (!cnss_seg_info)
+		goto end_dma_alloc;
+
+	memset(cnss_seg_info, 0, sizeof(*cnss_seg_info));
+	cnss_seg_info->codeseg_busaddr[0]   = (void *)dma_handle;
+	penv->codeseg_cpuaddr[0]            = cpu_addr;
+	cnss_seg_info->codeseg_size         = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->codeseg_total_bytes  = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->num_codesegs         = 1;
+	cnss_seg_info->codeseg_size_log2    = ilog2(EVICT_BIN_MAX_SIZE);
+
+	penv->cnss_seg_info = cnss_seg_info;
+	pr_debug("%s: Successfully allocated memory for CODESWAP\n", __func__);
+
+	return ret;
+
+end_dma_alloc:
+	dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle);
+err_unknown:
+err_pcie_suspend:
+smmu_init_fail:
+	cnss_pcie_reset_platform_ops(dev);
+	return ret;
+}
+
+static void cnss_wlan_pci_remove(struct pci_dev *pdev)
+{
+	struct device *dev;
+
+	if (!penv)
+		return;
+
+	dev = &penv->pldev->dev;
+	cnss_pcie_reset_platform_ops(dev);
+	device_remove_file(dev, &dev_attr_wlan_setup);
+
+	if (penv->smmu_mapping)
+		cnss_smmu_remove(&pdev->dev);
+}
+
+static int cnss_wlan_pci_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->suspend) {
+		ret = wdriver->suspend(pdev, state);
+
+		if (penv->pcie_link_state) {
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+		}
+	}
+	penv->monitor_wake_intr = false;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_pci_resume(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->resume && !penv->pcie_link_down_ind) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+		pci_restore_state(pdev);
+
+		ret = wdriver->resume(pdev);
+	}
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdrv;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime suspend start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_suspend)
+		ret = wdrv->runtime_ops->runtime_suspend(to_pci_dev(dev));
+
+	pr_info("cnss: runtime suspend status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_resume(struct device *dev)
+{
+	struct cnss_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime resume start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_resume)
+		ret = wdrv->runtime_ops->runtime_resume(to_pci_dev(dev));
+
+	pr_info("cnss: runtime resume status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_idle(struct device *dev)
+{
+	pr_debug("cnss: runtime idle\n");
+
+	pm_request_autosuspend(dev);
+
+	return -EBUSY;
+}
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+static int cnss_pm_notify(struct notifier_block *b,
+			  unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&cnss_pm_sem);
+		break;
+
+	case PM_POST_SUSPEND:
+		up_write(&cnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cnss_pm_notifier = {
+	.notifier_call = cnss_pm_notify,
+};
+
+static const struct pci_device_id cnss_wlan_pci_id_table[] = {
+	{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6174_VENDOR_ID, BEELINER_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6180_VENDOR_ID, QCA6180_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_wlan_pci_id_table);
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops cnss_wlan_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cnss_wlan_pci_suspend, cnss_wlan_pci_resume)
+	SET_RUNTIME_PM_OPS(cnss_wlan_runtime_suspend, cnss_wlan_runtime_resume,
+			   cnss_wlan_runtime_idle)
+};
+#endif
+
+struct pci_driver cnss_wlan_pci_driver = {
+	.name     = "cnss_wlan_pci",
+	.id_table = cnss_wlan_pci_id_table,
+	.probe    = cnss_wlan_pci_probe,
+	.remove   = cnss_wlan_pci_remove,
+#ifdef CONFIG_PM
+	.driver = {
+		.pm = &cnss_wlan_pm_ops,
+	},
+#endif
+};
+
+static ssize_t fw_image_setup_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->fw_image_setup);
+}
+
+static ssize_t fw_image_setup_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int val;
+	int ret;
+
+	if (!penv)
+		return -ENODEV;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	pr_info("%s: Firmware setup in progress\n", __func__);
+
+	if (kstrtoint(buf, 0, &val)) {
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -EINVAL;
+	}
+
+	if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION ||
+	    val == FW_IMAGE_BDATA) {
+		pr_info("%s: fw image setup triggered %d\n", __func__, val);
+		ret = cnss_setup_fw_image_table(val);
+		if (ret != 0) {
+			pr_err("%s: Invalid parsing of FW image files %d\n",
+			       __func__, ret);
+			mutex_unlock(&penv->fw_setup_stat_lock);
+			return -EINVAL;
+		}
+		penv->fw_image_setup = val;
+	} else if (val == FW_IMAGE_PRINT) {
+		print_allocated_image_table();
+	} else if (val == BMI_TEST_SETUP) {
+		penv->bmi_test = val;
+	}
+
+	pr_info("%s: Firmware setup completed\n", __func__);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+	return count;
+}
+
+static DEVICE_ATTR(fw_image_setup, 0600,
+	fw_image_setup_show, fw_image_setup_store);
+
+void cnss_pci_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_pci_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_pci_recovery_work, cnss_pci_recovery_work_handler);
+
+void cnss_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery_work);
+
+static inline void __cnss_disable_irq(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	disable_irq(pdev->irq);
+}
+
+void cnss_pci_events_cb(struct msm_pcie_notify *notify)
+{
+	unsigned long flags;
+
+	if (!notify)
+		return;
+
+	switch (notify->event) {
+	case MSM_PCIE_EVENT_LINKDOWN:
+		if (pcie_link_down_panic)
+			panic("PCIe link is down\n");
+
+		spin_lock_irqsave(&pci_link_down_lock, flags);
+		if (penv->pcie_link_down_ind) {
+			pr_debug("PCI link down recovery is in progress, ignore\n");
+			spin_unlock_irqrestore(&pci_link_down_lock, flags);
+			return;
+		}
+		penv->pcie_link_down_ind = true;
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+		pr_err("PCI link down, schedule recovery\n");
+		__cnss_disable_irq(notify->user);
+		schedule_work(&cnss_pci_recovery_work);
+		break;
+
+	case MSM_PCIE_EVENT_WAKEUP:
+		if (penv->monitor_wake_intr &&
+		    atomic_read(&penv->auto_suspended)) {
+			penv->monitor_wake_intr = false;
+			pm_request_resume(&penv->pdev->dev);
+		}
+		break;
+
+	default:
+		pr_err("cnss: invalid event from PCIe callback %d\n",
+		       notify->event);
+	}
+}
+
+void cnss_wlan_pci_link_down(void)
+{
+	unsigned long flags;
+
+	if (pcie_link_down_panic)
+		panic("PCIe link is down\n");
+
+	spin_lock_irqsave(&pci_link_down_lock, flags);
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress, ignore\n");
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+		return;
+	}
+	penv->pcie_link_down_ind = true;
+	spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+	pr_err("PCI link down detected by host driver, schedule recovery\n");
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_wlan_pci_link_down);
+
+int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return cnss_msm_pcie_shadow_control(dev, enable);
+}
+EXPORT_SYMBOL(cnss_pcie_shadow_control);
+
+int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
+{
+	struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	if (!cnss_seg_info) {
+		swap_seg = NULL;
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	if (!atomic_read(&penv->fw_available)) {
+		pr_debug("%s: fw is not available\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	*swap_seg = *cnss_seg_info;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_codeswap_struct);
+
+static void cnss_wlan_memory_expansion(void)
+{
+	struct device *dev;
+	const struct firmware *fw_entry;
+	const char *filename;
+	u32 fw_entry_size, size_left, dma_size_left, length;
+	char *fw_temp;
+	char *fw_data;
+	char *dma_virt_addr;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	u32 total_length = 0;
+	struct pci_dev *pdev;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	filename = cnss_wlan_get_evicted_data_file();
+	pdev = penv->pdev;
+	dev = &pdev->dev;
+	cnss_seg_info = penv->cnss_seg_info;
+
+	if (!cnss_seg_info) {
+		pr_debug("cnss: cnss_seg_info is NULL\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (atomic_read(&penv->fw_available)) {
+		pr_debug("cnss: fw code already copied to host memory\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (request_firmware(&fw_entry, filename, dev) != 0) {
+		pr_debug("cnss: failed to get fw: %s\n", filename);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (!fw_entry || !fw_entry->data) {
+		pr_err("%s: INVALID FW entries\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto release_fw;
+	}
+
+	dma_virt_addr = (char *)penv->codeseg_cpuaddr[0];
+	fw_data = (u8 *)fw_entry->data;
+	fw_temp = fw_data;
+	fw_entry_size = fw_entry->size;
+	if (fw_entry_size > EVICT_BIN_MAX_SIZE)
+		fw_entry_size = EVICT_BIN_MAX_SIZE;
+	size_left = fw_entry_size;
+	dma_size_left = EVICT_BIN_MAX_SIZE;
+	while ((size_left && fw_temp) && (dma_size_left > 0)) {
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		length = *(int *)fw_temp;
+		if ((length > size_left || length <= 0) ||
+		    (dma_size_left <= 0 || length > dma_size_left)) {
+			pr_err("cnss: wrong length read:%d\n",
+			       length);
+			break;
+		}
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		memcpy(dma_virt_addr, fw_temp, length);
+		dma_size_left = dma_size_left - length;
+		size_left = size_left - length;
+		fw_temp = fw_temp + length;
+		dma_virt_addr = dma_virt_addr + length;
+		total_length += length;
+		pr_debug("cnss: bytes_left to copy: fw:%d; dma_page:%d\n",
+			 size_left, dma_size_left);
+	}
+	pr_debug("cnss: total_bytes copied: %d\n", total_length);
+	cnss_seg_info->codeseg_total_bytes = total_length;
+
+	atomic_set(&penv->fw_available, 1);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+release_fw:
+	release_firmware(fw_entry);
+end:
+	return;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_pci_get_wlan_mac_address(u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+
+end:
+	*num = 0;
+	return NULL;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+end:
+	*num = 0;
+	return NULL;
+}
+EXPORT_SYMBOL(cnss_get_wlan_mac_address);
+
+/**
+ * cnss_pcie_set_wlan_mac_address() - API to get two wlan mac address
+ * @in: Input buffer with wlan mac addresses
+ * @len: Size of the buffer passed
+ *
+ * API to store wlan mac address passed by the caller. The stored mac
+ * addresses are used by the wlan functional driver to program wlan HW.
+ *
+ * Return: kernel error code.
+ */
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	u32 no_of_mac_addr;
+	struct cnss_wlan_mac_addr *addr = NULL;
+	int iter = 0;
+	u8 *temp = NULL;
+
+	if (len == 0 || (len % ETH_ALEN) != 0) {
+		pr_err("%s: Invalid Length:%d\n", __func__, len);
+		return -EINVAL;
+	}
+
+	no_of_mac_addr = len / ETH_ALEN;
+
+	if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
+		pr_err("%s: Num of supported MAC  addresses are:%d given:%d\n",
+		       __func__, MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
+		return -EINVAL;
+	}
+
+	if (!penv) {
+		pr_err("%s: Invalid CNSS Platform Context\n", __func__);
+		return -ENOENT;
+	}
+
+	if (penv->is_wlan_mac_set) {
+		pr_info("%s: Already MAC address are configured\n", __func__);
+		return 0;
+	}
+
+	penv->is_wlan_mac_set = true;
+	addr = &penv->wlan_mac_addr;
+	addr->no_of_mac_addr_set = no_of_mac_addr;
+	temp = &addr->mac_addr[0][0];
+
+	for (; iter < no_of_mac_addr; ++iter, temp += ETH_ALEN, in +=
+	     ETH_ALEN) {
+		ether_addr_copy(temp, in);
+		pr_debug("%s MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+			 __func__, temp[0], temp[1], temp[2], temp[3], temp[4],
+			 temp[5]);
+	}
+	return 0;
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver)
+{
+	int ret = 0;
+	int probe_again = 0;
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return -ENODEV;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!penv->driver) {
+		penv->driver = driver;
+		wdrv = penv->driver;
+	} else {
+		pr_err("driver already registered\n");
+		return -EEXIST;
+	}
+
+again:
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("wlan vreg ON failed\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+
+	if (!pdev) {
+		pr_debug("%s: invalid pdev. register pci device\n", __func__);
+		ret = pci_register_driver(&cnss_wlan_pci_driver);
+
+		if (ret) {
+			pr_err("%s: pci registration failed\n", __func__);
+			goto err_pcie_reg;
+		}
+		pdev = penv->pdev;
+		if (!pdev) {
+			pr_err("%s: pdev is still invalid\n", __func__);
+			goto err_pcie_reg;
+		}
+	}
+
+	penv->event_reg.events = MSM_PCIE_EVENT_LINKDOWN |
+			MSM_PCIE_EVENT_WAKEUP;
+	penv->event_reg.user = pdev;
+	penv->event_reg.mode = MSM_PCIE_TRIGGER_CALLBACK;
+	penv->event_reg.callback = cnss_pci_events_cb;
+	penv->event_reg.options = MSM_PCIE_CONFIG_NO_RECOVERY;
+	ret = cnss_msm_pcie_register_event(&penv->event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	if (!penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("PCIe link bring-up failed\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+	} else if (!penv->pcie_link_state && penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("PCIe link bring-up failed (link down option)\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+
+		ret = cnss_msm_pcie_recover_config(pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (!cnss_wlan_is_codeswap_supported(penv->revision_id))
+		cnss_wlan_memory_expansion();
+
+	if (wdrv->probe) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->probe(pdev, penv->id);
+		if (ret) {
+			wcnss_prealloc_check_memory_leak();
+			wcnss_pre_alloc_reset();
+
+			if (probe_again > 3) {
+				pr_err("Failed to probe WLAN\n");
+				goto err_wlan_probe;
+			}
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+			cnss_msm_pcie_deregister_event(&penv->event_reg);
+			cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS);
+			penv->pcie_link_state = PCIE_LINK_DOWN;
+			cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+			cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+			msleep(POWER_ON_DELAY);
+			probe_again++;
+			goto again;
+		}
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return ret;
+
+err_wlan_probe:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+err_pcie_link_up:
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+	if (penv->pcie_link_state) {
+		cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+err_pcie_reg:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering PCI device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	penv->driver = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto cut_power;
+	}
+
+	if (wdrv->remove)
+		wdrv->remove(pdev);
+
+	wcnss_prealloc_check_memory_leak();
+	wcnss_pre_alloc_reset();
+
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+
+	if (penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS)) {
+			pr_err("Failed to shutdown PCIe link\n");
+			return;
+		}
+	} else if (penv->pcie_link_state && penv->pcie_link_down_ind) {
+		penv->saved_state = NULL;
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_err("Failed to shutdown PCIe link (with linkdown option)\n");
+			return;
+		}
+	}
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+	penv->driver_status = CNSS_UNINITIALIZED;
+	penv->monitor_wake_intr = false;
+	atomic_set(&penv->auto_suspended, 0);
+
+cut_power:
+	penv->driver = NULL;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("wlan vreg OFF failed\n");
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+#ifdef CONFIG_PCI_MSM
+int cnss_wlan_pm_control(bool vote)
+{
+	if (!penv || !penv->pdev)
+		return -ENODEV;
+
+	return cnss_msm_pcie_pm_control(
+		vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC,
+		cnss_get_pci_dev_bus_number(penv->pdev),
+		penv->pdev, PM_OPTIONS);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+#endif
+
+void cnss_lock_pm_sem(void)
+{
+	down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(void)
+{
+	up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+void cnss_pci_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+
+void cnss_pci_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+
+void *cnss_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	penv->recovery_in_progress = true;
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	if (!pdev) {
+		ret = -EINVAL;
+		goto cut_power;
+	}
+
+	if (wdrv && wdrv->shutdown)
+		wdrv->shutdown(pdev);
+
+	if (penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_debug("cnss: Failed to shutdown PCIe link\n");
+			ret = -EFAULT;
+		}
+		penv->saved_state = NULL;
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+cut_power:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("cnss: Failed to set WLAN VREG_OFF\n");
+
+	return ret;
+}
+
+static int cnss_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->driver)
+		goto out;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("cnss: Failed to set WLAN VREG_ON\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	/**
+	 *  Some platforms have wifi and other PCIE card attached with PCIE
+	 *  switch on the same RC like P5459 board(ROME 3.2 PCIE card + Ethernet
+	 *  PCI), it will need extra time to stable the signals when do SSR,
+	 *  otherwise fail to create the PCIE link, so add PCIE_SWITCH_DELAY.
+	 */
+	msleep(PCIE_SWITCH_DELAY);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto err_pcie_link_up;
+	}
+
+	if (!penv->pcie_link_state) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("cnss: Failed to bring-up PCIe link\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+		ret = cnss_msm_pcie_recover_config(penv->pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (wdrv && wdrv->reinit) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->reinit(pdev, penv->id);
+		if (ret) {
+			pr_err("%d: Failed to do reinit\n", __LINE__);
+			goto err_wlan_reinit;
+		}
+	} else {
+		pr_err("%d: wdrv->reinit is invalid\n", __LINE__);
+			goto err_pcie_link_up;
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+out:
+	penv->recovery_in_progress = false;
+	return ret;
+
+err_wlan_reinit:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+	cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+err_pcie_link_up:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering pci device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	return ret;
+}
+
+void cnss_pci_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+
+static int cnss_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct ramdump_segment segment;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = penv->ramdump_addr;
+	segment.size = penv->ramdump_size;
+
+	return do_ramdump(penv->ramdump_dev, &segment, 1);
+}
+
+static void cnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (pdev && wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(pdev);
+}
+
+void cnss_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+EXPORT_SYMBOL(cnss_device_self_recovery);
+
+static int cnss_modem_notifier_nb(struct notifier_block *this,
+				  unsigned long code,
+				  void *ss_handle)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	pr_debug("%s: Modem-Notify: event %lu\n", __func__, code);
+
+	if (!penv)
+		return NOTIFY_DONE;
+
+	if (code == SUBSYS_AFTER_POWERUP)
+		penv->modem_current_status = 1;
+	else if (code == SUBSYS_BEFORE_SHUTDOWN)
+		penv->modem_current_status = 0;
+	else
+		return NOTIFY_DONE;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (!wdrv || !pdev || !wdrv->modem_status)
+		return NOTIFY_DONE;
+
+	wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = cnss_modem_notifier_nb,
+};
+
+static int cnss_init_dump_entry(void)
+{
+	struct msm_dump_entry dump_entry;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_dynamic)
+		return 0;
+
+	penv->dump_data.addr = penv->ramdump_phys;
+	penv->dump_data.len = penv->ramdump_size;
+	penv->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(penv->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(penv->dump_data.name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&penv->dump_data);
+
+	return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct esoc_desc *desc;
+	const char *client_desc;
+	struct device *dev = &pdev->dev;
+	u32 rc_num;
+	struct resource *res;
+	u32 ramdump_size = 0;
+	u32 smmu_iova_address[2];
+
+	if (penv)
+		return -ENODEV;
+
+	penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL);
+	if (!penv)
+		return -ENOMEM;
+
+	penv->pldev = pdev;
+	penv->esoc_desc = NULL;
+
+	penv->gpio_info.name = WLAN_EN_GPIO_NAME;
+	penv->gpio_info.num = 0;
+	penv->gpio_info.state = WLAN_EN_LOW;
+	penv->gpio_info.init = WLAN_EN_LOW;
+	penv->gpio_info.prop = false;
+	penv->vreg_info.wlan_reg = NULL;
+	penv->vreg_info.state = VREG_OFF;
+	penv->pci_register_again = false;
+	mutex_init(&penv->fw_setup_stat_lock);
+
+	ret = cnss_wlan_get_resources(pdev);
+	if (ret)
+		goto err_get_wlan_res;
+
+	ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	if (ret) {
+		pr_err("%s: Failed to enable WLAN enable gpio\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+	if (ret) {
+		pr_err("%s: Failed to find PCIe RC number\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = cnss_msm_pcie_enumerate(rc_num);
+	if (ret) {
+		pr_err("%s: Failed to enable PCIe RC%x\n", __func__, rc_num);
+		goto err_pcie_enumerate;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	penv->notify_modem_status =
+		of_property_read_bool(dev->of_node,
+				      "qcom,notify-modem-status");
+
+	if (penv->notify_modem_status) {
+		ret = of_property_read_string_index(dev->of_node, "esoc-names",
+						    0, &client_desc);
+		if (ret) {
+			pr_debug("%s: esoc-names is not defined in DT, SKIP\n",
+				 __func__);
+		} else {
+			desc = devm_register_esoc_client(dev, client_desc);
+			if (IS_ERR_OR_NULL(desc)) {
+				ret = PTR_RET(desc);
+				pr_err("%s: can't find esoc desc\n", __func__);
+				goto err_esoc_reg;
+			}
+			penv->esoc_desc = desc;
+		}
+	}
+
+	penv->subsysdesc.name = "AR6320";
+	penv->subsysdesc.owner = THIS_MODULE;
+	penv->subsysdesc.shutdown = cnss_shutdown;
+	penv->subsysdesc.powerup = cnss_powerup;
+	penv->subsysdesc.ramdump = cnss_ramdump;
+	penv->subsysdesc.crash_shutdown = cnss_crash_shutdown;
+	penv->subsysdesc.dev = &pdev->dev;
+	penv->subsys = subsys_register(&penv->subsysdesc);
+	if (IS_ERR(penv->subsys)) {
+		ret = PTR_ERR(penv->subsys);
+		goto err_subsys_reg;
+	}
+
+	penv->subsys_handle = subsystem_get(penv->subsysdesc.name);
+
+	if (of_property_read_bool(dev->of_node, "qcom,is-dual-wifi-enabled"))
+		penv->dual_wifi_info.is_dual_wifi_enabled = true;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		penv->ramdump_addr = dma_alloc_coherent(&pdev->dev,
+				ramdump_size, &penv->ramdump_phys, GFP_KERNEL);
+
+		if (penv->ramdump_addr)
+			penv->ramdump_size = ramdump_size;
+		penv->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(penv->pldev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			penv->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			penv->ramdump_addr = ioremap(penv->ramdump_phys,
+					ramdump_size);
+
+			if (penv->ramdump_addr)
+				penv->ramdump_size = ramdump_size;
+
+			penv->ramdump_dynamic = false;
+		}
+	}
+
+	pr_debug("%s: ramdump addr: %p, phys: %pa\n", __func__,
+		 penv->ramdump_addr, &penv->ramdump_phys);
+
+	if (penv->ramdump_size == 0) {
+		pr_info("%s: CNSS ramdump will not be collected\n", __func__);
+		goto skip_ramdump;
+	}
+
+	ret = cnss_init_dump_entry();
+	if (ret) {
+		pr_err("%s: Dump table setup failed: %d\n", __func__, ret);
+		goto err_ramdump_create;
+	}
+
+	penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name,
+				penv->subsysdesc.dev);
+	if (!penv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump_create;
+	}
+
+skip_ramdump:
+	penv->modem_current_status = 0;
+
+	if (penv->notify_modem_status) {
+		penv->modem_notify_handler =
+			subsys_notif_register_notifier(penv->esoc_desc ?
+						       penv->esoc_desc->name :
+						       "modem", &mnb);
+		if (IS_ERR(penv->modem_notify_handler)) {
+			ret = PTR_ERR(penv->modem_notify_handler);
+			pr_err("%s: Register notifier Failed\n", __func__);
+			goto err_notif_modem;
+		}
+	}
+
+	if (of_property_read_u32_array(dev->of_node,
+				       "qcom,wlan-smmu-iova-address",
+				       smmu_iova_address, 2) == 0) {
+		penv->smmu_iova_start = smmu_iova_address[0];
+		penv->smmu_iova_len = smmu_iova_address[1];
+	}
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret)
+		goto err_pci_reg;
+
+	penv->bus_scale_table = 0;
+	penv->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+
+	if (penv->bus_scale_table)  {
+		penv->bus_client =
+			msm_bus_scale_register_client(penv->bus_scale_table);
+
+		if (!penv->bus_client) {
+			pr_err("Failed to register with bus_scale client\n");
+			goto err_bus_reg;
+		}
+	}
+	cnss_pm_wake_lock_init(&penv->ws, "cnss_wlock");
+
+	register_pm_notifier(&cnss_pm_notifier);
+
+#ifdef CONFIG_CNSS_MAC_BUG
+	/* 0-4K memory is reserved for QCA6174 to address a MAC HW bug.
+	 * MAC would do an invalid pointer fetch based on the data
+	 * that was read from 0 to 4K. So fill it with zero's (to an
+	 * address for which PCIe RC honored the read without any errors).
+	 */
+	memset(phys_to_virt(0), 0, SZ_4K);
+#endif
+
+	ret = device_create_file(dev, &dev_attr_fw_image_setup);
+	if (ret) {
+		pr_err("cnss: fw_image_setup sys file creation failed\n");
+		goto err_bus_reg;
+	}
+	pr_debug("cnss: Platform driver probed successfully.\n");
+	return ret;
+
+err_bus_reg:
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+	pci_unregister_driver(&cnss_wlan_pci_driver);
+
+err_pci_reg:
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier
+			(penv->modem_notify_handler, &mnb);
+
+err_notif_modem:
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+
+err_ramdump_create:
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	if (penv->subsys_handle)
+		subsystem_put(penv->subsys_handle);
+
+	subsys_unregister(penv->subsys);
+
+err_subsys_reg:
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+
+err_esoc_reg:
+err_pcie_enumerate:
+err_get_rc:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_release_resources();
+
+err_get_wlan_res:
+	penv = NULL;
+
+	return ret;
+}
+
+static int cnss_remove(struct platform_device *pdev)
+{
+	unregister_pm_notifier(&cnss_pm_notifier);
+	device_remove_file(&pdev->dev, &dev_attr_fw_image_setup);
+
+	cnss_pm_wake_lock_destroy(&penv->ws);
+
+	if (penv->bus_client)
+		msm_bus_scale_unregister_client(penv->bus_client);
+
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+	cnss_wlan_release_resources();
+
+	return 0;
+}
+
+static const struct of_device_id cnss_dt_match[] = {
+	{.compatible = "qcom,cnss"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cnss_dt_match);
+
+static struct platform_driver cnss_driver = {
+	.probe  = cnss_probe,
+	.remove = cnss_remove,
+	.driver = {
+		.name = "cnss",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_dt_match,
+#ifdef CONFIG_CNSS_ASYNC
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+	},
+};
+
+static int __init cnss_initialize(void)
+{
+	return platform_driver_register(&cnss_driver);
+}
+
+static void __exit cnss_exit(void)
+{
+	struct platform_device *pdev = penv->pldev;
+
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier(penv->modem_notify_handler,
+						 &mnb);
+	subsys_unregister(penv->subsys);
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+	platform_driver_unregister(&cnss_driver);
+}
+
+void cnss_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos_type);
+
+void cnss_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos_type);
+
+void cnss_pci_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos);
+
+void cnss_pci_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_pci_remove_pm_qos);
+
+int cnss_pci_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+int cnss_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct cnss_platform_cap *cap)
+{
+	if (!penv)
+		return -ENODEV;
+
+	if (cap)
+		*cap = penv->cap;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+void cnss_set_driver_status(enum cnss_driver_status driver_status)
+{
+	penv->driver_status = driver_status;
+}
+EXPORT_SYMBOL(cnss_set_driver_status);
+
+int cnss_get_bmi_setup(void)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return penv->bmi_test;
+}
+EXPORT_SYMBOL(cnss_get_bmi_setup);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out)
+{
+	struct scatterlist sg;
+	struct hash_desc desc;
+	int ret = 0;
+
+	if (!out) {
+		pr_err("memory for output buffer is not allocated\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	desc.tfm   = crypto_alloc_hash(hash_idx, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		pr_err("crypto_alloc_hash failed:%ld\n", PTR_ERR(desc.tfm));
+		ret = PTR_ERR(desc.tfm);
+		goto end;
+	}
+
+	sg_init_one(&sg, data, data_len);
+	ret = crypto_hash_digest(&desc, &sg, sg.length, out);
+	crypto_free_hash(desc.tfm);
+end:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_get_sha_hash);
+
+void *cnss_get_fw_ptr(void)
+{
+	if (!penv)
+		return NULL;
+
+	return penv->fw_mem;
+}
+EXPORT_SYMBOL(cnss_get_fw_ptr);
+#endif
+
+int cnss_auto_suspend(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+		pci_disable_device(pdev);
+		ret = pci_set_power_state(pdev, PCI_D3hot);
+		if (ret)
+			pr_err("%s: Set D3Hot failed: %d\n", __func__, ret);
+		if (cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to shutdown PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+	atomic_set(&penv->auto_suspended, 1);
+	penv->monitor_wake_intr = true;
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    CNSS_BUS_WIDTH_NONE);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+	if (!penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to resume PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+		ret = pci_enable_device(pdev);
+		if (ret)
+			pr_err("%s: enable device failed: %d\n", __func__, ret);
+		penv->pcie_link_state = PCIE_LINK_UP;
+	}
+
+	if (penv->saved_state)
+		cnss_pci_load_and_free_saved_state(pdev, &penv->saved_state);
+
+	pci_restore_state(pdev);
+	pci_set_master(pdev);
+
+	atomic_set(&penv->auto_suspended, 0);
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    penv->current_bandwidth_vote);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_runtime_request(struct device *dev,
+			    enum cnss_runtime_request request)
+{
+	int ret = 0;
+
+	switch (request) {
+	case CNSS_PM_RUNTIME_GET:
+		ret = pm_runtime_get(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT:
+		ret = pm_runtime_put(dev);
+		break;
+	case CNSS_PM_RUNTIME_MARK_LAST_BUSY:
+		pm_runtime_mark_last_busy(dev);
+		break;
+	case CNSS_PM_RUNTIME_RESUME:
+		ret = pm_runtime_resume(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_AUTO:
+		ret = pm_runtime_put_autosuspend(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_NOIDLE:
+		pm_runtime_put_noidle(dev);
+		break;
+	case CNSS_PM_REQUEST_RESUME:
+		ret = pm_request_resume(dev);
+		break;
+	case CNSS_PM_GET_NORESUME:
+		pm_runtime_get_noresume(dev);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_pm_runtime_request);
+
+void cnss_runtime_init(struct device *dev, int auto_delay)
+{
+	pm_runtime_set_autosuspend_delay(dev, auto_delay);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_allow(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_noidle(dev);
+	pm_suspend_ignore_children(dev, true);
+}
+EXPORT_SYMBOL(cnss_runtime_init);
+
+void cnss_runtime_exit(struct device *dev)
+{
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+}
+EXPORT_SYMBOL(cnss_runtime_exit);
+
+static void __cnss_set_pcie_monitor_intr(struct device *dev, bool val)
+{
+	penv->monitor_wake_intr = val;
+}
+
+static void __cnss_set_auto_suspend(struct device *dev, int val)
+{
+	atomic_set(&penv->auto_suspended, val);
+}
+
+static int __cnss_resume_link(struct device *dev, u32 flags)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_RESUME, bus_num, pdev, flags);
+	if (ret)
+		pr_err("%s: PCIe link resume failed with flags:%d bus_num:%d\n",
+		       __func__, flags, bus_num);
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	return ret;
+}
+
+static int __cnss_suspend_link(struct device *dev, u32 flags)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+	int ret;
+
+	if (!penv->pcie_link_state)
+		return 0;
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus_num, pdev, flags);
+	if (ret) {
+		pr_err("%s: Failed to suspend link\n", __func__);
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return ret;
+}
+
+static int __cnss_pcie_recover_config(struct device *dev)
+{
+	int ret;
+
+	ret = cnss_msm_pcie_recover_config(to_pci_dev(dev));
+	if (ret)
+		pr_err("%s: PCIe Recover config failed\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_event_reg(struct device *dev)
+{
+	int ret;
+	struct msm_pcie_register_event *event_reg;
+
+	event_reg = &penv->event_reg;
+
+	event_reg->events = MSM_PCIE_EVENT_LINKDOWN |
+		MSM_PCIE_EVENT_WAKEUP;
+	event_reg->user = to_pci_dev(dev);
+	event_reg->mode = MSM_PCIE_TRIGGER_CALLBACK;
+	event_reg->callback = cnss_pci_events_cb;
+	event_reg->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+	ret = cnss_msm_pcie_register_event(event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	return ret;
+}
+
+static void __cnss_event_dereg(struct device *dev)
+{
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+}
+
+static struct pci_dev *__cnss_get_pcie_dev(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = penv->pdev;
+
+	if (pdev)
+		return pdev;
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret) {
+		pr_err("%s: pci re-registration failed\n", __func__);
+		return NULL;
+	}
+
+	pdev = penv->pdev;
+
+	return pdev;
+}
+
+static int __cnss_pcie_power_up(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("%s: WLAN VREG ON Failed\n", __func__);
+		return ret;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	return 0;
+}
+
+static int __cnss_pcie_power_down(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (ret)
+		pr_err("%s: Failed to turn off 3.3V regulator\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_suspend_link_state(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int link_ind;
+
+	if (!penv->pcie_link_state) {
+		pr_debug("%s: Link is already suspended\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	if (!link_ind)
+		pci_save_state(pdev);
+
+	penv->saved_state = link_ind ? NULL : cnss_pci_store_saved_state(pdev);
+
+	ret = link_ind ? __cnss_suspend_link(dev, PM_OPTIONS_SUSPEND_LINK_DOWN)
+		: __cnss_suspend_link(dev, PM_OPTIONS);
+	if (ret) {
+		pr_err("%s: Link Suspend failed in state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return 0;
+}
+
+static int __cnss_restore_pci_config_space(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int ret = 0;
+
+	if (penv->saved_state)
+		ret = cnss_pci_load_and_free_saved_state(pdev,
+							 &penv->saved_state);
+	pci_restore_state(pdev);
+
+	return ret;
+}
+
+static int __cnss_resume_link_state(struct device *dev)
+{
+	int ret;
+	int link_ind;
+
+	if (penv->pcie_link_state) {
+		pr_debug("%s: Link is already in active state\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	ret = link_ind ? __cnss_resume_link(dev, PM_OPTIONS_RESUME_LINK_DOWN) :
+		__cnss_resume_link(dev, PM_OPTIONS);
+
+	if (ret) {
+		pr_err("%s: Resume Link failed in link state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	ret = link_ind ?  __cnss_pcie_recover_config(dev) :
+		__cnss_restore_pci_config_space(dev);
+
+	if (ret) {
+		pr_err("%s: Link Recovery Config Failed link_state:%s\n",
+		       __func__, link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+		return ret;
+	}
+
+	penv->pcie_link_down_ind  = false;
+	return ret;
+}
+
+int cnss_pcie_power_up(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev;
+
+	if (!penv) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = __cnss_pcie_power_up(dev);
+	if (ret) {
+		pr_err("%s: Power UP Failed\n", __func__);
+		return ret;
+	}
+
+	pdev = __cnss_get_pcie_dev(dev);
+	if (!pdev) {
+		pr_err("%s: PCIe Dev is NULL\n", __func__);
+		goto power_down;
+	}
+
+	ret = __cnss_event_reg(dev);
+
+	if (ret)
+		pr_err("%s: PCIe event registration failed\n", __func__);
+
+	ret = __cnss_resume_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Link Bring Up Failed\n", __func__);
+		goto event_dereg;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, true);
+
+	return ret;
+
+event_dereg:
+	__cnss_event_dereg(dev);
+power_down:
+	__cnss_pcie_power_down(dev);
+	pr_err("%s: Device Power Up Failed Fatal Error\n", __func__);
+	return ret;
+}
+
+static void __cnss_vote_bus_width(struct device *dev, u32 option)
+{
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client, option);
+}
+
+int cnss_pcie_power_down(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform data\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!pdev) {
+		pr_err("%s: Invalid Pdev, Cut Power to device\n", __func__);
+		__cnss_pcie_power_down(dev);
+		return -ENODEV;
+	}
+
+	__cnss_vote_bus_width(dev, CNSS_BUS_WIDTH_NONE);
+	__cnss_event_dereg(dev);
+
+	ret = __cnss_suspend_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Suspend Link failed\n", __func__);
+		return ret;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, false);
+	__cnss_set_auto_suspend(dev, 0);
+
+	ret = __cnss_pcie_power_down(dev);
+	if (ret)
+		pr_err("%s: Power Down Failed\n", __func__);
+
+	return ret;
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS Driver");
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
new file mode 100644
index 0000000..c35ba38
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -0,0 +1,1564 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "cnss_sdio:%s:%d:: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <linux/pm_qos.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_DSRC_NAME	"vdd-wlan-dsrc"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_GPIO_CAPTSF_NAME	"qcom,cap-tsf-gpio"
+
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define POWER_ON_DELAY		4
+
+/* Values for Dynamic Ramdump Collection*/
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN_SDIO"
+#define CNSS_PINCTRL_SLEEP_STATE	"sleep"
+#define CNSS_PINCTRL_ACTIVE_STATE	"active"
+
+#define CNSS_HW_SLEEP 0
+#define CNSS_HW_ACTIVE 1
+
+struct cnss_sdio_regulator {
+	struct regulator *wlan_io;
+	struct regulator *wlan_xtal;
+	struct regulator *wlan_vreg;
+	struct regulator *wlan_vreg_dsrc;
+};
+
+struct cnss_sdio_info {
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct sdio_func *func;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	struct device *dev;
+	const struct sdio_device_id *id;
+	bool skip_wlan_en_toggle;
+	bool cnss_hw_state;
+	struct cnss_cap_tsf_info cap_tsf_info;
+};
+
+struct cnss_ssr_info {
+	struct subsys_device *subsys;
+	struct subsys_desc subsysdesc;
+	void *subsys_handle;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	bool ramdump_dynamic;
+	char subsys_name[10];
+};
+
+struct cnss_wlan_pinctrl_info {
+	bool is_antenna_shared;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *sleep;
+	struct pinctrl_state *active;
+};
+
+struct cnss_sdio_bus_bandwidth {
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+};
+
+static struct cnss_sdio_data {
+	struct cnss_sdio_regulator regulator;
+	struct platform_device *pdev;
+	struct cnss_sdio_info cnss_sdio_info;
+	struct cnss_ssr_info ssr_info;
+	struct pm_qos_request qos_request;
+	struct cnss_wlan_pinctrl_info pinctrl_info;
+	struct cnss_sdio_bus_bandwidth bus_bandwidth;
+	struct cnss_dev_platform_ops platform_ops;
+} *cnss_pdata;
+
+#define WLAN_RECOVERY_DELAY 1
+/* cnss sdio subsytem device name, required property */
+#define CNSS_SUBSYS_NAME_KEY "subsys-name"
+
+/* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_AR6320_BASE        0x500
+#define MANUFACTURER_ID_QCA9377_BASE       0x700
+#define MANUFACTURER_CODE                  0x271
+
+static const struct sdio_device_id ar6k_id_table[] = {
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))},
+	{},
+};
+MODULE_DEVICE_TABLE(sdio, ar6k_id_table);
+
+void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(&cnss_pdata->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos_type);
+
+int cnss_sdio_request_bus_bandwidth(int bandwidth)
+{
+	int ret;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (!bus_bandwidth->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, bandwidth);
+		if (!ret) {
+			bus_bandwidth->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_debug(
+			"could not set bus bandwidth %d, ret = %d\n",
+			 bandwidth, ret);
+		}
+		break;
+	default:
+		pr_debug("Invalid request %d\n", bandwidth);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void cnss_sdio_request_pm_qos(u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(
+		&cnss_pdata->qos_request,
+		PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos);
+
+void cnss_sdio_remove_pm_qos(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	pm_qos_remove_request(&cnss_pdata->qos_request);
+	pr_debug("PM QoS removed\n");
+}
+EXPORT_SYMBOL(cnss_sdio_remove_pm_qos);
+
+static int cnss_put_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct cnss_sdio_info *info;
+	struct mmc_host *host;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_SLEEP) {
+		pr_debug("HW resources are already released\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC host is invalid\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = mmc_power_save_host(host);
+	if (ret) {
+		pr_err("Failed to Power Save Host err:%d\n",
+		       ret);
+		return ret;
+	}
+
+	regulator_disable(cnss_pdata->regulator.wlan_vreg);
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+
+	return ret;
+}
+
+static int cnss_get_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct mmc_host *host;
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_ACTIVE) {
+		pr_debug("HW resources are already active\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC Host is Invalid; Enumeration Failed\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+	if (ret) {
+		pr_err("Failed to enable wlan vreg\n");
+		return ret;
+	}
+
+	ret = mmc_power_restore_host(host);
+	if (ret) {
+		pr_err("Failed to restore host power ret:%d\n",
+		       ret);
+		regulator_disable(cnss_pdata->regulator.wlan_vreg);
+		return ret;
+	}
+
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+	return ret;
+}
+
+static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (!wdrv)
+		return 0;
+	if (!wdrv->shutdown)
+		return 0;
+
+	wdrv->shutdown(cnss_info->func);
+	ret = cnss_put_hw_resources(cnss_info->dev);
+
+	if (ret)
+		pr_err("Failed to put hw resources\n");
+
+	return ret;
+}
+
+static int cnss_sdio_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+
+	if (!wdrv)
+		return 0;
+
+	if (!wdrv->reinit)
+		return 0;
+
+	ret = cnss_get_hw_resources(cnss_info->dev);
+	if (ret) {
+		pr_err("Failed to power up HW\n");
+		return ret;
+	}
+
+	ret = wdrv->reinit(cnss_info->func, cnss_info->id);
+	if (ret)
+		pr_err("wlan reinit error=%d\n", ret);
+
+	return ret;
+}
+
+static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+
+	if (!cnss_pdata)
+		return;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(cnss_info->func);
+}
+
+static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct ramdump_segment segment;
+	int ret;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	if (!cnss_pdata->ssr_info.ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = ssr_info->ramdump_addr;
+	segment.size = ssr_info->ramdump_size;
+	ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1);
+	if (ret)
+		pr_err("do_ramdump failed error=%d\n", ret);
+	return ret;
+}
+
+static int cnss_subsys_init(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	ssr_info->subsysdesc.name = ssr_info->subsys_name;
+	ssr_info->subsysdesc.owner = THIS_MODULE;
+	ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown;
+	ssr_info->subsysdesc.powerup = cnss_sdio_powerup;
+	ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump;
+	ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown;
+	ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev;
+	ssr_info->subsys = subsys_register(&ssr_info->subsysdesc);
+	if (IS_ERR(ssr_info->subsys)) {
+		ret = PTR_ERR(ssr_info->subsys);
+		ssr_info->subsys = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n",
+			ret);
+		goto err_subsys_reg;
+	}
+	ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name);
+	if (IS_ERR(ssr_info->subsys_handle)) {
+		ret = PTR_ERR(ssr_info->subsys_handle);
+		ssr_info->subsys_handle = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n",
+			ret);
+		goto err_subsys_get;
+	}
+	return 0;
+err_subsys_get:
+	subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+err_subsys_reg:
+	return ret;
+}
+
+static void cnss_subsys_exit(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys_handle)
+		subsystem_put(ssr_info->subsys_handle);
+	ssr_info->subsys_handle = NULL;
+	if (ssr_info->subsys)
+		subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+}
+
+static int cnss_configure_dump_table(struct cnss_ssr_info *ssr_info)
+{
+	struct msm_dump_entry dump_entry;
+	int ret;
+
+	ssr_info->dump_data.addr = ssr_info->ramdump_phys;
+	ssr_info->dump_data.len = ssr_info->ramdump_size;
+	ssr_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	ssr_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(ssr_info->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(ssr_info->dump_data.name));
+
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&ssr_info->dump_data);
+
+	ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+	if (ret)
+		pr_err("Dump table setup failed: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_configure_ramdump(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+	struct resource *res;
+	const char *name;
+	u32 ramdump_size = 0;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	dev = &cnss_pdata->pdev->dev;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	ret = of_property_read_string(dev->of_node, CNSS_SUBSYS_NAME_KEY,
+				      &name);
+	if (ret) {
+		pr_err("cnss missing DT key '%s'\n",
+		       CNSS_SUBSYS_NAME_KEY);
+		ret = -ENODEV;
+		goto err_subsys_name_query;
+	}
+
+	strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name));
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		ssr_info->ramdump_addr = dma_alloc_coherent(dev, ramdump_size,
+							&ssr_info->ramdump_phys,
+							GFP_KERNEL);
+		if (ssr_info->ramdump_addr)
+			ssr_info->ramdump_size = ramdump_size;
+		ssr_info->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(cnss_pdata->pdev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			ssr_info->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys,
+								ramdump_size);
+			if (ssr_info->ramdump_addr)
+				ssr_info->ramdump_size = ramdump_size;
+			ssr_info->ramdump_dynamic = false;
+		}
+	}
+
+	pr_info("ramdump addr: %p, phys: %pa subsys:'%s'\n",
+		ssr_info->ramdump_addr, &ssr_info->ramdump_phys,
+		ssr_info->subsys_name);
+
+	if (ssr_info->ramdump_size == 0) {
+		pr_info("CNSS ramdump will not be collected\n");
+		return 0;
+	}
+
+	if (ssr_info->ramdump_dynamic) {
+		ret = cnss_configure_dump_table(ssr_info);
+		if (ret)
+			goto err_configure_dump_table;
+	}
+
+	ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name,
+									dev);
+	if (!ssr_info->ramdump_dev) {
+		ret = -ENOMEM;
+		pr_err("ramdump dev create failed: error=%d\n",
+		       ret);
+		goto err_configure_dump_table;
+	}
+
+	return 0;
+
+err_configure_dump_table:
+	if (ssr_info->ramdump_dynamic)
+		dma_free_coherent(dev, ssr_info->ramdump_size,
+				  ssr_info->ramdump_addr,
+				  ssr_info->ramdump_phys);
+	else
+		iounmap(ssr_info->ramdump_addr);
+
+	ssr_info->ramdump_addr = NULL;
+	ssr_info->ramdump_size = 0;
+err_subsys_name_query:
+	return ret;
+}
+
+static void cnss_ramdump_cleanup(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return;
+
+	dev = &cnss_pdata->pdev->dev;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->ramdump_addr) {
+		if (ssr_info->ramdump_dynamic)
+			dma_free_coherent(dev, ssr_info->ramdump_size,
+					  ssr_info->ramdump_addr,
+					  ssr_info->ramdump_phys);
+		else
+			iounmap(ssr_info->ramdump_addr);
+	}
+
+	ssr_info->ramdump_addr = NULL;
+	if (ssr_info->ramdump_dev)
+		destroy_ramdump_device(ssr_info->ramdump_dev);
+	ssr_info->ramdump_dev = NULL;
+}
+
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!cnss_pdata || !cnss_pdata->pdev)
+		return NULL;
+
+	*size = cnss_pdata->ssr_info.ramdump_size;
+
+	return cnss_pdata->ssr_info.ramdump_addr;
+}
+
+void cnss_sdio_device_self_recovery(void)
+{
+	cnss_sdio_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_sdio_powerup(NULL);
+}
+
+void cnss_sdio_device_crashed(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys) {
+		subsys_set_crash_status(ssr_info->subsys, true);
+		subsystem_restart_dev(ssr_info->subsys);
+	}
+}
+
+static void cnss_sdio_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_sdio_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_sdio_recovery_work, cnss_sdio_recovery_work_handler);
+
+void cnss_sdio_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_sdio_recovery_work);
+}
+
+/**
+ * cnss_get_restart_level() - cnss get restart level API
+ *
+ * Wlan sdio function driver uses this API to get the current
+ * subsystem restart level.
+ *
+ * Return: CNSS_RESET_SOC - "SYSTEM", restart system
+ *         CNSS_RESET_SUBSYS_COUPLED - "RELATED",restart subsystem
+ */
+int cnss_get_restart_level(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int level;
+
+	if (!cnss_pdata)
+		return CNSS_RESET_SOC;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (!ssr_info->subsys)
+		return CNSS_RESET_SOC;
+	level = subsys_get_restart_level(ssr_info->subsys);
+	switch (level) {
+	case RESET_SOC:
+		return CNSS_RESET_SOC;
+	case RESET_SUBSYS_COUPLED:
+		return CNSS_RESET_SUBSYS_COUPLED;
+	default:
+		return CNSS_RESET_SOC;
+	}
+}
+EXPORT_SYMBOL(cnss_get_restart_level);
+
+static inline int cnss_get_tsf_cap_irq(struct device *dev)
+{
+	int irq = -EINVAL;
+	int gpio;
+
+	if (!dev)
+		return -ENODEV;
+
+	gpio = of_get_named_gpio(dev->of_node, WLAN_GPIO_CAPTSF_NAME, 0);
+	if (gpio >= 0)
+		irq = gpio_to_irq(gpio);
+
+	return irq;
+}
+
+static int cnss_sdio_register_tsf_captured_handler(irq_handler_t handler,
+						   void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	tsf_info->irq_handler = handler;
+	tsf_info->context = ctx;
+	return 0;
+}
+
+static int cnss_sdio_unregister_tsf_captured_handler(void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	if (ctx == tsf_info->context) {
+		tsf_info->irq_handler = NULL;
+		tsf_info->context = NULL;
+	}
+	return 0;
+}
+
+static irqreturn_t cnss_sdio_tsf_captured_handler(int irq, void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return IRQ_HANDLED;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0 || tsf_info->irq_num != irq ||
+	    !tsf_info->irq_handler || !tsf_info->context)
+		return IRQ_HANDLED;
+
+	return tsf_info->irq_handler(irq, tsf_info->context);
+}
+
+static void cnss_sdio_tsf_init(struct device *dev,
+			       struct cnss_cap_tsf_info *tsf_info)
+{
+	int ret, irq;
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+
+	irq = cnss_get_tsf_cap_irq(dev);
+	if (irq < 0) {
+		dev_err(dev, "%s: fail to get irq: %d\n", __func__, irq);
+		return;
+	}
+
+	ret = request_irq(irq, cnss_sdio_tsf_captured_handler,
+			  IRQF_SHARED | IRQF_TRIGGER_RISING, dev_name(dev),
+			  (void *)tsf_info);
+	dev_err(dev, "%s: request irq[%d] for dev: %s, result: %d\n",
+		__func__, irq, dev_name(dev), ret);
+	if (!ret)
+		tsf_info->irq_num = irq;
+}
+
+static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info)
+{
+	int irq = tsf_info->irq_num;
+
+	if (irq < 0)
+		return;
+
+	free_irq(irq, (void *)tsf_info);
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+}
+
+static void cnss_sdio_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+
+	pf_ops->power_up = cnss_sdio_power_up;
+	pf_ops->power_down = cnss_sdio_power_down;
+	pf_ops->device_crashed = cnss_sdio_device_crashed;
+	pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_sdio_device_self_recovery;
+	pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address;
+	pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work;
+	pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth;
+	pf_ops->register_tsf_captured_handler =
+		cnss_sdio_register_tsf_captured_handler;
+	pf_ops->unregister_tsf_captured_handler =
+		cnss_sdio_unregister_tsf_captured_handler;
+	dev->platform_data = pf_ops;
+}
+
+static int cnss_sdio_wlan_inserted(struct sdio_func *func,
+				   const struct sdio_device_id *id)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->func = func;
+	info->card = func->card;
+	info->host = func->card->host;
+	info->id = id;
+	info->dev = &func->dev;
+	cnss_sdio_set_platform_ops(info->dev);
+
+	cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev);
+
+	pr_info("SDIO Device is Probed\n");
+	return 0;
+}
+
+static void cnss_sdio_wlan_removed(struct sdio_func *func)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->host = NULL;
+	info->card = NULL;
+	info->func = NULL;
+	info->id = NULL;
+}
+
+#if defined(CONFIG_PM)
+static int cnss_sdio_wlan_suspend(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct sdio_func *func;
+
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	func = cnss_pdata->cnss_sdio_info.func;
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->suspend) {
+		error = wdrv->suspend(dev);
+		if (error)
+			pr_err("wlan suspend failed error=%d\n", error);
+	}
+
+	return error;
+}
+
+static int cnss_sdio_wlan_resume(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client,
+			bus_bandwidth->current_bandwidth_vote);
+	}
+
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->resume) {
+		error = wdrv->resume(dev);
+		if (error)
+			pr_err("wlan resume failed error=%d\n", error);
+	}
+	return error;
+}
+#endif
+
+#if defined(CONFIG_PM)
+static const struct dev_pm_ops cnss_ar6k_device_pm_ops = {
+	.suspend = cnss_sdio_wlan_suspend,
+	.resume = cnss_sdio_wlan_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct sdio_driver cnss_ar6k_driver = {
+	.name = "cnss_ar6k_wlan",
+	.id_table = ar6k_id_table,
+	.probe = cnss_sdio_wlan_inserted,
+	.remove = cnss_sdio_wlan_removed,
+#if defined(CONFIG_PM)
+	.drv = {
+		.pm = &cnss_ar6k_device_pm_ops,
+	}
+#endif
+};
+
+static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state)
+{
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!info->is_antenna_shared)
+		return 0;
+
+	if (!info->pinctrl)
+		return -EIO;
+
+	return state ? pinctrl_select_state(info->pinctrl, info->active) :
+		pinctrl_select_state(info->pinctrl, info->sleep);
+}
+
+int cnss_sdio_configure_spdt(bool state)
+{
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	return cnss_set_pinctrl_state(cnss_pdata, state);
+}
+EXPORT_SYMBOL(cnss_sdio_configure_spdt);
+
+/**
+ * cnss_sdio_wlan_register_driver() - cnss wlan register API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to register callback
+ * functions to cnss_sido platform driver. The callback will
+ * be invoked by corresponding wrapper function of this cnss
+ * platform driver.
+ */
+int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct device *dev;
+	int error = -EINVAL;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	dev = cnss_info->dev;
+
+	if (cnss_info->wdrv) {
+		pr_debug("wdrv already existed\n");
+		return error;
+	}
+
+	if (!driver)
+		return error;
+
+	error = cnss_get_hw_resources(dev);
+	if (error) {
+		pr_err("Failed to restore power err:%d\n", error);
+		return error;
+	}
+
+	error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE);
+	if (error) {
+		pr_err("Fail to set pinctrl to active state\n");
+		cnss_put_hw_resources(dev);
+		goto put_hw;
+	}
+
+	/* The HW resources are released in unregister logic if probe fails */
+	error = driver->probe ? driver->probe(cnss_info->func,
+					      cnss_info->id) : error;
+	if (error) {
+		pr_err("wlan probe failed error=%d\n", error);
+		/**
+		 * Check memory leak in skb pre-alloc memory pool
+		 * Reset the skb memory pool
+		 */
+		goto pinctrl_sleep;
+	}
+
+	cnss_info->wdrv = driver;
+
+	return error;
+
+pinctrl_sleep:
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+put_hw:
+	return error;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);
+
+/**
+ * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to detach it from cnss_sido
+ * platform driver.
+ */
+void
+cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	if (!cnss_info->wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (!driver)
+		return;
+
+	if (!driver->remove)
+		return;
+
+	driver->remove(cnss_info->func);
+
+	cnss_info->wdrv = NULL;
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+	cnss_put_hw_resources(cnss_info->dev);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);
+
+/**
+ * cnss_wlan_query_oob_status() - cnss wlan query oob status API
+ *
+ * Wlan sdio function driver uses this API to check whether oob is
+ * supported in platform driver.
+ *
+ * Return: 0 means oob is supported, others means unsupported.
+ */
+int cnss_wlan_query_oob_status(void)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_query_oob_status);
+
+/**
+ * cnss_wlan_register_oob_irq_handler() - cnss wlan register oob callback API
+ * @handler: oob callback function pointer which registered to platform driver.
+ * @pm_oob : parameter which registered to platform driver.
+ *
+ * Wlan sdio function driver uses this API to register oob callback
+ * function to platform driver.
+ *
+ * Return: 0 means register successfully, others means failure.
+ */
+int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_register_oob_irq_handler);
+
+/**
+ * cnss_wlan_unregister_oob_irq_handler() - unregister oob callback API
+ * @pm_oob: parameter which unregistered from platform driver.
+ *
+ * Wlan sdio function driver uses this API to unregister oob callback
+ * function from platform driver.
+ *
+ * Return: 0 means unregister successfully, others means failure.
+ */
+int cnss_wlan_unregister_oob_irq_handler(void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler);
+
+static void cnss_sdio_reset_platform_ops(void)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+	struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	if (sdio_info->dev)
+		sdio_info->dev->platform_data = NULL;
+}
+
+static int cnss_sdio_wlan_init(void)
+{
+	int error = 0;
+
+	error = sdio_register_driver(&cnss_ar6k_driver);
+	if (error) {
+		cnss_sdio_reset_platform_ops();
+		pr_err("registered fail error=%d\n", error);
+	} else {
+		pr_debug("registered success\n");
+	}
+
+	return error;
+}
+
+static void cnss_sdio_wlan_exit(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	cnss_sdio_reset_platform_ops();
+	sdio_unregister_driver(&cnss_ar6k_driver);
+}
+
+static void cnss_sdio_deinit_bus_bandwidth(void)
+{
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(bus_bandwidth->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+		msm_bus_scale_unregister_client(bus_bandwidth->bus_client);
+	}
+}
+
+static int cnss_sdio_configure_wlan_enable_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg);
+			dev_err(dev, "VDD-VREG get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+		if (error) {
+			dev_err(dev, "VDD-VREG enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg);
+
+	return error;
+}
+
+static int cnss_sdio_configure_wlan_enable_dsrc_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg_dsrc = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_DSRC_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg_dsrc)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg_dsrc);
+			dev_err(dev, "VDD-VREG-DSRC get failed error=%d\n",
+				error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg_dsrc);
+		if (error) {
+			dev_err(dev, "VDD-VREG-DSRC enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_dsrc_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_dsrc_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+
+	return error;
+}
+
+static int cnss_sdio_configure_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_IO_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_io = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_IO_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_io)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_io);
+			dev_err(dev, "VDD-IO get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_io,
+			WLAN_VREG_IO_MIN, WLAN_VREG_IO_MAX);
+		if (error) {
+			dev_err(dev, "VDD-IO set failed error=%d\n", error);
+			goto err_vdd_io_regulator;
+		} else {
+			error = regulator_enable(cnss_pdata->regulator.wlan_io);
+			if (error) {
+				dev_err(dev, "VDD-IO enable failed error=%d\n",
+					error);
+				goto err_vdd_io_regulator;
+			}
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_XTAL_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_xtal = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_XTAL_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_xtal)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_xtal);
+			dev_err(dev, "VDD-XTAL get failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_xtal,
+			WLAN_VREG_XTAL_MIN, WLAN_VREG_XTAL_MAX);
+		if (error) {
+			dev_err(dev, "VDD-XTAL set failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		} else {
+			error = regulator_enable(
+				cnss_pdata->regulator.wlan_xtal);
+			if (error) {
+				dev_err(dev, "VDD-XTAL enable failed err=%d\n",
+					error);
+				goto err_vdd_xtal_regulator;
+			}
+		}
+	}
+
+	return 0;
+
+err_vdd_xtal_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+err_vdd_io_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	return error;
+}
+
+static void cnss_sdio_release_resource(void)
+{
+	if (cnss_pdata->regulator.wlan_xtal)
+		regulator_put(cnss_pdata->regulator.wlan_xtal);
+	if (cnss_pdata->regulator.wlan_vreg)
+		regulator_put(cnss_pdata->regulator.wlan_vreg);
+	if (cnss_pdata->regulator.wlan_io)
+		regulator_put(cnss_pdata->regulator.wlan_io);
+	if (cnss_pdata->regulator.wlan_vreg_dsrc)
+		regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+}
+
+static int cnss_sdio_pinctrl_init(struct cnss_sdio_data *pdata,
+				  struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!of_find_property(dev->of_node, "qcom,is-antenna-shared", NULL))
+		return 0;
+
+	info->is_antenna_shared = true;
+	info->pinctrl = devm_pinctrl_get(dev);
+	if ((IS_ERR_OR_NULL(info->pinctrl))) {
+		dev_err(dev, "%s: Failed to get pinctrl\n", __func__);
+		return PTR_ERR(info->pinctrl);
+	}
+
+	info->sleep = pinctrl_lookup_state(info->pinctrl,
+						   CNSS_PINCTRL_SLEEP_STATE);
+	if (IS_ERR_OR_NULL(info->sleep)) {
+		dev_err(dev, "%s: Fail to get sleep state for pin\n", __func__);
+		ret = PTR_ERR(info->sleep);
+		goto release_pinctrl;
+	}
+
+	info->active = pinctrl_lookup_state(info->pinctrl,
+					    CNSS_PINCTRL_ACTIVE_STATE);
+	if (IS_ERR_OR_NULL(info->active)) {
+		dev_err(dev, "%s: Fail to get active state for pin\n",
+			__func__);
+		ret = PTR_ERR(info->active);
+		goto release_pinctrl;
+	}
+
+	ret = cnss_set_pinctrl_state(pdata, PINCTRL_SLEEP);
+
+	if (ret) {
+		dev_err(dev, "%s: Fail to set pin in sleep state\n", __func__);
+		goto release_pinctrl;
+	}
+
+	return ret;
+
+release_pinctrl:
+	devm_pinctrl_put(info->pinctrl);
+	info->is_antenna_shared = false;
+	return ret;
+}
+
+static int cnss_sdio_init_bus_bandwidth(void)
+{
+	int ret = 0;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	bus_bandwidth->bus_scale_table = msm_bus_cl_get_pdata(cnss_pdata->pdev);
+	if (!bus_bandwidth->bus_scale_table) {
+		dev_err(dev, "Failed to get the bus scale platform data\n");
+		ret = -EINVAL;
+	}
+
+	bus_bandwidth->bus_client = msm_bus_scale_register_client(
+			bus_bandwidth->bus_scale_table);
+	if (!bus_bandwidth->bus_client) {
+		dev_err(dev, "Failed to register with bus_scale client\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cnss_sdio_probe(struct platform_device *pdev)
+{
+	int error;
+	struct device *dev = &pdev->dev;
+	struct cnss_sdio_info *info;
+
+	if (pdev->dev.of_node) {
+		cnss_pdata = devm_kzalloc(
+			&pdev->dev, sizeof(*cnss_pdata), GFP_KERNEL);
+		if (!cnss_pdata)
+			return -ENOMEM;
+	} else {
+		cnss_pdata = pdev->dev.platform_data;
+	}
+
+	if (!cnss_pdata)
+		return -EINVAL;
+
+	cnss_pdata->pdev = pdev;
+	info = &cnss_pdata->cnss_sdio_info;
+
+	error = cnss_sdio_pinctrl_init(cnss_pdata, pdev);
+	if (error) {
+		dev_err(&pdev->dev, "Fail to configure pinctrl err:%d\n",
+			error);
+		return error;
+	}
+
+	error = cnss_sdio_configure_regulator();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n",
+			error);
+		return error;
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan enable regulator error=%d\n",
+				error);
+			goto err_wlan_enable_regulator;
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_dsrc_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan dsrc enable regulator\n");
+			goto err_wlan_dsrc_enable_regulator;
+		}
+	}
+
+	info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node,
+							  "qcom,skip-wlan-en-toggle");
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+
+	cnss_sdio_tsf_init(dev, &info->cap_tsf_info);
+
+	error = cnss_sdio_wlan_init();
+	if (error) {
+		dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error);
+		goto err_wlan_dsrc_enable_regulator;
+	}
+
+	error = cnss_configure_ramdump();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n",
+			error);
+		goto err_ramdump_create;
+	}
+
+	error = cnss_subsys_init();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n",
+			error);
+		goto err_subsys_init;
+	}
+
+	if (of_property_read_bool(
+		pdev->dev.of_node, "qcom,cnss-enable-bus-bandwidth")) {
+		error = cnss_sdio_init_bus_bandwidth();
+		if (error) {
+			dev_err(&pdev->dev, "Failed to init bus bandwidth\n");
+			goto err_bus_bandwidth_init;
+		}
+	}
+
+	dev_info(&pdev->dev, "CNSS SDIO Driver registered");
+	return 0;
+
+err_bus_bandwidth_init:
+	cnss_subsys_exit();
+err_subsys_init:
+	cnss_ramdump_cleanup();
+err_ramdump_create:
+	cnss_sdio_wlan_exit();
+err_wlan_dsrc_enable_regulator:
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+err_wlan_enable_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	cnss_pdata = NULL;
+	return error;
+}
+
+static int cnss_sdio_remove(struct platform_device *pdev)
+{
+	struct cnss_sdio_info *info;
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+	tsf_info = &info->cap_tsf_info;
+
+	cnss_sdio_tsf_deinit(tsf_info);
+	cnss_sdio_deinit_bus_bandwidth();
+	cnss_sdio_wlan_exit();
+	cnss_subsys_exit();
+	cnss_ramdump_cleanup();
+	cnss_put_hw_resources(info->dev);
+	cnss_sdio_release_resource();
+	cnss_pdata = NULL;
+	return 0;
+}
+
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	return 0;
+}
+
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num)
+{
+	*num = 0;
+	return NULL;
+}
+
+int cnss_sdio_power_down(struct device *dev)
+{
+	return 0;
+}
+
+int cnss_sdio_power_up(struct device *dev)
+{
+	return 0;
+}
+
+static const struct of_device_id cnss_sdio_dt_match[] = {
+	{.compatible = "qcom,cnss_sdio"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cnss_sdio_dt_match);
+
+static struct platform_driver cnss_sdio_driver = {
+	.probe  = cnss_sdio_probe,
+	.remove = cnss_sdio_remove,
+	.driver = {
+		.name = "cnss_sdio",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_sdio_dt_match,
+	},
+};
+
+static int __init cnss_sdio_init(void)
+{
+	return platform_driver_register(&cnss_sdio_driver);
+}
+
+static void __exit cnss_sdio_exit(void)
+{
+	platform_driver_unregister(&cnss_sdio_driver);
+}
+
+module_init(cnss_sdio_init);
+module_exit(cnss_sdio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS SDIO Driver");
diff --git a/drivers/net/wireless/cnss/logger/Kconfig b/drivers/net/wireless/cnss/logger/Kconfig
new file mode 100644
index 0000000..85b6992
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Kconfig
@@ -0,0 +1,6 @@
+config CNSS_LOGGER
+	tristate "CNSS Logging Service Driver"
+	---help---
+	  This module adds support for the CNSS Logging Service for CLD
+	  driver, including the netlink socket service registration, transmit,
+	  event receive.
diff --git a/drivers/net/wireless/cnss/logger/Makefile b/drivers/net/wireless/cnss/logger/Makefile
new file mode 100644
index 0000000..1e296a3
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CNSS_LOGGER) += logger.o
+
+logger-y += main.o	\
+	    nl_service.o
+
+logger-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/wireless/cnss/logger/debugfs.c b/drivers/net/wireless/cnss/logger/debugfs.c
new file mode 100644
index 0000000..027d630
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/debugfs.c
@@ -0,0 +1,134 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include "logger.h"
+
+#define CNSS_LOGGER_STATE_DUMP_BUFFER	(2 * 1024) /* 2KB */
+
+static int logger_state_dump_device(struct logger_device *dev, char *buf,
+				    int buf_len)
+{
+	int len = 0;
+	struct logger_event_handler *cur;
+
+	len += scnprintf(buf + len, buf_len - len,
+			"==============================================\n");
+
+	len += scnprintf(buf + len, buf_len - len,
+			"driver [%s] is registered with radio index: %d\n",
+			dev->name, dev->radio_idx);
+
+	if (list_empty(&dev->event_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "No event registered\n");
+		return len;
+	}
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		len += scnprintf(buf + len, buf_len - len,
+				"\t event %d\n", cur->event);
+	}
+	len += scnprintf(buf + len, buf_len - len, "\n");
+
+	return len;
+}
+
+static int logger_state_dump(struct logger_context *ctx, char *buf, int buf_len)
+{
+	int len = 0;
+	struct logger_device *cur;
+
+	if (list_empty(&ctx->dev_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "=======================\n");
+		len += scnprintf(buf + len, buf_len - len,
+				 "No driver registered\n");
+		return 0;
+	}
+
+	list_for_each_entry(cur, &ctx->dev_list, list)
+		len += logger_state_dump_device(cur, (buf + len), buf_len);
+
+	return 0;
+}
+
+static int logger_state_open(struct inode *inode, struct file *file)
+{
+	struct logger_context *ctx = inode->i_private;
+	void *buf;
+	int ret;
+
+	mutex_lock(&ctx->con_mutex);
+
+	buf = kmalloc(CNSS_LOGGER_STATE_DUMP_BUFFER, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto error_unlock;
+	}
+
+	ret = logger_state_dump(ctx, buf, CNSS_LOGGER_STATE_DUMP_BUFFER);
+	if (ret)
+		goto error_free;
+
+	file->private_data = buf;
+	mutex_unlock(&ctx->con_mutex);
+	return 0;
+
+error_free:
+	kfree(buf);
+
+error_unlock:
+	mutex_unlock(&ctx->con_mutex);
+
+	return ret;
+}
+
+static int logger_state_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static ssize_t logger_state_read(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	unsigned int len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_logger_state = {
+	.open = logger_state_open,
+	.release = logger_state_release,
+	.read = logger_state_read,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+void logger_debugfs_init(struct logger_context *ctx)
+{
+	if (!ctx->debugfs_entry)
+		ctx->debugfs_entry = debugfs_create_dir("cnss_logger", NULL);
+
+	debugfs_create_file("state", 0400, ctx->debugfs_entry, ctx,
+			    &fops_logger_state);
+}
+
+void logger_debugfs_remove(struct logger_context *ctx)
+{
+	debugfs_remove(ctx->debugfs_entry);
+}
+
diff --git a/drivers/net/wireless/cnss/logger/logger.h b/drivers/net/wireless/cnss/logger/logger.h
new file mode 100644
index 0000000..6531ac6
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/logger.h
@@ -0,0 +1,102 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LOGGER_H_
+#define _LOGGER_H_
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+
+#define CNSS_LOGGER_NL_MCAST_GRP_ID	0x01
+#define CNSS_LOGGER_NL_MAX_PAYLOAD	256
+#define CNSS_LOGGER_BROADCAST_ID	255
+
+/**
+ * struct aninlmsg - the wireless service message header
+ * @nlh:	the netlink message header
+ * @radio:	the radio index of this message
+ * @wmsg:	the pointer to the wireless message data
+ */
+struct aninlmsg {
+	struct  nlmsghdr *nlh;
+	int radio;
+	void *wmsg;
+};
+
+/**
+ * struct logger_event_handler - the logger event handler structure
+ * @list:	the event list associated to the same device
+ * @event:	the event number
+ * @radio_idx:	the callback handler
+ */
+struct logger_event_handler {
+	struct list_head list;
+
+	int event;
+	int (*cb)(struct sk_buff *skb);
+};
+
+/**
+ * struct logger_device - the logger device structure
+ * @list:	the device list registered to logger module
+ * @event_list:	the event list registered to this device
+ * @ctx:	the pointer to the logger context
+ * @wiphy:	the wiphy that associated to the device
+ * @name:	the name of the device driver module
+ * @radio_idx:	the radio index assigned to this device
+ */
+struct logger_device {
+	struct list_head list;
+	struct list_head event_list;
+
+	struct logger_context *ctx;
+	struct wiphy *wiphy;
+	char name[MODULE_NAME_LEN];
+	int radio_idx;
+};
+
+/**
+ * struct logger_context - the main context block for logger module
+ * @dev_list:	this is the list to maintain the devices that registered
+ *		to use the logger module feature
+ * @nl_sock:	the netlink socket to share accros the module
+ * @con_mutex:	the mutex to protect concurrent access
+ * @data_lock:	the lock to protect shared data
+ * @radio_mask: this mask would maintain the radio index assign and release
+ */
+struct logger_context {
+	struct list_head dev_list;
+
+	struct sock *nl_sock;
+	struct mutex con_mutex; /* concurrent access mutex */
+	spinlock_t data_lock;
+	unsigned long radio_mask; /* support up to 4 drivers registration? */
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_entry;
+#endif
+};
+
+int logger_netlink_init(struct logger_context *ctx);
+int logger_netlink_deinit(struct logger_context *ctx);
+struct logger_context *logger_get_ctx(void);
+
+#ifdef CONFIG_DEBUG_FS
+void logger_debugfs_init(struct logger_context *ctx);
+void logger_debugfs_remove(struct logger_context *ctx);
+#else
+static inline void logger_debugfs_init(struct logger_context *ctx) {}
+static inline void logger_debugfs_remove(struct logger_context *ctx) {}
+#endif
+
+#endif /* _LOGGER_H_ */
diff --git a/drivers/net/wireless/cnss/logger/main.c b/drivers/net/wireless/cnss/logger/main.c
new file mode 100644
index 0000000..4013e69
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/main.c
@@ -0,0 +1,55 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static struct logger_context *ctx;
+
+struct logger_context *logger_get_ctx(void)
+{
+	return ctx;
+}
+
+static int __init logger_module_init(void)
+{
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ret = logger_netlink_init(ctx);
+
+	mutex_init(&ctx->con_mutex);
+	spin_lock_init(&ctx->data_lock);
+	logger_debugfs_init(ctx);
+
+	return ret;
+}
+
+static void __exit logger_module_exit(void)
+{
+	logger_debugfs_remove(ctx);
+	logger_netlink_deinit(ctx);
+
+	kfree(ctx);
+}
+
+module_init(logger_module_init);
+module_exit(logger_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Logging Service Driver");
diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c
new file mode 100644
index 0000000..4ea76ae
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/nl_service.c
@@ -0,0 +1,476 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "cnss_logger: %s: "fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static DEFINE_MUTEX(logger_sem);
+
+/**
+ * logger_get_radio_idx() - to get the radio index
+ * @ctx: the logger context pointer
+ *
+ * Return: the first available radio index, otherwise failure code
+ */
+static int logger_get_radio_idx(struct logger_context *ctx)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ctx->radio_mask); i++) {
+		if (!test_and_set_bit(i, &ctx->radio_mask))
+			return i;
+	}
+	return -EINVAL;
+}
+
+/**
+ * logger_put_radio_idx() - to release the radio index
+ * @radio: the radio index to release
+ *
+ * Return: None
+ */
+static void logger_put_radio_idx(struct logger_context *ctx, int radio)
+{
+	clear_bit(radio, &ctx->radio_mask);
+}
+
+/**
+ * logger_get_device() - to get the logger device per radio index
+ * @radio: the radio index
+ *
+ * Return: the logger_device pointer, otherwise return NULL.
+ */
+static struct logger_device *logger_get_device(int radio)
+{
+	struct logger_device *dev;
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return NULL;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->radio_idx == radio)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_device_is_registered() - to check if device has been registered
+ * @dev: pointer to logger device
+ * @wiphy: the wiphy pointer of the device to register
+ *
+ * This helper function is to check if this device has been registered.
+ *
+ * Return: NULL if it has not, otherwise return the logger_device pointer.
+ */
+static struct logger_device *logger_device_is_registered(
+						 struct logger_context *ctx,
+						 struct wiphy *wiphy)
+{
+	struct logger_device *dev;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->wiphy == wiphy)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_dispatch_skb() - to dispatch the skb to devices
+ * @skb: the socket buffer received and to dispatch
+ *
+ * The function will look up the header of the skb, and dispatch the skb
+ * to the associated event and device that registered.
+ *
+ * Return: 0 if successfully dispatch, otherwise failure code
+ */
+static int logger_dispatch_skb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct logger_event_handler *evt;
+	int handled = 0;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	pr_info("skb_len: %d, skb_data_len: %d\n",
+		skb->len, skb->data_len);
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return 0;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	list_for_each_entry(cur, &ctx->dev_list, list) {
+		list_for_each_entry(evt, &cur->event_list, list) {
+			if (nlh->nlmsg_type == evt->event) {
+				if (evt->cb) {
+					handled = 1;
+					evt->cb(skb);
+				}
+				/* Break inside loop, next dev */
+				break;
+			}
+		}
+	}
+
+	if (!handled)
+		pr_info("Not handled msg type: %d\n", nlh->nlmsg_type);
+
+	return 0;
+}
+
+/**
+ * logger_flush_event_handle() - to flush the event handle associate to device
+ * @dev: pointer to logger device
+ *
+ * The function will clean up all the event handle's resource, take it out
+ * from the list, and free the memory allocated.
+ *
+ * Return: None
+ */
+static void logger_flush_event_handle(struct logger_device *dev)
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		pr_info("radio: %d, event: %d unregistered\n",
+			dev->radio_idx, cur->event);
+		list_del(&cur->list);
+		kfree(cur);
+	}
+}
+
+/**
+ * logger_flush_devices() - to flush the devices infomration
+ * @dev: pointer to logger device
+ *
+ * The helper function to flush the device information, all the device clean
+ * up prcoess should be starting from here.
+ *
+ * Return: None
+ */
+static void logger_flush_devices(struct logger_device *dev)
+{
+	pr_info("driver: [%s] and radio-%d is unregistered\n",
+		dev->name, dev->radio_idx);
+	logger_flush_event_handle(dev);
+	logger_put_radio_idx(dev->ctx, dev->radio_idx);
+	list_del(&dev->list);
+	kfree(dev);
+}
+
+/**
+ * logger_register_device_event() - register the evet to device
+ * @dev: pointer to logger device
+ * @event: the event to register
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if register successfully, otherwise the failure code
+ */
+static int logger_register_device_event(struct logger_device *dev, int event,
+					int (*cb)(struct sk_buff *skb))
+{
+	struct logger_event_handler *cur;
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		if (cur->event == event) {
+			pr_info("event %d, is already added\n", event);
+			return 0;
+		}
+	}
+
+	cur = kmalloc(sizeof(*cur), GFP_KERNEL);
+	if (!cur)
+		return -ENOMEM;
+
+	cur->event = event;
+	cur->cb = cb;
+
+	pr_info("radio: %d, event: %d\n", dev->radio_idx, cur->event);
+	list_add_tail(&cur->list, &dev->event_list);
+
+	return 0;
+}
+
+/**
+ * logger_unregister_device_event() - unregister the evet from device
+ * @dev: pointer to logger device
+ * @event: the event to unregister
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if unregister successfully, otherwise the failure code
+ */
+static int logger_unregister_device_event(struct logger_device *dev, int event,
+					  int (*cb)(struct sk_buff *skb))
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		if (cur->event == event && cur->cb == cb) {
+			pr_info("radio: %d, event: %d\n",
+				dev->radio_idx, cur->event);
+			list_del(&cur->list);
+			kfree(cur);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * logger_skb_input() - the callback to receive the skb
+ * @skb: the receive socket buffer
+ *
+ * Return: None
+ */
+static void logger_skb_input(struct sk_buff *skb)
+{
+	mutex_lock(&logger_sem);
+	logger_dispatch_skb(skb);
+	mutex_unlock(&logger_sem);
+}
+
+/**
+ * cnss_logger_event_register() - register the event
+ * @radio: the radio index to register
+ * @event: the event to register
+ * @cb: the callback
+ *
+ * This function is used to register event associated to the radio index.
+ *
+ * Return: 0 if register success, otherwise failure code
+ */
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_register_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_register);
+
+/**
+ * cnss_logger_event_unregister() - unregister the event
+ * @radio: the radio index to unregister
+ * @event: the event to unregister
+ * @cb: the callback
+ *
+ * This function is used to unregister the event from cnss logger module.
+ *
+ * Return: 0 if unregister success, otherwise failure code
+ */
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_unregister_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_unregister);
+
+/**
+ * cnss_logger_device_register() - register the driver
+ * @wiphy: the wiphy device to unregister
+ * @name: the module name of the driver
+ *
+ * This function is used to register the driver to cnss logger module,
+ * this will indicate the existence of the driver, and also assign the
+ * radio index for further operation.
+ *
+ * Return: the radio index if register successful, otherwise failure code
+ */
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name)
+{
+	int radio;
+	struct logger_context *ctx;
+	struct logger_device *new;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	/* sanity check, already registered? */
+	new = logger_device_is_registered(ctx, wiphy);
+	if (new)
+		return new->radio_idx;
+
+	radio = logger_get_radio_idx(ctx);
+	if (radio < 0) {
+		pr_err("driver registration is full\n");
+		return -ENOMEM;
+	}
+
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (!new) {
+		logger_put_radio_idx(ctx, radio);
+		return -ENOMEM;
+	}
+
+	new->radio_idx = radio;
+	new->wiphy = wiphy;
+	new->ctx = ctx;
+	strlcpy(new->name, name, sizeof(new->name));
+	INIT_LIST_HEAD(&new->event_list);
+
+	list_add(&new->list, &ctx->dev_list);
+
+	pr_info("driver: [%s] is registered as radio-%d\n",
+		new->name, new->radio_idx);
+
+	return new->radio_idx;
+}
+EXPORT_SYMBOL(cnss_logger_device_register);
+
+/**
+ * cnss_logger_device_unregister() - unregister the driver
+ * @radio: the radio to unregister
+ * @wiphy: the wiphy device to unregister
+ *
+ * This function is used to unregister the driver from cnss logger module.
+ * This will disable the driver to access the interface in cnss logger,
+ * and also all the related events that registered will be reset.
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct list_head *pos, *temp;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		cur = list_entry(pos, struct logger_device, list);
+		if (cur->radio_idx == radio && cur->wiphy == wiphy) {
+			logger_flush_devices(cur);
+			break;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_logger_device_unregister);
+
+/**
+ * cnss_logger_nl_ucast() - nl interface to unicast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the flag to indicate if this is a nonblock call
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_unicast(ctx->nl_sock, skb, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_ucast);
+
+/**
+ * cnss_logger_nl_bcast() - nl interface to broadcast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the gfp_t flag
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_broadcast(ctx->nl_sock, skb, 0, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_bcast);
+
+/**
+ * logger_netlink_init() - initialize the netlink socket
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: the netlink handle if success, otherwise failure code
+ */
+int logger_netlink_init(struct logger_context *ctx)
+{
+	struct netlink_kernel_cfg cfg = {
+		.groups	= CNSS_LOGGER_NL_MCAST_GRP_ID,
+		.input	= logger_skb_input,
+	};
+
+	ctx->nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
+	if (!ctx->nl_sock) {
+		pr_err("cnss_logger: Cannot create netlink socket");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&ctx->dev_list);
+
+	return 0;
+}
+
+/**
+ * logger_netlink_deinit() - release the netlink socket and other resource
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int logger_netlink_deinit(struct logger_context *ctx)
+{
+	struct list_head *pos, *temp;
+	struct logger_device *dev;
+
+	netlink_kernel_release(ctx->nl_sock);
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		dev = container_of(pos, struct logger_device, list);
+		logger_flush_devices(dev);
+	}
+	return 0;
+}
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index c02aabf..00ca8dc4 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -53,6 +53,8 @@
 #define PCIE20_PARF_DBI_BASE_ADDR_HI   0x354
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE        0x358
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI     0x35C
+#define PCIE20_PARF_ATU_BASE_ADDR      0x634
+#define PCIE20_PARF_ATU_BASE_ADDR_HI   0x638
 #define PCIE20_PARF_DEVICE_TYPE        0x1000
 
 #define PCIE20_ELBI_VERSION            0x00
@@ -98,6 +100,24 @@
 #define PCIE20_PLR_IATU_LTAR           0x918
 #define PCIE20_PLR_IATU_UTAR           0x91c
 
+#define PCIE20_IATU_BASE(n)            (n * 0x200)
+
+#define PCIE20_IATU_O_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x00)
+#define PCIE20_IATU_O_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x04)
+#define PCIE20_IATU_O_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x08)
+#define PCIE20_IATU_O_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x0c)
+#define PCIE20_IATU_O_LAR(n)           (PCIE20_IATU_BASE(n) + 0x10)
+#define PCIE20_IATU_O_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x14)
+#define PCIE20_IATU_O_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x18)
+
+#define PCIE20_IATU_I_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x100)
+#define PCIE20_IATU_I_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x104)
+#define PCIE20_IATU_I_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x108)
+#define PCIE20_IATU_I_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x10c)
+#define PCIE20_IATU_I_LAR(n)           (PCIE20_IATU_BASE(n) + 0x110)
+#define PCIE20_IATU_I_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x114)
+#define PCIE20_IATU_I_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x118)
+
 #define PCIE20_MHICFG                  0x110
 #define PCIE20_BHI_EXECENV             0x228
 
@@ -129,7 +149,7 @@
 
 #define EP_PCIE_LOG_PAGES 50
 #define EP_PCIE_MAX_VREG 2
-#define EP_PCIE_MAX_CLK 5
+#define EP_PCIE_MAX_CLK 7
 #define EP_PCIE_MAX_PIPE_CLK 1
 #define EP_PCIE_MAX_RESET 2
 
@@ -202,6 +222,7 @@
 	EP_PCIE_RES_MSI,
 	EP_PCIE_RES_DM_CORE,
 	EP_PCIE_RES_ELBI,
+	EP_PCIE_RES_IATU,
 	EP_PCIE_MAX_RES,
 };
 
@@ -292,6 +313,7 @@
 	void __iomem                 *msi;
 	void __iomem                 *dm_core;
 	void __iomem                 *elbi;
+	void __iomem                 *iatu;
 
 	struct msm_bus_scale_pdata   *bus_scale_table;
 	u32                          bus_client;
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index e48409b..055f026 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -68,6 +68,8 @@
 	{NULL, "pcie_0_slv_axi_clk", 0, true},
 	{NULL, "pcie_0_aux_clk", 1000000, true},
 	{NULL, "pcie_0_ldo", 0, true},
+	{NULL, "pcie_0_sleep_clk", 0, false},
+	{NULL, "pcie_0_slv_q2a_axi_clk", 0, false},
 };
 
 static struct ep_pcie_clk_info_t
@@ -82,12 +84,13 @@
 };
 
 static const struct ep_pcie_res_info_t ep_pcie_res_info[EP_PCIE_MAX_RES] = {
-	{"parf",	0, 0},
-	{"phy",		0, 0},
-	{"mmio",	0, 0},
-	{"msi",		0, 0},
-	{"dm_core",	0, 0},
-	{"elbi",	0, 0}
+	{"parf",	NULL, NULL},
+	{"phy",		NULL, NULL},
+	{"mmio",	NULL, NULL},
+	{"msi",		NULL, NULL},
+	{"dm_core",	NULL, NULL},
+	{"elbi",	NULL, NULL},
+	{"iatu",	NULL, NULL},
 };
 
 static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
@@ -318,8 +321,8 @@
 				break;
 			}
 			EP_PCIE_DBG(dev,
-				"PCIe V%d: set rate for clk %s.\n",
-				dev->rev, info->name);
+				"PCIe V%d: set rate %d for clk %s.\n",
+				dev->rev, info->freq, info->name);
 		}
 
 		rc = clk_prepare_enable(info->hdl);
@@ -528,6 +531,47 @@
 				0xf, dev->link_speed);
 	}
 
+	if (dev->active_config) {
+		struct resource *dbi = dev->res[EP_PCIE_RES_DM_CORE].resource;
+		u32 dbi_lo = dbi->start;
+
+		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
+
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
+					0, BIT(0));
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
+					0x200);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
+					0x0);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
+					0x100);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
+					dbi_lo);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: DBI base:0x%x.\n", dev->rev,
+			readl_relaxed(dev->parf + PCIE20_PARF_DBI_BASE_ADDR));
+
+		if (dev->phy_rev >= 6) {
+			struct resource *atu =
+					dev->res[EP_PCIE_RES_IATU].resource;
+			u32 atu_lo = atu->start;
+
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: configure MSB of ATU base for flipping and LSB as 0x%x.\n",
+				dev->rev, atu_lo);
+			ep_pcie_write_reg(dev->parf,
+					PCIE20_PARF_ATU_BASE_ADDR_HI, 0x100);
+			ep_pcie_write_reg(dev->parf, PCIE20_PARF_ATU_BASE_ADDR,
+					atu_lo);
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: LSB of ATU base:0x%x.\n",
+				dev->rev, readl_relaxed(dev->parf
+						+ PCIE20_PARF_ATU_BASE_ADDR));
+		}
+	}
+
 	/* Read halts write */
 	ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES,
 			0, BIT(0));
@@ -646,13 +690,6 @@
 			dev->rev,
 			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
 	}
-
-	if (dev->active_config) {
-		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
-
-		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
-	}
 }
 
 static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
@@ -671,6 +708,26 @@
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_LOWER, lower);
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_UPPER, 0x0);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL1(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_LTAR(0), lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_UTAR(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL2(0),
+					0xc0000000);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Inbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL1(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL1(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_LTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_LTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_UTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_UTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL2(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL2(0)));
+		return;
+	}
+
 	/* program inbound address translation using region 0 */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, 0x80000000);
 	/* set region to mem type */
@@ -701,6 +758,49 @@
 		"PCIe V%d: region:%d; lower:0x%x; limit:0x%x; target_lower:0x%x; target_upper:0x%x\n",
 		dev->rev, region, lower, limit, tgt_lower, tgt_upper);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_CTRL1(region),
+					0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LBAR(region),
+					lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UBAR(region),
+					upper);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LAR(region),
+					limit);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LTAR(region),
+					tgt_lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UTAR(region),
+					tgt_upper);
+		ep_pcie_write_mask(dev->iatu + PCIE20_IATU_O_CTRL2(region),
+					0, BIT(31));
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Outbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL1:0x%x\n",
+			readl_relaxed(dev->iatu
+					+ PCIE20_IATU_O_CTRL1(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL2:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_CTRL2(region)));
+
+		return;
+	}
+
 	/* program outbound address translation using an input region */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, region);
 	/* set region to mem type */
@@ -813,12 +913,10 @@
 		ret = of_property_read_u32_array(
 			(&pdev->dev)->of_node,
 			"max-clock-frequency-hz", clkfreq, cnt);
-		if (ret) {
-			EP_PCIE_ERR(dev,
-				"PCIe V%d: invalid max-clock-frequency-hz property:%d\n",
+		if (ret)
+			EP_PCIE_DBG2(dev,
+				"PCIe V%d: cannot get max-clock-frequency-hz property from DT:%d\n",
 				dev->rev, ret);
-			goto out;
-		}
 	}
 
 	for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
@@ -1037,6 +1135,7 @@
 	dev->msi = dev->res[EP_PCIE_RES_MSI].base;
 	dev->dm_core = dev->res[EP_PCIE_RES_DM_CORE].base;
 	dev->elbi = dev->res[EP_PCIE_RES_ELBI].base;
+	dev->iatu = dev->res[EP_PCIE_RES_IATU].base;
 
 out:
 	kfree(clkfreq);
@@ -1051,6 +1150,7 @@
 	dev->phy = NULL;
 	dev->mmio = NULL;
 	dev->msi = NULL;
+	dev->iatu = NULL;
 
 	if (dev->bus_client) {
 		msm_bus_scale_unregister_client(dev->bus_client);
@@ -1319,18 +1419,8 @@
 	}
 
 checkbme:
-	if (dev->active_config) {
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
-					0, BIT(0));
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
-					0x200);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
-					0x0);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
-					0x100);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
-					0x7FFFE000);
-	}
+	if (dev->active_config)
+		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
 
 	if (!(opt & EP_PCIE_OPT_ENUM_ASYNC)) {
 		/* Wait for up to 1000ms for BME to be set */
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
index 776ef08..f813bb9 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -35,6 +35,11 @@
 			"PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n",
 			dev->rev, dev->phy_rev);
 		break;
+	case 6:
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: PHY V%d: Initializing 7nm QMP phy - 100MHz\n",
+			dev->rev, dev->phy_rev);
+		break;
 	default:
 		EP_PCIE_ERR(dev,
 			"PCIe V%d: Unexpected phy version %d is caught!\n",
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index e20ddba..bf498f9 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -3230,6 +3230,18 @@
 	return ret;
 }
 
+/**
+ * ipa_pm_is_used() - Returns if IPA PM framework is used
+ */
+bool ipa_pm_is_used(void)
+{
+	bool ret;
+
+	IPA_API_DISPATCH_RETURN(ipa_pm_is_used);
+
+	return ret;
+}
+
 static const struct dev_pm_ops ipa_pm_ops = {
 	.suspend_noirq = ipa_ap_suspend,
 	.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index f3e62b8..79d0c70 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -421,6 +421,8 @@
 	int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
 		struct ipa_smmu_out_params *out);
 	int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
+
+	bool (*ipa_pm_is_used)(void);
 };
 
 #ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 52ffa52..78d1c96 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3925,7 +3925,6 @@
 	ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
 	ipa_ctx->use_dma_zone = resource_p->use_dma_zone;
 	ipa_ctx->tethered_flow_control = resource_p->tethered_flow_control;
-	ipa_ctx->use_ipa_pm = resource_p->use_ipa_pm;
 
 	/* Setting up IPA RX Polling Timeout Seconds */
 	ipa_rx_timeout_min_max_calc(&ipa_ctx->ipa_rx_min_timeout_usec,
@@ -4451,20 +4450,12 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa_ctx) ? ipa_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_configuration(struct platform_device *pdev,
 		struct ipa_plat_drv_res *ipa_drv_res)
 {
 	int result;
 	struct resource *resource;
 
-	ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
-		"qcom,use-ipa-pm");
-	IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
 	/* initialize ipa_res */
 	ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
 	ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index ec4942f..91017a5 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -1206,7 +1206,6 @@
 	int num_ipa_cne_evt_req;
 	struct mutex ipa_cne_evt_lock;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 /**
@@ -1263,7 +1262,6 @@
 	u32 ipa_rx_polling_sleep_msec;
 	u32 ipa_polling_iteration;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 struct ipa_mem_partition {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index e06f6cf..27120c8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -4984,6 +4984,11 @@
 	ipa_ctx->tag_process_before_gating = val;
 }
 
+static bool ipa2_pm_is_used(void)
+{
+	return false;
+}
+
 int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -5159,6 +5164,7 @@
 	api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
 	api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
 	api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+	api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 01c0736..0dd0b7b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -5381,11 +5381,6 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_pm_info(struct platform_device *pdev,
 	struct ipa3_plat_drv_res *ipa_drv_res)
 {
@@ -5973,6 +5968,7 @@
 	int bypass = 1;
 	u32 iova_ap_mapping[2];
 	u32 add_map_size;
+	u32 q6_smem_size;
 	const u32 *add_map;
 	void *smem_addr;
 	int i;
@@ -6089,9 +6085,18 @@
 		}
 	}
 
-	/* map SMEM memory for IPA table accesses */
-	smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
-		SMEM_MODEM, 0);
+	result = of_property_read_u32_array(dev->of_node,
+			"qcom,ipa-q6-smem-size", &q6_smem_size, 1);
+	if (result) {
+		IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
+		/* map SMEM memory for IPA table accesses */
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
+				SMEM_MODEM, 0);
+	} else {
+		IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
+				SMEM_MODEM, 0);
+	}
 	if (smem_addr) {
 		phys_addr_t iova = smem_virt_to_phys(smem_addr);
 		phys_addr_t pa = iova;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 9974b87..32e9891 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4336,6 +4336,11 @@
 	return 0;
 }
 
+static bool ipa3_pm_is_used(void)
+{
+	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
 int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -4523,6 +4528,7 @@
 	api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
 	api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
 	api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
+	api_ctrl->ipa_pm_is_used = ipa3_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 819fbf0..6adb44c 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -321,8 +321,11 @@
 	POWER_SUPPLY_ATTR(sdp_current_max),
 	POWER_SUPPLY_ATTR(connector_type),
 	POWER_SUPPLY_ATTR(parallel_batfet_mode),
+	POWER_SUPPLY_ATTR(parallel_fcc_max),
 	POWER_SUPPLY_ATTR(min_icl),
 	POWER_SUPPLY_ATTR(moisture_detected),
+	POWER_SUPPLY_ATTR(batt_full_current),
+	POWER_SUPPLY_ATTR(recharge_soc),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 3f8c727..223af14 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* 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
@@ -73,6 +73,7 @@
 	int			charge_type;
 	int			total_settled_ua;
 	int			pl_settled_ua;
+	int			pl_fcc_max;
 	struct class		qcom_batt_class;
 	struct wakeup_source	*pl_ws;
 	struct notifier_block	nb;
@@ -418,6 +419,7 @@
 	effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
 	slave_limited_ua = min(effective_total_ua, bcl_ua);
 	*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
+	*slave_ua = min(*slave_ua, chip->pl_fcc_max);
 
 	/*
 	 * In stacked BATFET configuration charger's current goes
@@ -935,6 +937,12 @@
 					&pval);
 	chip->pl_min_icl_ua = pval.intval;
 
+	chip->pl_fcc_max = INT_MAX;
+	rc = power_supply_get_property(chip->pl_psy,
+			POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval);
+	if (!rc)
+		chip->pl_fcc_max = pval.intval;
+
 	vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
 
 	return true;
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index d1031ba..b07efdf 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -28,7 +28,67 @@
 #include "smb5-reg.h"
 #include "smb5-lib.h"
 
-static struct smb_params smb5_params = {
+static struct smb_params smb5_pmi632_params = {
+	.fcc			= {
+		.name   = "fast charge current",
+		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.fv			= {
+		.name   = "float voltage",
+		.reg    = CHGR_FLOAT_VOLTAGE_CFG_REG,
+		.min_u  = 3600000,
+		.max_u  = 4800000,
+		.step_u = 10000,
+	},
+	.usb_icl		= {
+		.name   = "usb input current limit",
+		.reg    = USBIN_CURRENT_LIMIT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.icl_stat		= {
+		.name   = "input current limit status",
+		.reg    = AICL_ICL_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.otg_cl			= {
+		.name	= "usb otg current limit",
+		.reg	= DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+		.min_u	= 500000,
+		.max_u	= 1000000,
+		.step_u	= 250000,
+	},
+	.jeita_cc_comp_hot	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_HOT_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.jeita_cc_comp_cold	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_COLD_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.freq_switcher		= {
+		.name	= "switching frequency",
+		.reg	= DCDC_FSW_SEL_REG,
+		.min_u	= 600,
+		.max_u	= 1200,
+		.step_u	= 400,
+		.set_proc = smblib_set_chg_freq,
+	},
+};
+
+static struct smb_params smb5_pmi855_params = {
 	.fcc			= {
 		.name   = "fast charge current",
 		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
@@ -119,6 +179,64 @@
 	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
 );
 
+#define PMI632_MAX_ICL_UA	3000000
+static int smb5_chg_config_init(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct pmic_revid_data *pmic_rev_id;
+	struct device_node *revid_dev_node;
+	int rc = 0;
+
+	revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+					  "qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_err("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR_OR_NULL(pmic_rev_id)) {
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		rc =  -EPROBE_DEFER;
+		goto out;
+	}
+
+	switch (pmic_rev_id->pmic_subtype) {
+	case PM855B_SUBTYPE:
+		chip->chg.smb_version = PM855B_SUBTYPE;
+		chg->param = smb5_pmi855_params;
+		chg->name = "pm855b_charger";
+		break;
+	case PMI632_SUBTYPE:
+		chip->chg.smb_version = PMI632_SUBTYPE;
+		chg->param = smb5_pmi632_params;
+		chg->use_extcon = true;
+		chg->name = "pmi632_charger";
+		chg->hw_max_icl_ua =
+			(chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
+						: PMI632_MAX_ICL_UA;
+		chg->chg_freq.freq_5V			= 600;
+		chg->chg_freq.freq_6V_8V		= 800;
+		chg->chg_freq.freq_9V			= 1050;
+		chg->chg_freq.freq_removal		= 1050;
+		chg->chg_freq.freq_below_otg_threshold	= 800;
+		chg->chg_freq.freq_above_otg_threshold	= 800;
+		break;
+	default:
+		pr_err("PMIC subtype %d not supported\n",
+				pmic_rev_id->pmic_subtype);
+		rc = -EINVAL;
+	}
+
+out:
+	of_node_put(revid_dev_node);
+	return rc;
+}
+
 #define MICRO_1P5A		1500000
 #define MICRO_P1A		100000
 #define OTG_DEFAULT_DEGLITCH_TIME_MS	50
@@ -213,8 +331,6 @@
 	chip->dt.auto_recharge_soc = of_property_read_bool(node,
 						"qcom,auto-recharge-soc");
 
-	chg->micro_usb_mode = of_property_read_bool(node, "qcom,micro-usb");
-
 	chg->dcp_icl_ua = chip->dt.usb_icl_ua;
 
 	chg->suspend_input_on_debug_batt = of_property_read_bool(node,
@@ -253,6 +369,8 @@
 	POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
 	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
 };
 
 static int smb5_usb_get_prop(struct power_supply *psy,
@@ -272,12 +390,13 @@
 		if (!val->intval)
 			break;
 
-		if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
-			chg->micro_usb_mode) &&
-			chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
 			val->intval = 0;
 		else
 			val->intval = 1;
+
 		if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
 			val->intval = 0;
 		break;
@@ -297,19 +416,19 @@
 		val->intval = chg->real_charger_type;
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_MODE:
-		if (chg->micro_usb_mode)
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 			val->intval = POWER_SUPPLY_TYPEC_NONE;
 		else
 			val->intval = chg->typec_mode;
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
-		if (chg->micro_usb_mode)
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 			val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
 		else
 			rc = smblib_get_prop_typec_power_role(chg, val);
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
-		if (chg->micro_usb_mode)
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 			val->intval = 0;
 		else
 			rc = smblib_get_prop_typec_cc_orientation(chg, val);
@@ -354,6 +473,9 @@
 		val->intval = get_client_vote(chg->usb_icl_votable,
 					      USB_PSY_VOTER);
 		break;
+	case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
+		val->intval = chg->connector_type;
+		break;
 	default:
 		pr_err("get prop %d is not supported in usb\n", psp);
 		rc = -EINVAL;
@@ -496,9 +618,9 @@
 		if (!val->intval)
 			break;
 
-		if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
-			chg->micro_usb_mode) &&
-			chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
 			val->intval = 1;
 		else
 			val->intval = 0;
@@ -1093,7 +1215,7 @@
 	struct regulator_config cfg = {};
 	int rc = 0;
 
-	if (chg->micro_usb_mode)
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 		return 0;
 
 	chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
@@ -1139,7 +1261,6 @@
 	}
 
 	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
-				MICRO_USB_STATE_CHANGE_INT_EN_BIT |
 				TYPEC_WATER_DETECTION_INT_EN_BIT);
 	if (rc < 0) {
 		dev_err(chg->dev,
@@ -1172,14 +1293,23 @@
 		return rc;
 	}
 
+	rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
 	return rc;
 }
 
 static int smb5_init_hw(struct smb5 *chip)
 {
 	struct smb_charger *chg = &chip->chg;
-	int rc;
-	u8 val;
+	int rc, type = 0;
+	u8 val = 0;
 
 	if (chip->dt.no_battery)
 		chg->fake_capacity = 50;
@@ -1194,8 +1324,50 @@
 
 	smblib_get_charge_param(chg, &chg->param.usb_icl,
 				&chg->default_icl_ua);
-	if (chip->dt.usb_icl_ua < 0)
-		chip->dt.usb_icl_ua = chg->default_icl_ua;
+
+	/* Use SW based VBUS control, disable HW autonomous mode */
+	/* TODO: auth can be enabled through vote based on APSD flow */
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
+		HVDCP_AUTH_ALG_EN_CFG_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
+		return rc;
+	}
+
+	/*
+	 * PMI632 can have the connector type defined by a dedicated register
+	 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
+	 */
+	if (chg->smb_version == PMI632_SUBTYPE) {
+		rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
+			return rc;
+		}
+		type = !!(val & MICRO_USB_MODE_ONLY_BIT);
+	}
+
+	/*
+	 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
+	 * check the connector type using TYPEC_U_USB_CFG_REG.
+	 */
+	if (!type) {
+		rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		type = !!(val & EN_MICRO_USB_MODE_BIT);
+	}
+
+	chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
+					: POWER_SUPPLY_CONNECTOR_TYPEC;
+	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+
+	smblib_rerun_apsd_if_required(chg);
 
 	/* vote 0mA on usb_icl for non battery platforms */
 	vote(chg->usb_icl_votable,
@@ -1207,15 +1379,21 @@
 	vote(chg->fv_votable, HW_LIMIT_VOTER,
 		chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
 	vote(chg->fcc_votable,
-		BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua);
+		BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
+		chg->batt_profile_fcc_ua);
 	vote(chg->fv_votable,
-		BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv);
+		BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
+		chg->batt_profile_fv_uv);
 	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
 			true, 0);
 	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
 			true, 0);
 	vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
-			chg->micro_usb_mode, 0);
+		chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
+
+	/* Some h/w limit maximum supported ICL */
+	vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
+			chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
 
 	/*
 	 * AICL configuration:
@@ -1235,7 +1413,7 @@
 		return rc;
 	}
 
-	if (chg->micro_usb_mode)
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 		rc = smb5_configure_micro_usb(chg);
 	else
 		rc = smb5_configure_typec(chg);
@@ -1384,8 +1562,8 @@
 	pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
 	rc = smblib_set_prop_typec_power_role(chg, &pval);
 	if (rc < 0) {
-		dev_err(chg->dev,
-			"Couldn't configure power role for DRP rc=%d\n", rc);
+		dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
+				rc);
 		return rc;
 	}
 
@@ -1405,6 +1583,7 @@
 
 	if (chg->bms_psy)
 		smblib_suspend_on_debug_battery(chg);
+
 	usb_plugin_irq_handler(0, &irq_data);
 	typec_state_change_irq_handler(0, &irq_data);
 	usb_source_change_irq_handler(0, &irq_data);
@@ -1412,6 +1591,7 @@
 	icl_change_irq_handler(0, &irq_data);
 	batt_temp_changed_irq_handler(0, &irq_data);
 	wdog_bark_irq_handler(0, &irq_data);
+	typec_or_rid_detection_change_irq_handler(0, &irq_data);
 
 	return 0;
 }
@@ -1586,7 +1766,7 @@
 	/* TYPEC IRQs */
 	[TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
 		.name		= "typec-or-rid-detect-change",
-		.handler	= default_irq_handler,
+		.handler	= typec_or_rid_detection_change_irq_handler,
 	},
 	[TYPEC_VPD_DETECT_IRQ] = {
 		.name		= "typec-vpd-detect",
@@ -1880,13 +2060,12 @@
 
 	chg = &chip->chg;
 	chg->dev = &pdev->dev;
-	chg->param = smb5_params;
 	chg->debug_mask = &__debug_mask;
 	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
 	chg->mode = PARALLEL_MASTER;
 	chg->irq_info = smb5_irqs;
 	chg->die_health = -EINVAL;
-	chg->name = "pm855b_charger";
+	chg->otg_present = false;
 
 	chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
 	if (!chg->regmap) {
@@ -1897,13 +2076,20 @@
 	rc = smb5_parse_dt(chip);
 	if (rc < 0) {
 		pr_err("Couldn't parse device tree rc=%d\n", rc);
-		goto cleanup;
+		return rc;
+	}
+
+	rc = smb5_chg_config_init(chip);
+	if (rc < 0) {
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't setup chg_config rc=%d\n", rc);
+		return rc;
 	}
 
 	rc = smblib_init(chg);
 	if (rc < 0) {
 		pr_err("Smblib_init failed rc=%d\n", rc);
-		goto cleanup;
+		return rc;
 	}
 
 	/* set driver data before resources request it */
@@ -1945,10 +2131,12 @@
 		goto cleanup;
 	}
 
-	rc = smb5_init_dc_psy(chip);
-	if (rc < 0) {
-		pr_err("Couldn't initialize dc psy rc=%d\n", rc);
-		goto cleanup;
+	if (chg->smb_version == PM855B_SUBTYPE) {
+		rc = smb5_init_dc_psy(chip);
+		if (rc < 0) {
+			pr_err("Couldn't initialize dc psy rc=%d\n", rc);
+			goto cleanup;
+		}
 	}
 
 	rc = smb5_init_usb_psy(chip);
@@ -1991,7 +2179,7 @@
 	rc = smb5_post_init(chip);
 	if (rc < 0) {
 		pr_err("Failed in post init rc=%d\n", rc);
-		goto cleanup;
+		goto free_irq;
 	}
 
 	smb5_create_debugfs(chip);
@@ -1999,7 +2187,7 @@
 	rc = smb5_show_charger_status(chip);
 	if (rc < 0) {
 		pr_err("Failed in getting charger status rc=%d\n", rc);
-		goto cleanup;
+		goto free_irq;
 	}
 
 	device_init_wakeup(chg->dev, true);
@@ -2008,8 +2196,9 @@
 
 	return rc;
 
-cleanup:
+free_irq:
 	smb5_free_interrupts(chg);
+cleanup:
 	smblib_deinit(chg);
 	platform_set_drvdata(pdev, NULL);
 
@@ -2036,7 +2225,7 @@
 	smb5_disable_interrupts(chg);
 
 	/* configure power role for UFP */
-	if (!chg->micro_usb_mode)
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
 		smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
 				TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
 
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index ebaaf5c..ffbced6 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -31,6 +31,7 @@
 
 /* SMB1355 registers, different than mentioned in smb-reg.h */
 
+#define REVID_BASE	0x0100
 #define CHGR_BASE	0x1000
 #define ANA2_BASE	0x1100
 #define BATIF_BASE	0x1200
@@ -38,6 +39,8 @@
 #define ANA1_BASE	0x1400
 #define MISC_BASE	0x1600
 
+#define REVID_MFG_ID_SPARE_REG			(REVID_BASE + 0xFF)
+
 #define BATTERY_STATUS_2_REG			(CHGR_BASE + 0x0B)
 #define DISABLE_CHARGING_BIT			BIT(3)
 
@@ -222,6 +225,8 @@
 	char			*name;
 	struct regmap		*regmap;
 
+	int			max_fcc;
+
 	struct smb_dt_props	dt;
 	struct smb_params	param;
 	struct smb_iio		iio;
@@ -483,6 +488,7 @@
 	POWER_SUPPLY_PROP_PARALLEL_MODE,
 	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -624,6 +630,9 @@
 	case POWER_SUPPLY_PROP_MIN_ICL:
 		val->intval = MIN_PARALLEL_ICL_UA;
 		break;
+	case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
+		val->intval = chip->max_fcc;
+		break;
 	default:
 		pr_err_ratelimited("parallel psy get prop %d not supported\n",
 			prop);
@@ -798,6 +807,37 @@
  * HARDWARE INITIALIZATION *
  ***************************/
 
+#define MFG_ID_SMB1354			0x01
+#define MFG_ID_SMB1355			0xFF
+#define SMB1354_MAX_PARALLEL_FCC_UA	2500000
+static int smb1355_detect_version(struct smb1355 *chip)
+{
+	int rc;
+	u8 val;
+
+	rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val);
+	if (rc < 0) {
+		pr_err("Unable to read REVID rc=%d\n", rc);
+		return rc;
+	}
+
+	switch (val) {
+	case MFG_ID_SMB1354:
+		chip->name = "smb1354";
+		chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA;
+		break;
+	case MFG_ID_SMB1355:
+		chip->name = "smb1355";
+		chip->max_fcc = INT_MAX;
+		break;
+	default:
+		pr_err("Invalid value of REVID val=%d", val);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
 static int smb1355_tskin_sensor_config(struct smb1355 *chip)
 {
 	int rc;
@@ -1196,7 +1236,6 @@
 	chip->dev = &pdev->dev;
 	chip->param = v1_params;
 	chip->c_health = -EINVAL;
-	chip->name = "smb1355";
 	mutex_init(&chip->write_lock);
 	INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work);
 	chip->disabled = true;
@@ -1214,6 +1253,12 @@
 		return -ENODEV;
 	}
 
+	rc = smb1355_detect_version(chip);
+	if (rc < 0) {
+		pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc);
+		goto cleanup;
+	}
+
 	platform_set_drvdata(pdev, chip);
 
 	rc = smb1355_parse_dt(chip);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index ff7da6c..dbadd95 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -107,19 +107,6 @@
 	return 0;
 }
 
-int smblib_icl_override(struct smb_charger *chg, bool override)
-{
-	int rc;
-
-	rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
-				ICL_OVERRIDE_AFTER_APSD_BIT,
-				override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
-
-	return rc;
-}
-
 int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
 {
 	int rc = 0;
@@ -137,6 +124,39 @@
 	return rc;
 }
 
+static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
+{
+	union extcon_property_value val;
+	union power_supply_propval prop_val;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
+		smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+		val.intval = ((prop_val.intval == 2) ? 1 : 0);
+		extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_TYPEC_POLARITY, val);
+	}
+
+	val.intval = true;
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
 /********************
  * REGISTER GETTERS *
  ********************/
@@ -281,6 +301,48 @@
 /********************
  * REGISTER SETTERS *
  ********************/
+static const struct buck_boost_freq chg_freq_list[] = {
+	[0] = {
+		.freq_khz	= 2400,
+		.val		= 7,
+	},
+	[1] = {
+		.freq_khz	= 2100,
+		.val		= 8,
+	},
+	[2] = {
+		.freq_khz	= 1600,
+		.val		= 11,
+	},
+	[3] = {
+		.freq_khz	= 1200,
+		.val		= 15,
+	},
+};
+
+int smblib_set_chg_freq(struct smb_chg_param *param,
+				int val_u, u8 *val_raw)
+{
+	u8 i;
+
+	if (val_u > param->max_u || val_u < param->min_u)
+		return -EINVAL;
+
+	/* Charger FSW is the configured freqency / 2 */
+	val_u *= 2;
+	for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
+		if (chg_freq_list[i].freq_khz == val_u)
+			break;
+	}
+	if (i == ARRAY_SIZE(chg_freq_list)) {
+		pr_err("Invalid frequency %d Hz\n", val_u / 2);
+		return -EINVAL;
+	}
+
+	*val_raw = chg_freq_list[i].val;
+
+	return 0;
+}
 
 int smblib_set_opt_switcher_freq(struct smb_charger *chg, int fsw_khz)
 {
@@ -316,11 +378,15 @@
 		if (rc < 0)
 			return -EINVAL;
 	} else {
-		if (val_u > param->max_u || val_u < param->min_u) {
-			smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
+		if (val_u > param->max_u || val_u < param->min_u)
+			smblib_dbg(chg, PR_MISC,
+				"%s: %d is out of range [%d, %d]\n",
 				param->name, val_u, param->min_u, param->max_u);
-			return -EINVAL;
-		}
+
+		if (val_u > param->max_u)
+			val_u = param->max_u;
+		if (val_u < param->min_u)
+			val_u = param->min_u;
 
 		val_raw = (val_u - param->min_u) / param->step_u;
 	}
@@ -771,69 +837,46 @@
 int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
 {
 	int rc = 0;
-	bool override;
+	bool hc_mode = false;
 
 	/* suspend and return if 25mA or less is requested */
 	if (icl_ua <= USBIN_25MA)
 		return smblib_set_usb_suspend(chg, true);
 
 	if (icl_ua == INT_MAX)
-		goto override_suspend_config;
+		goto set_mode;
 
 	/* configure current */
-	if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+	if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
+		|| (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
 		&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
 		rc = set_sdp_current(chg, icl_ua);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
-			goto enable_icl_changed_interrupt;
+			goto out;
 		}
 	} else {
 		set_sdp_current(chg, 100000);
 		rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
-			goto enable_icl_changed_interrupt;
+			goto out;
 		}
+		hc_mode = true;
 	}
 
-override_suspend_config:
-	/* determine if override needs to be enforced */
-	override = true;
-	if (icl_ua == INT_MAX) {
-		/* remove override if no voters - hw defaults is desired */
-		override = false;
-	} else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-		if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
-			/* For std cable with type = SDP never override */
-			override = false;
-		else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
-			&& icl_ua == 1500000)
-			/*
-			 * For std cable with type = CDP override only if
-			 * current is not 1500mA
-			 */
-			override = false;
-	}
-
-	/* enforce override */
+set_mode:
 	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
-		USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
-
-	rc = smblib_icl_override(chg, override);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
-		goto enable_icl_changed_interrupt;
-	}
+		USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
 
 	/* unsuspend after configuring current and override */
 	rc = smblib_set_usb_suspend(chg, false);
 	if (rc < 0) {
 		smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
-		goto enable_icl_changed_interrupt;
+		goto out;
 	}
 
-enable_icl_changed_interrupt:
+out:
 	return rc;
 }
 
@@ -844,7 +887,7 @@
 	bool override;
 
 	if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
-		|| chg->micro_usb_mode)
+		|| chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 		&& (chg->usb_psy->desc->type == POWER_SUPPLY_TYPE_USB)) {
 		rc = get_sdp_current(chg, icl_ua);
 		if (rc < 0) {
@@ -881,6 +924,9 @@
 {
 	struct smb_charger *chg = data;
 
+	if (chg->smb_version == PMI632_SUBTYPE)
+		return 0;
+
 	/* resume input if suspend is invalid */
 	if (suspend < 0)
 		suspend = 0;
@@ -1523,6 +1569,18 @@
 	return rc;
 }
 
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+	int rc;
+
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
 int smblib_dp_dm(struct smb_charger *chg, int val)
 {
 	int target_icl_ua, rc = 0;
@@ -1573,6 +1631,21 @@
 		smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
 				target_icl_ua, chg->usb_icl_delta_ua);
 		break;
+	case POWER_SUPPLY_DP_DM_FORCE_5V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 5V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_9V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 9V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_12V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 12V\n");
+		break;
 	case POWER_SUPPLY_DP_DM_ICL_UP:
 	default:
 		break;
@@ -1699,8 +1772,13 @@
 {
 	switch (chg->real_charger_type) {
 	case POWER_SUPPLY_TYPE_USB_HVDCP:
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
 	case POWER_SUPPLY_TYPE_USB_PD:
-		val->intval = MICRO_12V;
+		if (chg->smb_version == PMI632_SUBTYPE)
+			val->intval = MICRO_9V;
+		else
+			val->intval = MICRO_12V;
+		break;
 	default:
 		val->intval = MICRO_5V;
 		break;
@@ -2053,7 +2131,7 @@
 }
 
 int smblib_set_prop_boost_current(struct smb_charger *chg,
-				    const union power_supply_propval *val)
+					const union power_supply_propval *val)
 {
 	int rc = 0;
 
@@ -2076,6 +2154,9 @@
 	int rc = 0;
 	u8 power_role;
 
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		return 0;
+
 	switch (val->intval) {
 	case POWER_SUPPLY_TYPEC_PR_NONE:
 		power_role = TYPEC_DISABLE_CMD_BIT;
@@ -2513,7 +2594,7 @@
 	} else {
 		chg->typec_present = 0;
 		smblib_update_usb_type(chg);
-		extcon_set_state_sync(chg->extcon, EXTCON_USB, false);
+		smblib_notify_device_mode(chg, false);
 		smblib_uusb_removal(chg);
 	}
 }
@@ -2601,7 +2682,7 @@
 			smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
 	}
 
-	if (chg->micro_usb_mode)
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 		smblib_micro_usb_plugin(chg, vbus_rising);
 
 	power_supply_changed(chg->usb_psy);
@@ -2763,37 +2844,6 @@
 		   rising ? "rising" : "falling");
 }
 
-static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
-{
-	union extcon_property_value val;
-	union power_supply_propval prop_val;
-
-	smblib_get_prop_typec_cc_orientation(chg, &prop_val);
-	val.intval = ((prop_val.intval == 2) ? 1 : 0);
-	extcon_set_property(chg->extcon, id,
-				EXTCON_PROP_USB_TYPEC_POLARITY, val);
-
-	val.intval = true;
-	extcon_set_property(chg->extcon, id,
-				EXTCON_PROP_USB_SS, val);
-}
-
-static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
-{
-	if (enable)
-		smblib_notify_extcon_props(chg, EXTCON_USB);
-
-	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
-}
-
-static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
-{
-	if (enable)
-		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
-
-	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
-}
-
 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
 {
 	const struct apsd_result *apsd_result;
@@ -2806,13 +2856,11 @@
 	switch (apsd_result->bit) {
 	case SDP_CHARGER_BIT:
 	case CDP_CHARGER_BIT:
-		if (chg->micro_usb_mode)
-			extcon_set_state_sync(chg->extcon, EXTCON_USB,
-					true);
 		/* if not DCP then no hvdcp timeout happens. Enable pd here */
 		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
 				false, 0);
-		if (chg->use_extcon)
+		if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+				|| chg->use_extcon)
 			smblib_notify_device_mode(chg, true);
 		break;
 	case OCP_CHARGER_BIT:
@@ -2845,8 +2893,9 @@
 	}
 	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
 
-	if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
-			&& !chg->uusb_apsd_rerun_done) {
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		&& (stat & APSD_DTC_STATUS_DONE_BIT)
+		&& !chg->uusb_apsd_rerun_done) {
 		/*
 		 * Force re-run APSD to handle slow insertion related
 		 * charger-mis-detection.
@@ -3146,12 +3195,12 @@
 	power_supply_changed(chg->usb_psy);
 }
 
-irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
 {
 	struct smb_irq_data *irq_data = data;
 	struct smb_charger *chg = irq_data->parent_data;
 
-	if (chg->micro_usb_mode) {
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
 		cancel_delayed_work_sync(&chg->uusb_otg_work);
 		vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
 		smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
@@ -3160,7 +3209,16 @@
 		return IRQ_HANDLED;
 	}
 
-	if (chg->pr_swap_in_progress) {
+	return IRQ_HANDLED;
+}
+
+irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			|| chg->pr_swap_in_progress) {
 		smblib_dbg(chg, PR_INTERRUPT,
 				"Ignoring since pr_swap_in_progress\n");
 		return IRQ_HANDLED;
@@ -3335,10 +3393,20 @@
 		smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
 		goto out;
 	}
+	otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
+	if (chg->otg_present != otg)
+		smblib_notify_usb_host(chg, otg);
+	chg->otg_present = otg;
+	if (!otg)
+		chg->boost_current_ua = 0;
 
-	otg = !!(stat & (U_USB_GROUND_NOVBUS_BIT | U_USB_GROUND_BIT));
-	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, otg);
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+				otg ? chg->chg_freq.freq_below_otg_threshold
+					: chg->chg_freq.freq_removal);
+	if (rc < 0)
+		dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_U_USB_STATUS = 0x%02x OTG=%d\n",
 			stat, otg);
 	power_supply_changed(chg->usb_psy);
 
@@ -3559,13 +3627,6 @@
 			return rc;
 		}
 
-		rc = smblib_register_notifier(chg);
-		if (rc < 0) {
-			smblib_err(chg,
-				"Couldn't register notifier rc=%d\n", rc);
-			return rc;
-		}
-
 		chg->bms_psy = power_supply_get_by_name("bms");
 		chg->pl.psy = power_supply_get_by_name("parallel");
 		if (chg->pl.psy) {
@@ -3576,6 +3637,12 @@
 				return rc;
 			}
 		}
+		rc = smblib_register_notifier(chg);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't register notifier rc=%d\n", rc);
+			return rc;
+		}
 		break;
 	case PARALLEL_SLAVE:
 		break;
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 8633ba0..fa7381c 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -196,6 +196,11 @@
 				    u8 *val_raw);
 };
 
+struct buck_boost_freq {
+	int freq_khz;
+	u8 val;
+};
+
 struct smb_chg_freq {
 	unsigned int		freq_5V;
 	unsigned int		freq_6V_8V;
@@ -311,7 +316,7 @@
 	bool			sw_jeita_enabled;
 	bool			is_hdc;
 	bool			chg_done;
-	bool			micro_usb_mode;
+	int			connector_type;
 	bool			otg_en;
 	bool			suspend_input_on_debug_batt;
 	int			otg_attempts;
@@ -329,6 +334,7 @@
 	u8			float_cfg;
 	bool			use_extcon;
 	bool			otg_present;
+	int			hw_max_icl_ua;
 
 	/* workaround flag */
 	u32			wa_flags;
@@ -369,6 +375,8 @@
 					     int val_u, u8 *val_raw);
 int smblib_set_chg_freq(struct smb_chg_param *param,
 				int val_u, u8 *val_raw);
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+				const union power_supply_propval *val);
 int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
 int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
 int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);
@@ -390,6 +398,7 @@
 irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
 irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
 irqreturn_t wdog_bark_irq_handler(int irq, void *data);
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
 
 int smblib_get_prop_input_suspend(struct smb_charger *chg,
 				union power_supply_propval *val);
@@ -470,8 +479,6 @@
 				const union power_supply_propval *val);
 int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
 				const union power_supply_propval *val);
-int smblib_set_prop_boost_current(struct smb_charger *chg,
-				const union power_supply_propval *val);
 int smblib_set_prop_typec_power_role(struct smb_charger *chg,
 				const union power_supply_propval *val);
 int smblib_set_prop_pd_active(struct smb_charger *chg,
@@ -484,7 +491,6 @@
 int smblib_rerun_apsd_if_required(struct smb_charger *chg);
 int smblib_get_prop_fcc_delta(struct smb_charger *chg,
 				union power_supply_propval *val);
-int smblib_icl_override(struct smb_charger *chg, bool override);
 int smblib_dp_dm(struct smb_charger *chg, int val);
 int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
 int smblib_rerun_aicl(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index 1534f7c..9a418c8 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -178,6 +178,8 @@
 #define APSD_RERUN_BIT				BIT(0)
 
 #define CMD_HVDCP_2_REG				(USBIN_BASE + 0x43)
+#define FORCE_12V_BIT				BIT(5)
+#define FORCE_9V_BIT				BIT(4)
 #define FORCE_5V_BIT				BIT(3)
 #define SINGLE_DECREMENT_BIT			BIT(1)
 #define SINGLE_INCREMENT_BIT			BIT(0)
@@ -196,6 +198,7 @@
 };
 
 #define USBIN_OPTIONS_1_CFG_REG			(USBIN_BASE + 0x62)
+#define HVDCP_AUTH_ALG_EN_CFG_BIT		BIT(6)
 #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT	BIT(5)
 #define BC1P2_SRC_DETECT_BIT			BIT(3)
 
@@ -299,6 +302,8 @@
 #define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
 #define EN_MICRO_USB_MODE_BIT			BIT(0)
 
+#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x70)
+#define MICRO_USB_MODE_ONLY_BIT			BIT(0)
 /********************************
  *  MISC Peripheral Registers  *
  ********************************/
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 2800607..115a9b7 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -773,12 +773,34 @@
 	return ldo_vreg->vreg_enabled;
 }
 
+/**
+ * msm_gfx_ldo_list_corner_voltage() - return the ldo voltage mapped to
+ *			the specified voltage corner
+ * @rdev:		Regulator device pointer for the msm_gfx_ldo
+ * @corner:		Voltage corner
+ *
+ * Return: voltage value in microvolts or -EINVAL if the corner is out of range
+ */
+static int msm_gfx_ldo_list_corner_voltage(struct regulator_dev *rdev,
+		int corner)
+{
+	struct msm_gfx_ldo *ldo_vreg  = rdev_get_drvdata(rdev);
+
+	corner -= MIN_CORNER_OFFSET;
+
+	if (corner >= 0 && corner < ldo_vreg->num_corners)
+		return ldo_vreg->open_loop_volt[corner];
+	else
+		return -EINVAL;
+}
+
 static struct regulator_ops msm_gfx_ldo_corner_ops = {
-	.enable		= msm_gfx_ldo_corner_enable,
-	.disable	= msm_gfx_ldo_disable,
-	.is_enabled	= msm_gfx_ldo_is_enabled,
-	.set_voltage	= msm_gfx_ldo_set_corner,
-	.get_voltage	= msm_gfx_ldo_get_corner,
+	.enable			= msm_gfx_ldo_corner_enable,
+	.disable		= msm_gfx_ldo_disable,
+	.is_enabled		= msm_gfx_ldo_is_enabled,
+	.set_voltage		= msm_gfx_ldo_set_corner,
+	.get_voltage		= msm_gfx_ldo_get_corner,
+	.list_corner_voltage	= msm_gfx_ldo_list_corner_voltage,
 };
 
 static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c3b2ca8..770f056 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -250,6 +250,17 @@
 	  deadlocks. It does not run during the bootup process, so it will
 	  not catch any early lockups.
 
+config QCOM_WDOG_IPI_ENABLE
+	bool "Qcom WDT pet optimization"
+	depends on QCOM_WATCHDOG_V2
+	default n
+	help
+	  When this option is enabled, watchdog sends IPI to cores in low power
+	  mode also. For power optimizations, by default watchdog don't ping
+	  cores in low power mode at pettime.
+
+	  To track CPUs health on LPM, or on debug builds enable it.
+
 config QPNP_PBS
 	tristate "PBS trigger support for QPNP PMIC"
 	depends on SPMI
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0255761..c882403 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,9 +65,9 @@
 obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
 
 obj-$(CONFIG_MEM_SHARE_QMI_SERVICE)		+= memshare/
+obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 
 obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
 
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 9becb10..da122fc 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -216,7 +216,6 @@
 	bool tx_blocked_signal_sent;
 	struct kthread_work kwork;
 	struct kthread_worker kworker;
-	struct work_struct wakeup_work;
 	struct task_struct *task;
 	struct tasklet_struct tasklet;
 	struct srcu_struct use_ref;
@@ -854,6 +853,39 @@
 }
 
 /**
+ * tx_wakeup_worker() - worker function to wakeup tx blocked thread
+ * @work:	kwork associated with the edge to process commands on.
+ */
+static void tx_wakeup_worker(struct edge_info *einfo)
+{
+	struct glink_transport_if xprt_if = einfo->xprt_if;
+	bool trigger_wakeup = false;
+	bool trigger_resume = false;
+	unsigned long flags;
+
+	if (einfo->in_ssr)
+		return;
+
+	spin_lock_irqsave(&einfo->write_lock, flags);
+	if (fifo_write_avail(einfo)) {
+		if (einfo->tx_blocked_signal_sent)
+			einfo->tx_blocked_signal_sent = false;
+		if (einfo->tx_resume_needed) {
+			einfo->tx_resume_needed = false;
+			trigger_resume = true;
+		}
+	}
+	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
+		trigger_wakeup = true;
+	}
+	spin_unlock_irqrestore(&einfo->write_lock, flags);
+	if (trigger_wakeup)
+		wake_up_all(&einfo->tx_blocked_queue);
+	if (trigger_resume)
+		xprt_if.glink_core_if_ptr->tx_resume(&xprt_if);
+}
+
+/**
  * __rx_worker() - process received commands on a specific edge
  * @einfo:	Edge to process commands on.
  * @atomic_ctx:	Indicates if the caller is in atomic context and requires any
@@ -903,7 +935,7 @@
 
 	if ((atomic_ctx) && ((einfo->tx_resume_needed) ||
 		(waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/
-		schedule_work(&einfo->wakeup_work);
+		tx_wakeup_worker(einfo);
 
 	/*
 	 * Access to the fifo needs to be synchronized, however only the calls
@@ -1211,39 +1243,6 @@
 }
 
 /**
- * tx_wakeup_worker() - worker function to wakeup tx blocked thread
- * @work:	kwork associated with the edge to process commands on.
- */
-static void tx_wakeup_worker(struct work_struct *work)
-{
-	struct edge_info *einfo;
-	bool trigger_wakeup = false;
-	unsigned long flags;
-	int rcu_id;
-
-	einfo = container_of(work, struct edge_info, wakeup_work);
-	rcu_id = srcu_read_lock(&einfo->use_ref);
-	if (einfo->in_ssr) {
-		srcu_read_unlock(&einfo->use_ref, rcu_id);
-		return;
-	}
-	if (einfo->tx_resume_needed && fifo_write_avail(einfo)) {
-		einfo->tx_resume_needed = false;
-		einfo->xprt_if.glink_core_if_ptr->tx_resume(
-						&einfo->xprt_if);
-	}
-	spin_lock_irqsave(&einfo->write_lock, flags);
-	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
-		einfo->tx_blocked_signal_sent = false;
-		trigger_wakeup = true;
-	}
-	spin_unlock_irqrestore(&einfo->write_lock, flags);
-	if (trigger_wakeup)
-		wake_up_all(&einfo->tx_blocked_queue);
-	srcu_read_unlock(&einfo->use_ref, rcu_id);
-}
-
-/**
  * rx_worker() - worker function to process received commands
  * @work:	kwork associated with the edge to process commands on.
  */
@@ -2425,7 +2424,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -2541,7 +2539,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2629,7 +2626,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->intentless = true;
 	einfo->read_from_fifo = memcpy32_fromio;
@@ -2790,7 +2786,6 @@
 reg_xprt_fail:
 toc_init_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2922,7 +2917,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -3043,7 +3037,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index cef3c77..c93e0e1 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -31,6 +31,7 @@
 module_param_named(debug_mask, ipc_router_glink_xprt_debug_mask,
 		   int, 0664);
 
+#define IPCRTR_INTENT_REQ_TIMEOUT_MS 5000
 #if defined(DEBUG)
 #define D(x...) do { \
 if (ipc_router_glink_xprt_debug_mask) \
@@ -43,6 +44,7 @@
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 #define IPC_RTR_XPRT_NAME_LEN (2 * GLINK_NAME_SIZE)
 #define PIL_SUBSYSTEM_NAME_LEN 32
+#define IPC_RTR_WS_NAME_LEN ((2 * GLINK_NAME_SIZE) + 4)
 
 #define MAX_NUM_LO_INTENTS 5
 #define MAX_NUM_MD_INTENTS 3
@@ -59,6 +61,7 @@
  * @transport: Physical Transport Name as identified by Glink.
  * @pil_edge: Edge name understood by PIL.
  * @ipc_rtr_xprt_name: XPRT Name to be registered with IPC Router.
+ * @notify_rx_ws_name: Name of wakesource used in notify rx path.
  * @xprt: IPC Router XPRT structure to contain XPRT specific info.
  * @ch_hndl: Opaque Channel handle returned by GLink.
  * @xprt_wq: Workqueue to queue read & other XPRT related works.
@@ -79,9 +82,11 @@
 	char transport[GLINK_NAME_SIZE];
 	char pil_edge[PIL_SUBSYSTEM_NAME_LEN];
 	char ipc_rtr_xprt_name[IPC_RTR_XPRT_NAME_LEN];
+	char notify_rx_ws_name[IPC_RTR_WS_NAME_LEN];
 	struct msm_ipc_router_xprt xprt;
 	void *ch_hndl;
 	struct workqueue_struct *xprt_wq;
+	struct wakeup_source notify_rxv_ws;
 	struct rw_semaphore ss_reset_rwlock;
 	int ss_reset;
 	void *pil;
@@ -379,6 +384,7 @@
 	glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
 	kfree(rx_work);
 	up_read(&glink_xprtp->ss_reset_rwlock);
+	__pm_relax(&glink_xprtp->notify_rxv_ws);
 }
 
 static void glink_xprt_open_event(struct work_struct *work)
@@ -493,6 +499,8 @@
 	rx_work->iovec_size = size;
 	rx_work->vbuf_provider = vbuf_provider;
 	rx_work->pbuf_provider = pbuf_provider;
+	if (!glink_xprtp->dynamic_wakeup_source)
+		__pm_stay_awake(&glink_xprtp->notify_rxv_ws);
 	INIT_WORK(&rx_work->work, glink_xprt_read_data);
 	queue_work(glink_xprtp->xprt_wq, &rx_work->work);
 }
@@ -602,6 +610,7 @@
 	open_cfg.notify_state = glink_xprt_notify_state;
 	open_cfg.notify_rx_intent_req = glink_xprt_notify_rx_intent_req;
 	open_cfg.priv = glink_xprtp;
+	open_cfg.rx_intent_req_timeout_ms = IPCRTR_INTENT_REQ_TIMEOUT_MS;
 
 	glink_xprtp->pil = msm_ipc_load_subsystem(glink_xprtp);
 	glink_xprtp->ch_hndl =  glink_open(&open_cfg);
@@ -760,7 +769,10 @@
 		kfree(glink_xprtp);
 		return -EFAULT;
 	}
-
+	scnprintf(glink_xprtp->notify_rx_ws_name, IPC_RTR_WS_NAME_LEN,
+			"%s_%s_rx", glink_xprtp->ch_name, glink_xprtp->edge);
+	wakeup_source_init(&glink_xprtp->notify_rxv_ws,
+				glink_xprtp->notify_rx_ws_name);
 	mutex_lock(&glink_xprt_list_lock_lha1);
 	list_add(&glink_xprtp->list, &glink_xprt_list);
 	mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index 4a41eee..a4d59f4 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -697,8 +697,10 @@
 
 	centry = &stats->child;
 	list_for_each_entry_reverse(pos, centry, sibling) {
-		if (!list_empty(&pos->child))
+		if (!list_empty(&pos->child)) {
 			cleanup_stats(pos);
+			continue;
+		}
 
 		list_del_init(&pos->child);
 
diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c
index 2c379a0..bc665fd 100644
--- a/drivers/soc/qcom/rpmh_master_stat.c
+++ b/drivers/soc/qcom/rpmh_master_stat.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
@@ -13,21 +13,25 @@
 
 #define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
 
-#include <linux/debugfs.h>
-#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/uaccess.h>
 #include <soc/qcom/smem.h>
+#include "rpmh_master_stat.h"
+
+#define UNIT_DIST 0x14
+#define REG_VALID 0x0
+#define REG_DATA_LO 0x4
+#define REG_DATA_HI 0x8
+
+#define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO))
 
 enum master_smem_id {
 	MPSS = 605,
@@ -48,6 +52,14 @@
 	PID_DISPLAY = PID_APSS,
 };
 
+enum profile_data {
+	POWER_DOWN_START,
+	POWER_UP_END,
+	POWER_DOWN_END,
+	POWER_UP_START,
+	NUM_UNIT,
+};
+
 struct msm_rpmh_master_data {
 	char *master_name;
 	enum master_smem_id smem_id;
@@ -66,16 +78,24 @@
 struct msm_rpmh_master_stats {
 	uint32_t version_id;
 	uint32_t counts;
-	uint64_t last_entered_at;
-	uint64_t last_exited_at;
+	uint64_t last_entered;
+	uint64_t last_exited;
 	uint64_t accumulated_duration;
 };
 
+struct msm_rpmh_profile_unit {
+	uint64_t value;
+	uint64_t valid;
+};
+
 struct rpmh_master_stats_prv_data {
 	struct kobj_attribute ka;
 	struct kobject *kobj;
 };
 
+static struct msm_rpmh_master_stats apss_master_stats;
+static void __iomem *rpmh_unit_base;
+
 static DEFINE_MUTEX(rpmh_stats_mutex);
 
 static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length,
@@ -88,7 +108,7 @@
 			"\tSleep Last Exited At:0x%llx\n"
 			"\tSleep Accumulated Duration:0x%llx\n\n",
 			name, record->version_id, record->counts,
-			record->last_entered_at, record->last_exited_at,
+			record->last_entered, record->last_exited,
 			record->accumulated_duration);
 }
 
@@ -100,13 +120,16 @@
 	unsigned int size = 0;
 	struct msm_rpmh_master_stats *record = NULL;
 
-	/*
-	 * Read SMEM data written by masters
-	 */
-
 	mutex_lock(&rpmh_stats_mutex);
 
-	for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
+	/* First Read APSS master stats */
+
+	length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE,
+						&apss_master_stats, "APSS");
+
+	/* Read SMEM data written by other masters */
+
+	for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
 		record = (struct msm_rpmh_master_stats *) smem_get_entry(
 					rpmh_masters[i].smem_id, &size,
 					rpmh_masters[i].pid, 0);
@@ -122,30 +145,66 @@
 	return length;
 }
 
+static inline void msm_rpmh_apss_master_stats_update(
+				struct msm_rpmh_profile_unit *profile_unit)
+{
+	apss_master_stats.counts++;
+	apss_master_stats.last_entered = profile_unit[POWER_DOWN_END].value;
+	apss_master_stats.last_exited = profile_unit[POWER_UP_START].value;
+	apss_master_stats.accumulated_duration +=
+					(apss_master_stats.last_exited
+					- apss_master_stats.last_entered);
+}
+
+void msm_rpmh_master_stats_update(void)
+{
+	int i;
+	struct msm_rpmh_profile_unit profile_unit[NUM_UNIT];
+
+	if (!rpmh_unit_base)
+		return;
+
+	for (i = POWER_DOWN_END; i < NUM_UNIT; i++) {
+		profile_unit[i].valid = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_VALID, i));
+
+		/*
+		 * Do not update APSS stats if valid bit is not set.
+		 * It means APSS did not execute cx-off sequence.
+		 * This can be due to fall through at some point.
+		 */
+
+		if (!(profile_unit[i].valid & BIT(REG_VALID)))
+			return;
+
+		profile_unit[i].value = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_DATA_LO, i));
+		profile_unit[i].value |= ((uint64_t)
+					readl_relaxed(rpmh_unit_base +
+					GET_ADDR(REG_DATA_HI, i)) << 32);
+	}
+	msm_rpmh_apss_master_stats_update(profile_unit);
+}
+EXPORT_SYMBOL(msm_rpmh_master_stats_update);
+
 static int msm_rpmh_master_stats_probe(struct platform_device *pdev)
 {
 	struct rpmh_master_stats_prv_data *prvdata = NULL;
 	struct kobject *rpmh_master_stats_kobj = NULL;
-	int ret = 0;
+	int ret = -ENOMEM;
 
 	if (!pdev)
 		return -EINVAL;
 
-	prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data),
-							GFP_KERNEL);
-	if (!prvdata) {
-		ret = -ENOMEM;
-		goto fail;
-	}
+	prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL);
+	if (!prvdata)
+		return ret;
 
 	rpmh_master_stats_kobj = kobject_create_and_add(
 					"rpmh_stats",
 					power_kobj);
-	if (!rpmh_master_stats_kobj) {
-		ret = -ENOMEM;
-		kfree(prvdata);
-		goto fail;
-	}
+	if (!rpmh_master_stats_kobj)
+		return ret;
 
 	prvdata->kobj = rpmh_master_stats_kobj;
 
@@ -158,14 +217,24 @@
 	ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr);
 	if (ret) {
 		pr_err("sysfs_create_file failed\n");
-		kobject_put(prvdata->kobj);
-		kfree(prvdata);
-		goto fail;
+		goto fail_sysfs;
 	}
 
-	platform_set_drvdata(pdev, prvdata);
+	rpmh_unit_base = of_iomap(pdev->dev.of_node, 0);
+	if (!rpmh_unit_base) {
+		pr_err("Failed to get rpmh_unit_base\n");
+		ret = -ENOMEM;
+		goto fail_iomap;
+	}
 
-fail:
+	apss_master_stats.version_id = 0x1;
+	platform_set_drvdata(pdev, prvdata);
+	return ret;
+
+fail_iomap:
+	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
+fail_sysfs:
+	kobject_put(prvdata->kobj);
 	return ret;
 }
 
@@ -181,14 +250,14 @@
 
 	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
 	kobject_put(prvdata->kobj);
-	kfree(prvdata);
 	platform_set_drvdata(pdev, NULL);
+	iounmap(rpmh_unit_base);
 
 	return 0;
 }
 
 static const struct of_device_id rpmh_master_table[] = {
-	{.compatible = "qcom,rpmh-master-stats"},
+	{.compatible = "qcom,rpmh-master-stats-v1"},
 	{},
 };
 
@@ -197,24 +266,11 @@
 	.remove = msm_rpmh_master_stats_remove,
 	.driver = {
 		.name = "msm_rpmh_master_stats",
-		.owner = THIS_MODULE,
 		.of_match_table = rpmh_master_table,
 	},
 };
 
-static int __init msm_rpmh_master_stats_init(void)
-{
-	return platform_driver_register(&msm_rpmh_master_stats_driver);
-}
-
-static void __exit msm_rpmh_master_stats_exit(void)
-{
-	platform_driver_unregister(&msm_rpmh_master_stats_driver);
-}
-
-module_init(msm_rpmh_master_stats_init);
-module_exit(msm_rpmh_master_stats_exit);
-
+module_platform_driver(msm_rpmh_master_stats_driver);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MSM RPMH Master Statistics driver");
 MODULE_ALIAS("platform:msm_rpmh_master_stat_log");
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/drivers/soc/qcom/rpmh_master_stat.h
similarity index 61%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to drivers/soc/qcom/rpmh_master_stat.h
index 194bfeb..c3fe7dc 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/drivers/soc/qcom/rpmh_master_stat.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -9,16 +9,15 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
+ *
  */
 
-/dts-v1/;
+#if defined(CONFIG_QTI_RPMH_API) && defined(CONFIG_QTI_RPM_STATS_LOG)
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+void msm_rpmh_master_stats_update(void);
 
-/ {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
+#else
 
-};
+static inline void msm_rpmh_master_stats_update(void) {}
+
+#endif
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 685b384..0e83971 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -595,6 +595,10 @@
 	[294] = {MSM_CPU_8937, "MSM8937"},
 	[295] = {MSM_CPU_8937, "APQ8937"},
 
+	/* SDM429 and SDM439 ID*/
+	[353] = {MSM_CPU_SDM439, "SDM439"},
+	[354] = {MSM_CPU_SDM429, "SDM429"},
+
 
 	/* Uninitialized IDs are not known to run Linux.
 	 * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -1535,6 +1539,14 @@
 		dummy_socinfo.id = 349;
 		strlcpy(dummy_socinfo.build_id, "sdm632 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm439()) {
+		dummy_socinfo.id = 353;
+		strlcpy(dummy_socinfo.build_id, "sdm439 - ",
+				sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm429()) {
+		dummy_socinfo.id = 354;
+		strlcpy(dummy_socinfo.build_id, "sdm429 - ",
+				sizeof(dummy_socinfo.build_id));
 	}
 
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 480a33c..30b73db 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -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
@@ -19,6 +19,7 @@
 #include <soc/qcom/system_pm.h>
 
 #include <clocksource/arm_arch_timer.h>
+#include "rpmh_master_stat.h"
 
 #define PDC_TIME_VALID_SHIFT	31
 #define PDC_TIME_UPPER_MASK	0xFFFFFF
@@ -76,6 +77,7 @@
  */
 void system_sleep_exit(void)
 {
+	msm_rpmh_master_stats_update();
 }
 EXPORT_SYMBOL(system_sleep_exit);
 
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index 6d58d6b..8040d6d 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -112,12 +112,22 @@
 module_param(WDT_HZ, long, 0);
 
 /*
+ * Watchdog ipi optimization:
+ * Does not ping cores in low power mode at pet time to save power.
+ * This feature is enabled by default.
+ *
  * On the kernel command line specify
- * watchdog_v2.ipi_opt_en=1 to enable the watchdog ipi ping
- * optimization. By default it is turned off
+ * watchdog_v2.ipi_en=1 to disable this optimization.
+ * Or, can be turned off, by enabling CONFIG_QCOM_WDOG_IPI_ENABLE.
  */
-static int ipi_opt_en;
-module_param(ipi_opt_en, int, 0);
+#ifdef CONFIG_QCOM_WDOG_IPI_ENABLE
+#define IPI_CORES_IN_LPM 1
+#else
+#define IPI_CORES_IN_LPM 0
+#endif
+
+static int ipi_en = IPI_CORES_IN_LPM;
+module_param(ipi_en, int, 0444);
 
 static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
 {
@@ -463,7 +473,7 @@
 	struct msm_watchdog_data *wdog_dd =
 			(struct msm_watchdog_data *)platform_get_drvdata(pdev);
 
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_unregister_notifier(&wdog_cpu_pm_nb);
 
 	mutex_lock(&wdog_dd->disable_lock);
@@ -709,7 +719,7 @@
 
 	if (wdog_dd->irq_ppi)
 		enable_percpu_irq(wdog_dd->bark_irq, 0);
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_register_notifier(&wdog_cpu_pm_nb);
 	dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
 }
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 83b46d4..a1602e4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -510,17 +510,36 @@
 		if (test_task_flag(tsk, TIF_MM_RELEASED))
 			continue;
 
-		if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
-			if (test_task_lmk_waiting(tsk)) {
-				rcu_read_unlock();
-				mutex_unlock(&scan_mutex);
-				return 0;
-			}
-		}
+		if (oom_reaper) {
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
 
-		p = find_lock_task_mm(tsk);
-		if (!p)
-			continue;
+			if (test_bit(MMF_OOM_VICTIM, &p->mm->flags)) {
+				if (test_bit(MMF_OOM_SKIP, &p->mm->flags)) {
+					task_unlock(p);
+					continue;
+				} else if (time_before_eq(jiffies,
+						lowmem_deathpending_timeout)) {
+					task_unlock(p);
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+			}
+		} else {
+			if (time_before_eq(jiffies,
+					   lowmem_deathpending_timeout))
+				if (test_task_lmk_waiting(tsk)) {
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
+		}
 
 		oom_score_adj = p->signal->oom_score_adj;
 		if (oom_score_adj < min_score_adj) {
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 27bf54b..1259654 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
+obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9e96f8a..2c4a63a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -237,11 +237,17 @@
 	case PM_POST_RESTORE:
 	case PM_POST_SUSPEND:
 		mutex_lock(&cooling_list_lock);
-		mutex_lock(&core_isolate_lock);
 		list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+			mutex_lock(&core_isolate_lock);
 			if (cpufreq_dev->cpufreq_state ==
 				cpufreq_dev->max_level) {
 				cpu = cpumask_any(&cpufreq_dev->allowed_cpus);
+				/*
+				 * Unlock this lock before calling
+				 * schedule_isolate. as this could lead to
+				 * deadlock with hotplug path.
+				 */
+				mutex_unlock(&core_isolate_lock);
 				if (cpu_online(cpu) &&
 					!cpumask_test_and_set_cpu(cpu,
 					&cpus_isolated_by_thermal)) {
@@ -249,9 +255,10 @@
 						cpumask_clear_cpu(cpu,
 						&cpus_isolated_by_thermal);
 				}
+				continue;
 			}
+			mutex_unlock(&core_isolate_lock);
 		}
-		mutex_unlock(&core_isolate_lock);
 		mutex_unlock(&cooling_list_lock);
 
 		atomic_set(&in_suspend, 0);
@@ -727,6 +734,7 @@
 	mutex_lock(&core_isolate_lock);
 	prev_state = cpufreq_device->cpufreq_state;
 	cpufreq_device->cpufreq_state = state;
+	mutex_unlock(&core_isolate_lock);
 	/* If state is the last, isolate the CPU */
 	if (state == cpufreq_device->max_level) {
 		if (cpu_online(cpu) &&
@@ -736,18 +744,11 @@
 				cpumask_clear_cpu(cpu,
 					&cpus_isolated_by_thermal);
 		}
-		mutex_unlock(&core_isolate_lock);
 		return ret;
 	} else if ((prev_state == cpufreq_device->max_level)
 			&& (state < cpufreq_device->max_level)) {
 		if (cpumask_test_and_clear_cpu(cpu, &cpus_pending_online)) {
 			cpu_dev = get_cpu_device(cpu);
-			mutex_unlock(&core_isolate_lock);
-			/*
-			 * Unlock before calling the device_online.
-			 * Else, this will lead to deadlock, since the hp
-			 * online callback will be blocked on this mutex.
-			 */
 			ret = device_online(cpu_dev);
 			if (ret)
 				pr_err("CPU:%d online error:%d\n", cpu, ret);
@@ -757,7 +758,6 @@
 			sched_unisolate_cpu(cpu);
 		}
 	}
-	mutex_unlock(&core_isolate_lock);
 update_frequency:
 	clip_freq = cpufreq_device->freq_table[state];
 	cpufreq_device->clipped_freq = clip_freq;
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index fe0a7c7..c137d3d 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.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
@@ -49,6 +49,11 @@
 	return tmdev->ops->hw_init(tmdev);
 }
 
+static int tsens_calib(struct tsens_device *tmdev)
+{
+	return tmdev->ops->calibrate(tmdev);
+}
+
 static int tsens_register_interrupts(struct tsens_device *tmdev)
 {
 	if (tmdev->ops->interrupts_reg)
@@ -82,6 +87,9 @@
 	{	.compatible = "qcom,tsens24xx",
 		.data = &data_tsens24xx,
 	},
+	{	.compatible = "qcom,msm8937-tsens",
+		.data = &data_tsens14xx,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, tsens_table);
@@ -97,6 +105,7 @@
 	struct device_node *of_node = pdev->dev.of_node;
 	const struct of_device_id *id;
 	const struct tsens_data *data;
+	int rc = 0;
 	struct resource *res_tsens_mem;
 
 	if (!of_match_node(tsens_table, of_node)) {
@@ -150,7 +159,27 @@
 		return PTR_ERR(tmdev->tsens_tm_addr);
 	}
 
-	return 0;
+	/* TSENS eeprom register region */
+	res_tsens_mem = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tsens_eeprom_physical");
+	if (!res_tsens_mem) {
+		pr_debug("Could not get tsens physical address resource\n");
+	} else {
+		tmdev->tsens_calib_addr = devm_ioremap_resource(&pdev->dev,
+								res_tsens_mem);
+		if (IS_ERR(tmdev->tsens_calib_addr)) {
+			dev_err(&pdev->dev, "Failed to IO map TSENS EEPROM registers.\n");
+			rc = PTR_ERR(tmdev->tsens_calib_addr);
+		}  else {
+			rc = tsens_calib(tmdev);
+			if (rc) {
+				pr_err("Error initializing TSENS controller\n");
+				return rc;
+			}
+		}
+	}
+
+	return rc;
 }
 
 static int tsens_thermal_zone_register(struct tsens_device *tmdev)
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ae4741d..885b15c 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -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
@@ -23,10 +23,15 @@
 
 #define DEBUG_SIZE				10
 #define TSENS_MAX_SENSORS			16
+#define TSENS_1x_MAX_SENSORS			11
 #define TSENS_CONTROLLER_ID(n)			(n)
 #define TSENS_CTRL_ADDR(n)			(n)
 #define TSENS_TM_SN_STATUS(n)			((n) + 0xa0)
 
+#define ONE_PT_CALIB		0x1
+#define ONE_PT_CALIB2		0x2
+#define TWO_PT_CALIB		0x3
+
 enum tsens_dbg_type {
 	TSENS_DBG_POLL,
 	TSENS_DBG_LOG_TEMP_READS,
@@ -70,6 +75,8 @@
 	int				high_temp;
 	int				low_temp;
 	int				crit_temp;
+	int				high_adc_code;
+	int				low_adc_code;
 };
 
 struct tsens_sensor {
@@ -79,6 +86,8 @@
 	u32				id;
 	const char			*sensor_name;
 	struct tsens_context		thr_state;
+	int				offset;
+	int				slope;
 };
 
 /**
@@ -93,6 +102,7 @@
 	int (*interrupts_reg)(struct tsens_device *);
 	int (*dbg)(struct tsens_device *, u32, u32, int *);
 	int (*sensor_en)(struct tsens_device *, u32);
+	int (*calibrate)(struct tsens_device *);
 };
 
 struct tsens_irqs {
@@ -116,14 +126,15 @@
 	bool				wd_bark;
 	u32				wd_bark_mask;
 	bool				mtc;
+	bool				valid_status_check;
 };
 
 struct tsens_mtc_sysfs {
-	uint32_t	zone_log;
+	u32			zone_log;
 	int			zone_mtc;
 	int			th1;
 	int			th2;
-	uint32_t	zone_hist;
+	u32			zone_hist;
 };
 
 struct tsens_device {
@@ -134,6 +145,7 @@
 	struct regmap_field		*status_field;
 	void __iomem			*tsens_srot_addr;
 	void __iomem			*tsens_tm_addr;
+	void __iomem			*tsens_calib_addr;
 	const struct tsens_ops		*ops;
 	struct tsens_dbg_context	tsens_dbg;
 	spinlock_t			tsens_crit_lock;
@@ -144,6 +156,7 @@
 };
 
 extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern const struct tsens_data data_tsens14xx;
 extern struct list_head tsens_device_list;
 
 #endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
new file mode 100644
index 0000000..e2fad32
--- /dev/null
+++ b/drivers/thermal/tsens1xxx.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 2012-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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+#include "thermal_core.h"
+
+#define TSENS_DRIVER_NAME			"msm-tsens"
+
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n)		(n)
+#define TSENS_INTERRUPT_EN		BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n)	((n) + 0x04)
+#define TSENS_UPPER_STATUS_CLR		BIT(21)
+#define TSENS_LOWER_STATUS_CLR		BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK	0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK	0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT	10
+
+#define TSENS_S0_STATUS_ADDR(n)		((n) + 0x30)
+#define TSENS_SN_ADDR_OFFSET		0x4
+#define TSENS_SN_STATUS_TEMP_MASK	0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS	BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS	BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET			2
+
+#define TSENS_TRDY_MASK			BIT(0)
+
+#define TSENS_SN_STATUS_ADDR(n)	((n) + 0x44)
+#define TSENS_SN_STATUS_VALID		BIT(14)
+#define TSENS_SN_STATUS_VALID_MASK	0x4000
+#define TSENS_TRDY_ADDR(n)		((n) + 0x84)
+
+#define TSENS_CTRL_ADDR(n)		(n)
+#define TSENS_EN				BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0x7ff)
+#define TSENS_TRDY_RDY_MIN_TIME		2000
+#define TSENS_TRDY_RDY_MAX_TIME		2100
+#define TSENS_THRESHOLD_MAX_CODE	0x3ff
+#define TSENS_THRESHOLD_MIN_CODE	0x0
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK	0x000000ff
+#define BASE1_MASK	0xff000000
+#define BASE1_SHIFT	24
+
+#define S0_P1_MASK		0x000001f8
+#define S1_P1_MASK		0x001f8000
+#define S2_P1_MASK_0_4		0xf8000000
+#define S2_P1_MASK_5		0x00000001
+#define S3_P1_MASK		0x00001f80
+#define S4_P1_MASK		0x01f80000
+#define S5_P1_MASK		0x00003f00
+#define S6_P1_MASK		0x03f00000
+#define S7_P1_MASK		0x0000003f
+#define S8_P1_MASK		0x0003f000
+#define S9_P1_MASK		0x0000003f
+#define S10_P1_MASK		0x0003f000
+
+#define S0_P2_MASK		0x00007e00
+#define S1_P2_MASK		0x07e00000
+#define S2_P2_MASK		0x0000007e
+#define S3_P2_MASK		0x0007e000
+#define S4_P2_MASK		0x7e000000
+#define S5_P2_MASK		0x000fc000
+#define S6_P2_MASK		0xfc000000
+#define S7_P2_MASK		0x00000fc0
+#define S8_P2_MASK		0x00fc0000
+#define S9_P2_MASK		0x00000fc0
+#define S10_P2_MASK		0x00fc0000
+
+#define S0_P1_SHIFT     3
+#define S1_P1_SHIFT     15
+#define S2_P1_SHIFT_0_4 27
+#define S2_P1_SHIFT_5   5
+#define S3_P1_SHIFT     7
+#define S4_P1_SHIFT     19
+#define S5_P1_SHIFT     8
+#define S6_P1_SHIFT     20
+#define S8_P1_SHIFT     12
+#define S10_P1_SHIFT    12
+
+#define S0_P2_SHIFT     9
+#define S1_P2_SHIFT     21
+#define S2_P2_SHIFT     1
+#define S3_P2_SHIFT     13
+#define S4_P2_SHIFT     25
+#define S5_P2_SHIFT     14
+#define S6_P2_SHIFT     26
+#define S7_P2_SHIFT     6
+#define S8_P2_SHIFT     18
+#define S9_P2_SHIFT     6
+#define S10_P2_SHIFT    18
+
+#define CAL_SEL_MASK	0x00000007
+
+#define CAL_DEGC_PT1		30
+#define CAL_DEGC_PT2		120
+#define SLOPE_FACTOR		1000
+#define SLOPE_DEFAULT		3200
+
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+			     u32 *p2, u32 mode)
+{
+	int i;
+	int num, den;
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		pr_debug(
+			"sensor%d - data_point1:%#x data_point2:%#x\n",
+			i, p1[i], p2[i]);
+
+		tmdev->sensor[i].slope = SLOPE_DEFAULT;
+		if (mode == TWO_PT_CALIB) {
+			/*
+			 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+			 *	temp_120_degc - temp_30_degc (x2 - x1)
+			 */
+			num = p2[i] - p1[i];
+			num *= SLOPE_FACTOR;
+			den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+			tmdev->sensor[i].slope = num / den;
+		}
+
+		tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+				(CAL_DEGC_PT1 *
+				tmdev->sensor[i].slope);
+		pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+	}
+}
+
+static int code_to_degc(u32 adc_code, const struct tsens_sensor *sensor)
+{
+	int degc, num, den;
+
+	num = (adc_code * SLOPE_FACTOR) - sensor->offset;
+	den = sensor->slope;
+
+	if (num > 0)
+		degc = num + (den / 2);
+	else if (num < 0)
+		degc = num - (den / 2);
+	else
+		degc = num;
+
+	degc /= den;
+
+	return degc;
+}
+
+static int degc_to_code(int degc, const struct tsens_sensor *sensor)
+{
+	int code = ((degc * sensor->slope)
+		+ sensor->offset)/SLOPE_FACTOR;
+
+	if (code > TSENS_THRESHOLD_MAX_CODE)
+		code = TSENS_THRESHOLD_MAX_CODE;
+	else if (code < TSENS_THRESHOLD_MIN_CODE)
+		code = TSENS_THRESHOLD_MIN_CODE;
+	pr_debug("raw_code:0x%x, degc:%d\n",
+			code, degc);
+	return code;
+}
+
+static int calibrate_8937(struct tsens_device *tmdev)
+{
+	int base0 = 0, base1 = 0, i;
+	u32 p1[TSENS_1x_MAX_SENSORS], p2[TSENS_1x_MAX_SENSORS];
+	int mode = 0, tmp = 0;
+	u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+	qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+	qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+	qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+	qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+	qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+	mode = (qfprom_cdata[2] & CAL_SEL_MASK);
+	pr_debug("calibration mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
+		p2[0] = (qfprom_cdata[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+		p2[1] = (qfprom_cdata[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+		p2[2] = (qfprom_cdata[3] & S2_P2_MASK) >> S2_P2_SHIFT;
+		p2[3] = (qfprom_cdata[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+		p2[4] = (qfprom_cdata[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+		p2[5] = (qfprom_cdata[0] & S5_P2_MASK) >> S5_P2_SHIFT;
+		p2[6] = (qfprom_cdata[0] & S6_P2_MASK) >> S6_P2_SHIFT;
+		p2[7] = (qfprom_cdata[1] & S7_P2_MASK) >> S7_P2_SHIFT;
+		p2[8] = (qfprom_cdata[1] & S8_P2_MASK) >> S8_P2_SHIFT;
+		p2[9] = (qfprom_cdata[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+		p2[10] = (qfprom_cdata[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+		/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (qfprom_cdata[0] & BASE0_MASK);
+		p1[0] = (qfprom_cdata[2] & S0_P1_MASK) >> S0_P1_SHIFT;
+		p1[1] = (qfprom_cdata[2] & S1_P1_MASK) >> S1_P1_SHIFT;
+		p1[2] = (qfprom_cdata[2] & S2_P1_MASK_0_4) >> S2_P1_SHIFT_0_4;
+		tmp = (qfprom_cdata[3] & S2_P1_MASK_5) << S2_P1_SHIFT_5;
+		p1[2] |= tmp;
+		p1[3] = (qfprom_cdata[3] & S3_P1_MASK) >> S3_P1_SHIFT;
+		p1[4] = (qfprom_cdata[3] & S4_P1_MASK) >> S4_P1_SHIFT;
+		p1[5] = (qfprom_cdata[0] & S5_P1_MASK) >> S5_P1_SHIFT;
+		p1[6] = (qfprom_cdata[0] & S6_P1_MASK) >> S6_P1_SHIFT;
+		p1[7] = (qfprom_cdata[1] & S7_P1_MASK);
+		p1[8] = (qfprom_cdata[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+		p1[9] = (qfprom_cdata[4] & S9_P1_MASK);
+		p1[10] = (qfprom_cdata[4] & S10_P1_MASK) >> S10_P1_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+
+	return 0;
+}
+
+static int tsens1xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int code;
+	void __iomem *sensor_addr;
+	void __iomem *trdy_addr;
+	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+	bool last_temp_valid = false, last_temp2_valid = false;
+	bool last_temp3_valid = false;
+
+	if (!sensor)
+		return -EINVAL;
+
+	tmdev = sensor->tmdev;
+
+	trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_tm_addr);
+	sensor_addr = TSENS_SN_STATUS_ADDR(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed(sensor_addr +
+			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp = code & TSENS_SN_STATUS_TEMP_MASK;
+
+	if (tmdev->ctrl_data->valid_status_check) {
+		if (code & TSENS_SN_STATUS_VALID)
+			last_temp_valid = true;
+		else {
+			code = readl_relaxed(sensor_addr +
+				(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+			last_temp2 = code & TSENS_SN_STATUS_TEMP_MASK;
+			if (code & TSENS_SN_STATUS_VALID) {
+				last_temp = last_temp2;
+				last_temp2_valid = true;
+			} else {
+				code = readl_relaxed(sensor_addr +
+					(sensor->hw_id <<
+					TSENS_STATUS_ADDR_OFFSET));
+				last_temp3 = code & TSENS_SN_STATUS_TEMP_MASK;
+				if (code & TSENS_SN_STATUS_VALID) {
+					last_temp = last_temp3;
+					last_temp3_valid = true;
+				}
+			}
+		}
+	}
+
+	if ((tmdev->ctrl_data->valid_status_check) &&
+		(!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) {
+		if (last_temp == last_temp2)
+			last_temp = last_temp2;
+		else if (last_temp2 == last_temp3)
+			last_temp = last_temp3;
+	}
+
+	*temp = code_to_degc(last_temp, sensor);
+
+	return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct tsens_sensor *tm_sensor,
+			int trip, enum thermal_device_mode mode)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+	/* clear the interrupt and unmask */
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+
+	switch (trip) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_th_state = mode;
+
+		code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		mask = TSENS_UPPER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_th_state = mode;
+
+		code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		mask = TSENS_LOWER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == THERMAL_DEVICE_DISABLED)
+		writel_relaxed(reg_cntl | mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+			(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	else
+		writel_relaxed(reg_cntl & ~mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+		(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	/* Enable the thresholds */
+	mb();
+
+	return 0;
+}
+
+static int tsens1xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+						int low_temp, int high_temp)
+{
+	unsigned int reg_cntl;
+	unsigned long flags;
+	struct tsens_device *tmdev = NULL;
+	int high_code, low_code, rc = 0;
+
+	if (!tm_sensor)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
+	if (high_temp != INT_MAX) {
+		high_code = degc_to_code(high_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
+							high_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_temp =
+							high_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					 TSENS_SN_ADDR_OFFSET));
+
+		high_code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+		reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | high_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+
+	if (low_temp != INT_MIN) {
+		low_code = degc_to_code(low_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
+							low_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_temp =
+							low_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET));
+
+		reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | low_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+	/* Set trip temperature thresholds */
+	mb();
+
+	if (high_temp != INT_MAX) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip high enable error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip high disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+	if (low_temp != INT_MIN) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip low enable activation error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip low disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	return rc;
+}
+
+static irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status, threshold, temp, th_temp;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_status_ctrl_addr;
+	u32 rc = 0, addr_offset;
+
+	sensor_status_addr = TSENS_SN_STATUS_ADDR(tm->tsens_tm_addr);
+	sensor_status_ctrl_addr =
+		TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_tm_addr);
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		bool upper_thr = false, lower_thr = false;
+
+		if (IS_ERR(tm->sensor[i].tzd))
+			continue;
+
+		rc = tsens1xxx_get_temp(&tm->sensor[i], &temp);
+		if (rc) {
+			pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+			continue;
+		}
+
+		spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		threshold = readl_relaxed(sensor_status_ctrl_addr +
+								addr_offset);
+
+		if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+			writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_UPPER_THRESHOLD_MASK) >>
+					TSENS_UPPER_THRESHOLD_SHIFT,
+					tm->sensor);
+			if (th_temp > temp) {
+				pr_debug("Re-arm high threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_HI,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("high rearm failed");
+			} else {
+				upper_thr = true;
+				tm->sensor[i].thr_state.high_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+
+		if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+			writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_LOWER_THRESHOLD_MASK),
+					tm->sensor);
+			if (th_temp < temp) {
+				pr_debug("Re-arm Low threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_LOW,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("low rearm failed");
+			} else {
+				lower_thr = true;
+				tm->sensor[i].thr_state.low_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+		spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+		if (upper_thr || lower_thr) {
+			pr_debug("sensor:%d trigger temp (%d degC)\n",
+				tm->sensor[i].hw_id,
+				code_to_degc((status &
+				TSENS_SN_STATUS_TEMP_MASK),
+				tm->sensor));
+			of_thermal_handle_trip(tm->sensor[i].tzd);
+		}
+	}
+
+	/* Disable monitoring sensor trip threshold for triggered sensor */
+	mb();
+
+	return IRQ_HANDLED;
+}
+
+static int tsens1xxx_hw_sensor_en(struct tsens_device *tmdev,
+					u32 sensor_id)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val, sensor_en;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+	sensor_en = ((1 << sensor_id) & srot_val);
+
+	return sensor_en;
+}
+
+static int tsens1xxx_hw_init(struct tsens_device *tmdev)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	if (!(srot_val & TSENS_EN)) {
+		pr_err("TSENS device is not enabled\n");
+		return -ENODEV;
+	}
+
+	writel_relaxed(TSENS_INTERRUPT_EN,
+			TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_tm_addr));
+
+	spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+	return 0;
+}
+
+static const struct tsens_irqs tsens1xxx_irqs[] = {
+	{ "tsens-upper-lower", tsens_irq_thread},
+};
+
+static int tsens1xxx_register_interrupts(struct tsens_device *tmdev)
+{
+	struct platform_device *pdev;
+	int i, rc;
+
+	if (!tmdev)
+		return -EINVAL;
+
+	pdev = tmdev->pdev;
+
+	for (i = 0; i < ARRAY_SIZE(tsens1xxx_irqs); i++) {
+		int irq;
+
+		irq = platform_get_irq_byname(pdev, tsens1xxx_irqs[i].name);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return irq;
+		}
+
+		rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				tsens1xxx_irqs[i].handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				tsens1xxx_irqs[i].name, tmdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return rc;
+		}
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+}
+
+static const struct tsens_ops ops_tsens1xxx = {
+	.hw_init		= tsens1xxx_hw_init,
+	.get_temp		= tsens1xxx_get_temp,
+	.set_trips		= tsens1xxx_set_trip_temp,
+	.interrupts_reg		= tsens1xxx_register_interrupts,
+	.sensor_en		= tsens1xxx_hw_sensor_en,
+	.calibrate		= calibrate_8937,
+};
+
+const struct tsens_data data_tsens14xx = {
+	.ops			= &ops_tsens1xxx,
+	.valid_status_check	= true,
+	.mtc			= true,
+};
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 50c847f..af60a4b 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -59,9 +59,11 @@
 #define TSENS_TM_SCALE_DECI_MILLIDEG		100
 #define TSENS_DEBUG_WDOG_TRIGGER_COUNT		5
 #define TSENS_TM_WATCHDOG_LOG(n)		((n) + 0x13c)
-
 #define TSENS_EN				BIT(0)
 #define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0xffff)
+#define TSENS_TM_TRDY(n)			((n) + 0xe4)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE	BIT(3)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT	3
 
 static void msm_tsens_convert_temp(int last_temp, int *temp)
 {
@@ -79,7 +81,7 @@
 {
 	struct tsens_device *tmdev = NULL;
 	unsigned int code;
-	void __iomem *sensor_addr;
+	void __iomem *sensor_addr, *trdy;
 	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
 
 	if (!sensor)
@@ -87,6 +89,14 @@
 
 	tmdev = sensor->tmdev;
 	sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
+	trdy = TSENS_TM_TRDY(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed_no_log(trdy);
+	if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >>
+			TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT)) {
+		pr_err("TSENS device first round not complete0x%x\n", code);
+		return -ENODATA;
+	}
 
 	code = readl_relaxed_no_log(sensor_addr +
 			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..d4c243c 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,6 +11,7 @@
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/ulpi.h>
 #include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "ci13xxx_udc.c"
 
@@ -24,9 +25,13 @@
 	int wake_gpio;
 	int wake_irq;
 	bool wake_irq_state;
+	struct pinctrl *ci13xxx_pinctrl;
+	struct timer_list irq_enable_timer;
+	bool irq_disabled;
 };
 
 static struct ci13xxx_udc_context _udc_ctxt;
+#define IRQ_ENABLE_DELAY	(jiffies + msecs_to_jiffies(1000))
 
 static irqreturn_t msm_udc_irq(int irq, void *data)
 {
@@ -36,6 +41,7 @@
 static void ci13xxx_msm_suspend(void)
 {
 	struct device *dev = _udc->gadget.dev.parent;
+
 	dev_dbg(dev, "ci13xxx_msm_suspend\n");
 
 	if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
@@ -48,6 +54,7 @@
 static void ci13xxx_msm_resume(void)
 {
 	struct device *dev = _udc->gadget.dev.parent;
+
 	dev_dbg(dev, "ci13xxx_msm_resume\n");
 
 	if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
@@ -62,11 +69,27 @@
 	struct ci13xxx *udc = _udc;
 	struct usb_phy *phy = udc->transceiver;
 
-	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		u32 temp;
+
 		usb_phy_io_write(phy,
 				ULPI_MISC_A_VBUSVLDEXT |
 				ULPI_MISC_A_VBUSVLDEXTSEL,
 				ULPI_CLR(ULPI_MISC_A));
+
+		/* Notify LINK of VBUS LOW */
+		temp = readl_relaxed(USB_USBCMD);
+		temp &= ~USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
 }
 
 /* Link power management will reduce power consumption by
@@ -102,9 +125,9 @@
 			ULPI_MISC_A_VBUSVLDEXTSEL,
 			ULPI_SET(ULPI_MISC_A));
 
-		temp = readl_relaxed(USB_GENCONFIG2);
-		temp |= GENCFG2_SESS_VLD_CTRL_EN;
-		writel_relaxed(temp, USB_GENCONFIG2);
+		temp = readl_relaxed(USB_GENCONFIG_2);
+		temp |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+		writel_relaxed(temp, USB_GENCONFIG_2);
 
 		temp = readl_relaxed(USB_USBCMD);
 		temp |= USBCMD_SESS_VLD_CTRL;
@@ -125,10 +148,17 @@
 	struct ci13xxx *udc = _udc;
 	struct usb_phy *phy = udc->transceiver;
 	struct device *dev = udc->gadget.dev.parent;
+	int	temp;
 
 	writel_relaxed(0, USB_AHBBURST);
 	writel_relaxed(0x08, USB_AHBMODE);
 
+	/* workaround for rx buffer collision issue */
+	temp = readl_relaxed(USB_GENCONFIG);
+	temp &= ~GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE;
+	temp &= ~GENCONFIG_ULPI_SERIAL_EN;
+	writel_relaxed(temp, USB_GENCONFIG);
+
 	if (udc->gadget.l1_supported)
 		ci13xxx_msm_set_l1(udc);
 
@@ -149,7 +179,24 @@
 	}
 }
 
-static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
+static void ci13xxx_msm_mark_err_event(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return;
+
+	if (udc->transceiver == NULL)
+		return;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	/* This will trigger hardware reset before next connection */
+	otg->err_event_seen = true;
+}
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned int event)
 {
 	struct device *dev = udc->gadget.dev.parent;
 
@@ -175,13 +222,36 @@
 		dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
 		ci13xxx_msm_resume();
 		break;
-
+	case CI13XXX_CONTROLLER_ERROR_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_ERROR_EVENT received\n");
+		ci13xxx_msm_mark_err_event();
+		break;
+	case CI13XXX_CONTROLLER_UDC_STARTED_EVENT:
+		dev_info(dev,
+			 "CI13XXX_CONTROLLER_UDC_STARTED_EVENT received\n");
+		break;
 	default:
 		dev_dbg(dev, "unknown ci13xxx_udc event\n");
 		break;
 	}
 }
 
+static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
+{
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return false;
+
+	if (udc->transceiver == NULL)
+		return false;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	return (atomic_read(&otg->in_lpm) != 0);
+}
+
+
 static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
 {
 	struct ci13xxx *udc = _udc;
@@ -200,10 +270,10 @@
 				  CI13XXX_REQUIRE_TRANSCEIVER |
 				  CI13XXX_PULLUP_ON_VBUS |
 				  CI13XXX_ZERO_ITC |
-				  CI13XXX_DISABLE_STREAMING |
-				  CI13XXX_IS_OTG,
+				  CI13XXX_DISABLE_STREAMING,
 	.nz_itc			= 0,
 	.notify_event		= ci13xxx_msm_notify_event,
+	.in_lpm                 = ci13xxx_msm_in_lpm,
 };
 
 static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
@@ -211,10 +281,20 @@
 {
 	int wake_irq;
 	int ret;
+	struct pinctrl_state *set_state;
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
 
 	_udc_ctxt.wake_gpio = res->start;
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_active");
+		if (IS_ERR(set_state)) {
+			pr_err("cannot get ci13xxx pinctrl active state\n");
+			return PTR_ERR(set_state);
+		}
+		pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl, set_state);
+	}
 	gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
 	gpio_direction_input(_udc_ctxt.wake_gpio);
 	wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio);
@@ -238,20 +318,42 @@
 
 gpio_free:
 	gpio_free(_udc_ctxt.wake_gpio);
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_sleep");
+		if (IS_ERR(set_state))
+			pr_err("cannot get ci13xxx pinctrl sleep state\n");
+		else
+			pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+					set_state);
+	}
 	_udc_ctxt.wake_gpio = 0;
 	return ret;
 }
 
 static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
 {
+	struct pinctrl_state *set_state;
+
 	dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
 
 	if (_udc_ctxt.wake_gpio) {
 		gpio_free(_udc_ctxt.wake_gpio);
+		if (_udc_ctxt.ci13xxx_pinctrl) {
+			set_state =
+				pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+						"ci13xxx_sleep");
+			if (IS_ERR(set_state))
+				pr_err("cannot get ci13xxx pinctrl sleep state\n");
+			else
+				pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+						set_state);
+		}
 		_udc_ctxt.wake_gpio = 0;
 	}
 }
 
+static void enable_usb_irq_timer_func(unsigned long data);
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -271,6 +373,15 @@
 				1 << (pdata->log2_itc-1);
 
 		is_l1_supported = pdata->l1_supported;
+		/* Set ahb2ahb bypass flag if it is requested. */
+		if (pdata->enable_ahb2ahb_bypass)
+			ci13xxx_msm_udc_driver.flags |=
+				CI13XXX_ENABLE_AHB2AHB_BYPASS;
+
+		/* Clear disable streaming flag if is requested. */
+		if (pdata->enable_streaming)
+			ci13xxx_msm_udc_driver.flags &=
+						~CI13XXX_DISABLE_STREAMING;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -301,6 +412,17 @@
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+	/* Get pinctrl if target uses pinctrl */
+	_udc_ctxt.ci13xxx_pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(_udc_ctxt.ci13xxx_pinctrl)) {
+		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+			ret = PTR_ERR(_udc_ctxt.ci13xxx_pinctrl);
+			goto udc_remove;
+		}
+		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+		_udc_ctxt.ci13xxx_pinctrl = NULL;
+	}
 	if (res) {
 		ret = ci13xxx_msm_install_wake_gpio(pdev, res);
 		if (ret < 0) {
@@ -316,7 +438,11 @@
 		goto gpio_uninstall;
 	}
 
+	setup_timer(&_udc_ctxt.irq_enable_timer, enable_usb_irq_timer_func,
+							(unsigned long)NULL);
+
 	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
@@ -341,6 +467,18 @@
 	return 0;
 }
 
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+	ci13xxx_pullup(&_udc->gadget, 0);
+}
+
+void msm_hw_soft_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+
+	hw_device_reset(udc);
+}
+
 void msm_hw_bam_disable(bool bam_disable)
 {
 	u32 val;
@@ -354,12 +492,52 @@
 	writel_relaxed(val, USB_GENCONFIG);
 }
 
+void msm_usb_irq_disable(bool disable)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	if (_udc_ctxt.irq_disabled == disable) {
+		pr_debug("Interrupt state already disable = %d\n", disable);
+		if (disable)
+			mod_timer(&_udc_ctxt.irq_enable_timer,
+					IRQ_ENABLE_DELAY);
+		spin_unlock_irqrestore(udc->lock, flags);
+		return;
+	}
+
+	if (disable) {
+		disable_irq_nosync(_udc_ctxt.irq);
+		/* start timer here */
+		pr_debug("%s: Disabling interrupts\n", __func__);
+		mod_timer(&_udc_ctxt.irq_enable_timer, IRQ_ENABLE_DELAY);
+		_udc_ctxt.irq_disabled = true;
+
+	} else {
+		pr_debug("%s: Enabling interrupts\n", __func__);
+		del_timer(&_udc_ctxt.irq_enable_timer);
+		enable_irq(_udc_ctxt.irq);
+		_udc_ctxt.irq_disabled = false;
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+}
+
+static void enable_usb_irq_timer_func(unsigned long data)
+{
+	pr_debug("enabling interrupt from timer\n");
+	msm_usb_irq_disable(false);
+}
+
 static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
 	.driver = {
 		.name = "msm_hsusb",
 	},
 	.remove = ci13xxx_msm_remove,
+	.shutdown = ci13xxx_msm_shutdown,
 };
 MODULE_ALIAS("platform:msm_hsusb");
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b8389e2..28aaa1f 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -58,6 +58,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -66,22 +67,17 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/msm_hsusb.h>
-#include <linux/tracepoint.h>
-#include <mach/usb_trace.h>
-#include "ci13xxx_udc.h"
 
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
+#include "ci13xxx_udc.h"
 
 /******************************************************************************
  * DEFINE
  *****************************************************************************/
 
-#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
 #define USB_MAX_TIMEOUT		25 /* 25msec timeout */
 #define EP_PRIME_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
 #define MAX_PRIME_CHECK_RETRY	3 /*Wait for 3sec for EP prime failure */
+#define EXTRA_ALLOCATION_SIZE	256
 
 /* ctrl register bank access */
 static DEFINE_SPINLOCK(udc_lock);
@@ -140,27 +136,12 @@
 	return n ? n-1 : 32;
 }
 
-struct ci13xxx_ebi_err_entry {
-	u32 *usb_req_buf;
-	u32 usb_req_length;
-	u32 ep_info;
-	struct ci13xxx_ebi_err_entry *next;
-};
-
-struct ci13xxx_ebi_err_data {
-	u32 ebi_err_addr;
-	u32 apkt0;
-	u32 apkt1;
-	struct ci13xxx_ebi_err_entry *ebi_err_entry;
-};
-static struct ci13xxx_ebi_err_data *ebi_err_data;
-
 /******************************************************************************
  * HW block
  *****************************************************************************/
 /* register bank descriptor */
 static struct {
-	unsigned      lpm;    /* is LPM? */
+	unsigned int  lpm;    /* is LPM? */
 	void __iomem *abs;    /* bus map offset */
 	void __iomem *cap;    /* bus map offset + CAP offset + CAP data */
 	size_t        size;   /* bank size */
@@ -195,7 +176,7 @@
 #define REMOTE_WAKEUP_DELAY	msecs_to_jiffies(200)
 
 /* maximum number of enpoints: valid only after hw_device_reset() */
-static unsigned hw_ep_max;
+static unsigned int hw_ep_max;
 static void dbg_usb_op_fail(u8 addr, const char *name,
 				const struct ci13xxx_ep *mep);
 /**
@@ -394,17 +375,26 @@
 	struct ci13xxx *udc = _udc;
 
 	if (dma) {
-		if (streaming || !(udc->udc_driver->flags &
-				CI13XXX_DISABLE_STREAMING))
+		if (!(udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)) {
 			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
-		else
+			pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+				 __func__, hw_cread(CAP_USBMODE, ~0));
+
+		} else {
 			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+			pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+				__func__, hw_cread(CAP_USBMODE, ~0));
+		}
 
 		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
 
-		if (udc->udc_driver->notify_event)
-			udc->udc_driver->notify_event(udc,
-				CI13XXX_CONTROLLER_CONNECT_EVENT);
+
+		/* Set BIT(31) to enable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+			pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
 
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_cwrite(CAP_USBINTR, ~0,
@@ -413,6 +403,12 @@
 	} else {
 		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
 		hw_cwrite(CAP_USBINTR, ~0, 0);
+		/* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+			pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
 	}
 	return 0;
 }
@@ -469,6 +465,10 @@
 					dir ? "IN" : "OUT");
 				debug_ept_flush_info(num, dir);
 				_udc->skip_flush = true;
+				/* Notify to trigger h/w reset recovery later */
+				if (_udc->udc_driver->notify_event)
+					_udc->udc_driver->notify_event(_udc,
+						CI13XXX_CONTROLLER_ERROR_EVENT);
 				return 0;
 			}
 		}
@@ -716,7 +716,7 @@
  */
 static size_t hw_register_read(u32 *buf, size_t size)
 {
-	unsigned i;
+	unsigned int i;
 
 	if (size > hw_bank.size)
 		size = hw_bank.size;
@@ -827,9 +827,6 @@
 	/* ESS flushes only at end?!? */
 	hw_cwrite(CAP_ENDPTFLUSH,    ~0, ~0);   /* flush all EPs */
 
-	/* clear setup token semaphores */
-	hw_cwrite(CAP_ENDPTSETUPSTAT, 0,  0);   /* writes its content */
-
 	/* clear complete status */
 	hw_cwrite(CAP_ENDPTCOMPLETE,  0,  0);   /* writes its content */
 
@@ -841,8 +838,10 @@
 
 	/* reset all endpoints ? */
 
-	/* reset internal status and wait for further instructions
-	   no need to verify the port reset status (ESS does it) */
+	/*
+	 * reset internal status and wait for further instructions
+	 * no need to verify the port reset status (ESS does it)
+	 */
 
 	return 0;
 }
@@ -862,7 +861,7 @@
 	struct usb_gadget *gadget = &udc->gadget;
 	int n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -890,7 +889,7 @@
 
 	return n;
 }
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+static DEVICE_ATTR(device, 0400, show_device, NULL);
 
 /**
  * show_driver: prints information about attached gadget (if any)
@@ -904,7 +903,7 @@
 	struct usb_gadget_driver *driver = udc->driver;
 	int n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -921,7 +920,7 @@
 
 	return n;
 }
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+static DEVICE_ATTR(driver, 0400, show_driver, NULL);
 
 /* Maximum event message length */
 #define DBG_DATA_MSG   64UL
@@ -931,10 +930,10 @@
 
 /* Event buffer descriptor */
 static struct {
-	char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
-	unsigned idx;   /* index */
-	unsigned tty;   /* print to console? */
-	rwlock_t lck;   /* lock */
+	char		(buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned int	idx;   /* index */
+	unsigned int	tty;   /* print to console? */
+	rwlock_t	lck;   /* lock */
 } dbg_data = {
 	.idx = 0,
 	.tty = 0,
@@ -945,7 +944,7 @@
  * dbg_dec: decrements debug event index
  * @idx: buffer index
  */
-static void dbg_dec(unsigned *idx)
+static void dbg_dec(unsigned int *idx)
 {
 	*idx = (*idx - 1) & (DBG_DATA_MAX-1);
 }
@@ -954,16 +953,16 @@
  * dbg_inc: increments debug event index
  * @idx: buffer index
  */
-static void dbg_inc(unsigned *idx)
+static void dbg_inc(unsigned int *idx)
 {
 	*idx = (*idx + 1) & (DBG_DATA_MAX-1);
 }
 
 
 static unsigned int ep_addr_txdbg_mask;
-module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
+module_param(ep_addr_txdbg_mask, uint, 0644);
 static unsigned int ep_addr_rxdbg_mask;
-module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
+module_param(ep_addr_rxdbg_mask, uint, 0644);
 
 static int allow_dbg_print(u8 addr)
 {
@@ -985,6 +984,20 @@
 	return 0;
 }
 
+#define TIME_BUF_LEN  20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+	unsigned long long t;
+	unsigned long nanosec_rem;
+
+	t = cpu_clock(smp_processor_id());
+	nanosec_rem = do_div(t, 1000000000)/1000;
+	scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+		nanosec_rem);
+	return tbuf;
+}
+
 /**
  * dbg_print:  prints the common part of the event
  * @addr:   endpoint address
@@ -994,30 +1007,25 @@
  */
 static void dbg_print(u8 addr, const char *name, int status, const char *extra)
 {
-	struct timeval tval;
-	unsigned int stamp;
 	unsigned long flags;
+	char tbuf[TIME_BUF_LEN];
 
 	if (!allow_dbg_print(addr))
 		return;
 
 	write_lock_irqsave(&dbg_data.lck, flags);
 
-	do_gettimeofday(&tval);
-	stamp = tval.tv_sec & 0xFFFF;	/* 2^32 = 4294967296. Limit to 4096s */
-	stamp = stamp * 1000000 + tval.tv_usec;
-
 	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
-		  "%04X\t? %02X %-7.7s %4i ?\t%s\n",
-		  stamp, addr, name, status, extra);
+		  "%s\t? %02X %-7.7s %4i ?\t%s\n",
+		  get_timestamp(tbuf), addr, name, status, extra);
 
 	dbg_inc(&dbg_data.idx);
 
 	write_unlock_irqrestore(&dbg_data.lck, flags);
 
 	if (dbg_data.tty != 0)
-		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
-			  stamp, addr, name, status, extra);
+		pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+			  get_timestamp(tbuf), addr, name, status, extra);
 }
 
 /**
@@ -1110,8 +1118,8 @@
 		list_for_each(ptr, &mep->qh.queue) {
 			req = list_entry(ptr, struct ci13xxx_req, queue);
 			scnprintf(msg, sizeof(msg),
-					"%08X:%08X:%08X\n",
-					req->dma, req->ptr->next,
+					"%pKa:%08X:%08X\n",
+					&req->dma, req->ptr->next,
 					req->ptr->token);
 			dbg_print(addr, "REQ", 0, msg);
 			scnprintf(msg, sizeof(msg), "%08X:%d\n",
@@ -1131,9 +1139,9 @@
 			   char *buf)
 {
 	unsigned long flags;
-	unsigned i, j, n = 0;
+	unsigned int i, j, n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -1166,15 +1174,15 @@
 static ssize_t store_events(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	unsigned tty;
+	unsigned int tty;
 
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		goto done;
 	}
 
-	if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+	if (kstrtouint(buf, 10, &tty) || tty > 1) {
 		dev_err(dev, "<1|0>: enable|disable console log\n");
 		goto done;
 	}
@@ -1185,7 +1193,7 @@
  done:
 	return count;
 }
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+static DEVICE_ATTR(events, 0600, show_events, store_events);
 
 /**
  * show_inters: interrupt status, enable status and historic
@@ -1198,9 +1206,9 @@
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	u32 intr;
-	unsigned i, j, n = 0;
+	unsigned int i, j, n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -1271,9 +1279,9 @@
 {
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
-	unsigned en, bit;
+	unsigned int en, bit;
 
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		goto done;
@@ -1299,7 +1307,7 @@
  done:
 	return count;
 }
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+static DEVICE_ATTR(inters, 0600, show_inters, store_inters);
 
 /**
  * show_port_test: reads port test mode
@@ -1311,9 +1319,9 @@
 {
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
-	unsigned mode;
+	unsigned int mode;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -1337,15 +1345,15 @@
 {
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
-	unsigned mode;
+	unsigned int mode;
 
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		goto done;
 	}
 
-	if (sscanf(buf, "%u", &mode) != 1) {
+	if (kstrtouint(buf, 10, &mode)) {
 		dev_err(dev, "<mode>: set port test mode");
 		goto done;
 	}
@@ -1358,8 +1366,7 @@
  done:
 	return count;
 }
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
-		   show_port_test, store_port_test);
+static DEVICE_ATTR(port_test, 0600, show_port_test, store_port_test);
 
 /**
  * show_qheads: DMA contents of all queue heads
@@ -1371,9 +1378,9 @@
 {
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
-	unsigned i, j, n = 0;
+	unsigned int i, j, n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -1383,6 +1390,7 @@
 	for (i = 0; i < hw_ep_max/2; i++) {
 		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
 		struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
+
 		n += scnprintf(buf + n, PAGE_SIZE - n,
 			       "EP=%02i: RX=%08X TX=%08X\n",
 			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
@@ -1397,7 +1405,7 @@
 
 	return n;
 }
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+static DEVICE_ATTR(qheads, 0400, show_qheads, NULL);
 
 /**
  * show_registers: dumps all registers
@@ -1411,19 +1419,17 @@
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	u32 *dump;
-	unsigned i, k, n = 0;
+	unsigned int i, k, n = 0;
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
 	}
 
 	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
-	if (!dump) {
-		dev_err(dev, "%s: out of memory\n", __func__);
+	if (!dump)
 		return 0;
-	}
 
 	spin_lock_irqsave(udc->lock, flags);
 	k = hw_register_read(dump, DUMP_ENTRIES);
@@ -1432,7 +1438,7 @@
 	for (i = 0; i < k; i++) {
 		n += scnprintf(buf + n, PAGE_SIZE - n,
 			       "reg[0x%04X] = 0x%08X\n",
-			       i * (unsigned)sizeof(u32), dump[i]);
+			       i * (unsigned int)sizeof(u32), dump[i]);
 	}
 	kfree(dump);
 
@@ -1451,7 +1457,7 @@
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long addr, data, flags;
 
-	dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		goto done;
@@ -1470,8 +1476,7 @@
  done:
 	return count;
 }
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
-		   show_registers, store_registers);
+static DEVICE_ATTR(registers, 0600, show_registers, store_registers);
 
 /**
  * show_requests: DMA contents of all requests currently queued (all endpts)
@@ -1485,9 +1490,9 @@
 	unsigned long flags;
 	struct list_head   *ptr = NULL;
 	struct ci13xxx_req *req = NULL;
-	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+	unsigned int i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
-	dbg_trace("[%s] %p\n", __func__, buf);
+	dbg_trace("[%s] %pK\n", __func__, buf);
 	if (attr == NULL || buf == NULL) {
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
@@ -1513,7 +1518,7 @@
 
 	return n;
 }
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+static DEVICE_ATTR(requests, 0400, show_requests, NULL);
 
 /* EP# and Direction */
 static ssize_t prime_ept(struct device *dev,
@@ -1541,6 +1546,7 @@
 	mEp->qh.ptr->td.next   = mReq->dma;
 	mEp->qh.ptr->td.token &= ~TD_STATUS;
 
+	/* Makes sure that above write goes through */
 	wmb();
 
 	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
@@ -1555,7 +1561,7 @@
 	return count;
 
 }
-static DEVICE_ATTR(prime, S_IWUSR, NULL, prime_ept);
+static DEVICE_ATTR(prime, 0200, NULL, prime_ept);
 
 /* EP# and Direction */
 static ssize_t print_dtds(struct device *dev,
@@ -1580,15 +1586,14 @@
 		mEp = &udc->ci13xxx_ep[ep_num];
 
 	n = hw_ep_bit(mEp->num, mEp->dir);
-	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s"
-			"dTD_update_fail_count: %lu "
-			"mEp->dTD_update_fail_count: %lu"
-			"mEp->prime_fail_count: %lu\n", __func__,
+	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s dTD_update_fail_count: %lu mEp->dTD_update_fail_count: %lu mEp->dTD_active_re_q_count: %lu mEp->prime_fail_count: %lu\n",
+			__func__,
 			hw_cread(CAP_ENDPTPRIME, ~0),
 			hw_cread(CAP_ENDPTSTAT, ~0),
 			mEp->num, mEp->dir ? "IN" : "OUT",
 			udc->dTD_update_fail_count,
 			mEp->dTD_update_fail_count,
+			mEp->dTD_active_re_q_count,
 			mEp->prime_fail_count);
 
 	pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
@@ -1598,15 +1603,15 @@
 	list_for_each(ptr, &mEp->qh.queue) {
 		req = list_entry(ptr, struct ci13xxx_req, queue);
 
-		pr_info("\treq:%08x next:%08x token:%08x page0:%08x status:%d\n",
-				req->dma, req->ptr->next, req->ptr->token,
+		pr_info("\treq:%pKa next:%08x token:%08x page0:%08x status:%d\n",
+				&req->dma, req->ptr->next, req->ptr->token,
 				req->ptr->page[0], req->req.status);
 	}
 done:
 	return count;
 
 }
-static DEVICE_ATTR(dtds, S_IWUSR, NULL, print_dtds);
+static DEVICE_ATTR(dtds, 0200, NULL, print_dtds);
 
 static int ci13xxx_wakeup(struct usb_gadget *_gadget)
 {
@@ -1617,13 +1622,15 @@
 	trace();
 
 	spin_lock_irqsave(udc->lock, flags);
-	if (!udc->remote_wakeup) {
+	if (!udc->gadget.remote_wakeup) {
 		ret = -EOPNOTSUPP;
 		dbg_trace("remote wakeup feature is not enabled\n");
 		goto out;
 	}
 	spin_unlock_irqrestore(udc->lock, flags);
 
+	pm_runtime_get_sync(&_gadget->dev);
+
 	udc->udc_driver->notify_event(udc,
 		CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
 
@@ -1634,9 +1641,13 @@
 	if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
 		ret = -EINVAL;
 		dbg_trace("port is not suspended\n");
+		pm_runtime_put(&_gadget->dev);
 		goto out;
 	}
 	hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
 out:
 	spin_unlock_irqrestore(udc->lock, flags);
 	return ret;
@@ -1653,7 +1664,7 @@
 	 * if wakeup conditions are still met.
 	 */
 	spin_lock_irqsave(udc->lock, flags);
-	do_wake = udc->suspended && udc->remote_wakeup;
+	do_wake = udc->suspended && udc->gadget.remote_wakeup;
 	spin_unlock_irqrestore(udc->lock, flags);
 
 	if (do_wake)
@@ -1669,7 +1680,7 @@
 
 	return count;
 }
-static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup);
+static DEVICE_ATTR(wakeup, 0200, 0, usb_remote_wakeup);
 
 /**
  * dbg_create_files: initializes the attribute interface
@@ -1677,7 +1688,7 @@
  *
  * This function returns an error code
  */
-__maybe_unused static int dbg_create_files(struct device *dev)
+static int __maybe_unused dbg_create_files(struct device *dev)
 {
 	int retval = 0;
 
@@ -1749,7 +1760,7 @@
  *
  * This function returns an error code
  */
-__maybe_unused static int dbg_remove_files(struct device *dev)
+static int __maybe_unused dbg_remove_files(struct device *dev)
 {
 	if (dev == NULL)
 		return -EINVAL;
@@ -1765,72 +1776,6 @@
 	return 0;
 }
 
-static void dump_usb_info(void *ignore, unsigned int ebi_addr,
-	unsigned int ebi_apacket0, unsigned int ebi_apacket1)
-{
-	struct ci13xxx *udc = _udc;
-	unsigned long flags;
-	struct list_head   *ptr = NULL;
-	struct ci13xxx_req *req = NULL;
-	struct ci13xxx_ep *mEp;
-	unsigned i;
-	struct ci13xxx_ebi_err_entry *temp_dump;
-	static int count;
-	u32 epdir = 0;
-
-	if (count)
-		return;
-	count++;
-
-	pr_info("%s: USB EBI error detected\n", __func__);
-
-	ebi_err_data = kmalloc(sizeof(struct ci13xxx_ebi_err_data),
-				 GFP_ATOMIC);
-	if (!ebi_err_data) {
-		pr_err("%s: memory alloc failed for ebi_err_data\n", __func__);
-		return;
-	}
-
-	ebi_err_data->ebi_err_entry = kmalloc(
-					sizeof(struct ci13xxx_ebi_err_entry),
-					GFP_ATOMIC);
-	if (!ebi_err_data->ebi_err_entry) {
-		kfree(ebi_err_data);
-		pr_err("%s: memory alloc failed for ebi_err_entry\n", __func__);
-		return;
-	}
-
-	ebi_err_data->ebi_err_addr = ebi_addr;
-	ebi_err_data->apkt0 = ebi_apacket0;
-	ebi_err_data->apkt1 = ebi_apacket1;
-
-	temp_dump = ebi_err_data->ebi_err_entry;
-	pr_info("\n DUMPING USB Requests Information\n");
-	spin_lock_irqsave(udc->lock, flags);
-	for (i = 0; i < hw_ep_max; i++) {
-		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) {
-			mEp = &udc->ci13xxx_ep[i];
-			req = list_entry(ptr, struct ci13xxx_req, queue);
-
-			temp_dump->usb_req_buf = req->req.buf;
-			temp_dump->usb_req_length = req->req.length;
-			epdir = mEp->dir;
-			temp_dump->ep_info = mEp->num | (epdir << 15);
-
-			temp_dump->next = kmalloc(
-					  sizeof(struct ci13xxx_ebi_err_entry),
-					  GFP_ATOMIC);
-			if (!temp_dump->next) {
-				pr_err("%s: memory alloc failed\n", __func__);
-				spin_unlock_irqrestore(udc->lock, flags);
-				return;
-			}
-			temp_dump = temp_dump->next;
-		}
-	}
-	spin_unlock_irqrestore(udc->lock, flags);
-}
-
 /******************************************************************************
  * UTIL block
  *****************************************************************************/
@@ -1869,6 +1814,7 @@
 
 	req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
 
+	/* clean speculative fetches on req->ptr->token */
 	mb();
 	if (!(TD_STATUS_ACTIVE & req->ptr->token))
 		goto out;
@@ -1882,8 +1828,8 @@
 				mep->qh.ptr->td.next, mep->qh.ptr->td.token);
 		list_for_each(ptr, &mep->qh.queue) {
 			req = list_entry(ptr, struct ci13xxx_req, queue);
-			pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
-					req->dma, req->ptr->next,
+			pr_info("\treq:%pKa:%08xtkn:%08xpage0:%08xsts:%d\n",
+					&req->dma, req->ptr->next,
 					req->ptr->token, req->ptr->page[0],
 					req->req.status);
 		}
@@ -1911,23 +1857,22 @@
  */
 static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
 {
-	unsigned i;
+	unsigned int i;
 	int ret = 0;
-	unsigned length = mReq->req.length;
+	unsigned int length = mReq->req.length;
 	struct ci13xxx *udc = _udc;
 
-	trace("%p, %p", mEp, mReq);
+	trace("%pK, %pK", mEp, mReq);
 
 	/* don't queue twice */
 	if (mReq->req.status == -EALREADY)
 		return -EALREADY;
 
 	mReq->req.status = -EALREADY;
-	if (length && mReq->req.dma == DMA_ADDR_INVALID) {
-		mReq->req.dma = \
-			dma_map_single(mEp->device, mReq->req.buf,
-				       length, mEp->dir ? DMA_TO_DEVICE :
-				       DMA_FROM_DEVICE);
+	if (length && mReq->req.dma == DMA_ERROR_CODE) {
+		mReq->req.dma = dma_map_single(mEp->device, mReq->req.buf,
+					length, mEp->dir ? DMA_TO_DEVICE :
+					DMA_FROM_DEVICE);
 		if (mReq->req.dma == 0)
 			return -ENOMEM;
 
@@ -1942,7 +1887,7 @@
 				dma_unmap_single(mEp->device, mReq->req.dma,
 					length, mEp->dir ? DMA_TO_DEVICE :
 					DMA_FROM_DEVICE);
-				mReq->req.dma = DMA_ADDR_INVALID;
+				mReq->req.dma = DMA_ERROR_CODE;
 				mReq->map     = 0;
 			}
 			return -ENOMEM;
@@ -1953,6 +1898,7 @@
 		if (!mReq->req.no_interrupt)
 			mReq->zptr->token   |= TD_IOC;
 	}
+
 	/*
 	 * TD configuration
 	 * TODO - handle requests which spawns into several TDs
@@ -1970,7 +1916,7 @@
 	}
 
 	/* MSM Specific: updating the request as required for
-	 * SPS mode. Enable MSM DMA engine acording
+	 * SPS mode. Enable MSM DMA engine according
 	 * to the UDC private data in the request.
 	 */
 	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
@@ -1990,16 +1936,22 @@
 	for (i = 1; i < 5; i++)
 		mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) &
 							~TD_RESERVED_MASK;
+	/* Makes sure that above write goes through */
 	wmb();
 
 	/* Remote Wakeup */
 	if (udc->suspended) {
-		if (!udc->remote_wakeup) {
+		if (!udc->gadget.remote_wakeup) {
 			mReq->req.status = -EAGAIN;
-			dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
-				__func__, mEp->num);
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+
 			return -EAGAIN;
 		}
+
 		usb_phy_set_suspend(udc->transceiver, 0);
 		schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
 	}
@@ -2016,6 +1968,7 @@
 			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
 		else
 			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+		/* Makes sure that above write goes through */
 		wmb();
 		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
 			goto done;
@@ -2039,19 +1992,37 @@
 			goto done;
 	}
 
-	/*  QH configuration */
+	/* Hardware may leave few TDs unprocessed, check and reprime with 1st */
 	if (!list_empty(&mEp->qh.queue)) {
-		struct ci13xxx_req *mReq = \
-			list_entry(mEp->qh.queue.next,
-				   struct ci13xxx_req, queue);
+		struct ci13xxx_req *mReq_active, *mReq_next;
+		u32 i = 0;
 
-		if (TD_STATUS_ACTIVE & mReq->ptr->token) {
-			mEp->qh.ptr->td.next   = mReq->dma;
-			mEp->qh.ptr->td.token &= ~TD_STATUS;
-			goto prime;
+		/* Nothing to be done if hardware already finished this TD */
+		if ((TD_STATUS_ACTIVE & mReq->ptr->token) == 0)
+			goto done;
+
+		/* Iterate forward to find first TD with ACTIVE bit set */
+		mReq_active = mReq;
+		list_for_each_entry(mReq_next, &mEp->qh.queue, queue) {
+			i++;
+			mEp->dTD_active_re_q_count++;
+			if (TD_STATUS_ACTIVE & mReq_next->ptr->token) {
+				mReq_active = mReq_next;
+				dbg_event(_usb_addr(mEp), "ReQUE",
+					  mReq_next->ptr->token);
+				pr_debug("!!ReQ(%u-%u-%x)-%u!!\n", mEp->num,
+					 mEp->dir, mReq_next->ptr->token, i);
+				break;
+			}
 		}
+
+		/*  QH configuration */
+		mEp->qh.ptr->td.next = mReq_active->dma;
+		mEp->qh.ptr->td.token &= ~TD_STATUS;
+		goto prime;
 	}
 
+	/*  QH configuration */
 	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
 
 	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
@@ -2063,8 +2034,10 @@
 			i = (mEp->dir == TX) ?
 				((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
 					(i & MSM_PIPE_ID_MASK);
-			/* If requested pipe id is different from current,
-			   then write it */
+			/*
+			 * If requested pipe id is different from current,
+			 * then write it
+			 */
 			if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
 				if (mEp->dir == TX)
 					hw_cwrite(
@@ -2090,12 +2063,14 @@
 	mEp->qh.ptr->cap |=  QH_ZLT;
 
 prime:
+	/* Makes sure that above write goes through */
 	wmb();   /* synchronize before ep prime */
 
 	ret = hw_ep_prime(mEp->num, mEp->dir,
 			   mEp->type == USB_ENDPOINT_XFER_CONTROL);
 	if (!ret)
 		mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+
 done:
 	return ret;
 }
@@ -2109,7 +2084,7 @@
  */
 static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
 {
-	trace("%p, %p", mEp, mReq);
+	trace("%pK, %pK", mEp, mReq);
 
 	if (mReq->req.status != -EALREADY)
 		return -EINVAL;
@@ -2147,7 +2122,7 @@
 	if (mReq->map) {
 		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
 				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		mReq->req.dma = DMA_ADDR_INVALID;
+		mReq->req.dma = DMA_ERROR_CODE;
 		mReq->map     = 0;
 	}
 
@@ -2168,6 +2143,65 @@
 }
 
 /**
+ * purge_rw_queue: Purge requests pending at the remote-wakeup
+ * queue and send them to the HW.
+ *
+ * Go over all of the endpoints and push any pending requests to
+ * the HW queue.
+ */
+static void purge_rw_queue(struct ci13xxx *udc)
+{
+	int i;
+	struct ci13xxx_ep  *mEp  = NULL;
+	struct ci13xxx_req *mReq = NULL;
+
+	/*
+	 * Go over all of the endpoints and push any pending requests to
+	 * the HW queue.
+	 */
+	for (i = 0; i < hw_ep_max; i++) {
+		mEp = &udc->ci13xxx_ep[i];
+
+		while (!list_empty(&udc->ci13xxx_ep[i].rw_queue)) {
+			int retval;
+
+			/* pop oldest request */
+			mReq = list_entry(udc->ci13xxx_ep[i].rw_queue.next,
+					  struct ci13xxx_req, queue);
+
+			list_del_init(&mReq->queue);
+
+			retval = _hardware_enqueue(mEp, mReq);
+
+			if (retval != 0) {
+				dbg_event(_usb_addr(mEp), "QUEUE", retval);
+				mReq->req.status = retval;
+				if (mReq->req.complete != NULL) {
+					if (mEp->type ==
+					    USB_ENDPOINT_XFER_CONTROL)
+						mReq->req.complete(
+							&(_udc->ep0in.ep),
+							&mReq->req);
+					else
+						mReq->req.complete(
+							&mEp->ep,
+							&mReq->req);
+				}
+				retval = 0;
+			}
+
+			if (!retval)
+				list_add_tail(&mReq->queue, &mEp->qh.queue);
+			else if (mEp->multi_req)
+				mEp->multi_req = false;
+
+		}
+	}
+
+	udc->rw_pending = false;
+}
+
+/**
  * restore_original_req: Restore original req's attributes
  * @mReq: Request
  *
@@ -2187,6 +2221,67 @@
 }
 
 /**
+ * release_ep_request: Free and endpoint request and release
+ * resources
+ * @mReq: request
+ * @mEp: endpoint
+ *
+ */
+static void release_ep_request(struct ci13xxx_ep  *mEp,
+			       struct ci13xxx_req *mReq)
+{
+	struct ci13xxx_ep *mEpTemp = mEp;
+
+	unsigned int val;
+
+	/* MSM Specific: Clear end point specific register */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			val = hw_cread(CAP_ENDPTPIPEID +
+				mEp->num * sizeof(u32),
+				~0);
+
+			if (val != MSM_EP_PIPE_ID_RESET_VAL)
+				hw_cwrite(
+					CAP_ENDPTPIPEID +
+					 mEp->num * sizeof(u32),
+					~0, MSM_EP_PIPE_ID_RESET_VAL);
+		}
+	}
+	mReq->req.status = -ESHUTDOWN;
+
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma,
+			mReq->req.length,
+			mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
+	if (mEp->multi_req) {
+		restore_original_req(mReq);
+		mEp->multi_req = false;
+	}
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+			mReq->req.length)
+			mEpTemp = &_udc->ep0in;
+		mReq->req.complete(&mEpTemp->ep, &mReq->req);
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mReq->req.complete = NULL;
+		spin_lock(mEp->lock);
+	}
+}
+
+/**
  * _ep_nuke: dequeues all endpoint requests
  * @mEp: endpoint
  *
@@ -2197,10 +2292,7 @@
 __releases(mEp->lock)
 __acquires(mEp->lock)
 {
-	struct ci13xxx_ep *mEpTemp = mEp;
-	unsigned val;
-
-	trace("%p", mEp);
+	trace("%pK", mEp);
 
 	if (mEp == NULL)
 		return -EINVAL;
@@ -2211,53 +2303,34 @@
 	hw_ep_flush(mEp->num, mEp->dir);
 
 	while (!list_empty(&mEp->qh.queue)) {
-
 		/* pop oldest request */
-		struct ci13xxx_req *mReq = \
+		struct ci13xxx_req *mReq =
 			list_entry(mEp->qh.queue.next,
 				   struct ci13xxx_req, queue);
 		list_del_init(&mReq->queue);
 
-		/* MSM Specific: Clear end point specific register */
-		if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
-			if (mReq->req.udc_priv & MSM_SPS_MODE) {
-				val = hw_cread(CAP_ENDPTPIPEID +
-					mEp->num * sizeof(u32),
-					~0);
-
-				if (val != MSM_EP_PIPE_ID_RESET_VAL)
-					hw_cwrite(
-						CAP_ENDPTPIPEID +
-						 mEp->num * sizeof(u32),
-						~0, MSM_EP_PIPE_ID_RESET_VAL);
-			}
-		}
-		mReq->req.status = -ESHUTDOWN;
-
-		if (mReq->map) {
-			dma_unmap_single(mEp->device, mReq->req.dma,
-				mReq->req.length,
-				mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-			mReq->req.dma = DMA_ADDR_INVALID;
-			mReq->map     = 0;
-		}
-
-		if (mEp->multi_req) {
-			restore_original_req(mReq);
-			mEp->multi_req = false;
-		}
-
-		if (mReq->req.complete != NULL) {
-			spin_unlock(mEp->lock);
-			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
-				mReq->req.length)
-				mEpTemp = &_udc->ep0in;
-			mReq->req.complete(&mEpTemp->ep, &mReq->req);
-			if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-				mReq->req.complete = NULL;
-			spin_lock(mEp->lock);
-		}
+		release_ep_request(mEp, mReq);
 	}
+
+	/* Clear the requests pending at the remote-wakeup queue */
+	while (!list_empty(&mEp->rw_queue)) {
+
+		/* pop oldest request */
+		struct ci13xxx_req *mReq =
+			list_entry(mEp->rw_queue.next,
+				   struct ci13xxx_req, queue);
+
+		list_del_init(&mReq->queue);
+
+		release_ep_request(mEp, mReq);
+	}
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
 	return 0;
 }
 
@@ -2272,23 +2345,18 @@
 	struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
 	unsigned long flags;
 
-	trace("%p", gadget);
+	trace("%pK", gadget);
 
 	if (gadget == NULL)
 		return -EINVAL;
 
 	spin_lock_irqsave(udc->lock, flags);
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
-	udc->remote_wakeup = 0;
+	udc->gadget.remote_wakeup = 0;
 	udc->suspended = 0;
 	udc->configured = 0;
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	gadget->b_hnp_enable = 0;
-	gadget->a_hnp_support = 0;
-	gadget->host_request = 0;
-	gadget->otg_srp_reqd = 0;
-
 	udc->driver->disconnect(gadget);
 
 	spin_lock_irqsave(udc->lock, flags);
@@ -2296,12 +2364,6 @@
 	_ep_nuke(&udc->ep0in);
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	if (udc->ep0in.last_zptr) {
-		dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
-				udc->ep0in.last_zdma);
-		udc->ep0in.last_zptr = NULL;
-	}
-
 	return 0;
 }
 
@@ -2320,7 +2382,7 @@
 {
 	int retval;
 
-	trace("%p", udc);
+	trace("%pK", udc);
 
 	if (udc == NULL) {
 		err("EINVAL");
@@ -2349,6 +2411,9 @@
 	if (retval)
 		goto done;
 
+	if (udc->rw_pending)
+		purge_rw_queue(udc);
+
 	_udc->skip_flush = false;
 	retval = hw_usb_reset();
 	if (retval)
@@ -2377,9 +2442,13 @@
 			  CI13XXX_CONTROLLER_RESUME_EVENT);
 		if (udc->transceiver)
 			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->suspended = 0;
 		udc->driver->resume(&udc->gadget);
 		spin_lock(udc->lock);
-		udc->suspended = 0;
+
+		if (udc->rw_pending)
+			purge_rw_queue(udc);
+
 	}
 }
 
@@ -2415,7 +2484,7 @@
  */
 static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	trace("%p, %p", ep, req);
+	trace("%pK, %pK", ep, req);
 
 	if (ep == NULL || req == NULL) {
 		err("EINVAL");
@@ -2442,7 +2511,7 @@
 	struct usb_request *req = udc->status;
 	int dir, num, retval;
 
-	trace("%p, %p", mEp, setup);
+	trace("%pK, %pK", mEp, setup);
 
 	if (mEp == NULL || setup == NULL)
 		return -EINVAL;
@@ -2452,18 +2521,11 @@
 	req->buf      = udc->status_buf;
 
 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		if (setup->wIndex == OTG_STATUS_SELECTOR) {
-			*((u8 *)req->buf) = _udc->gadget.host_request <<
-						HOST_REQUEST_FLAG;
-			req->length = 1;
-		} else {
-			/* Assume that device is bus powered for now. */
-			*((u16 *)req->buf) = _udc->remote_wakeup << 1;
-		}
-		/* TODO: D1 - Remote Wakeup; D0 - Self Powered */
+		/* Assume that device is bus powered for now. */
+		*((u16 *)req->buf) = _udc->gadget.remote_wakeup << 1;
 		retval = 0;
-	} else if ((setup->bRequestType & USB_RECIP_MASK) \
-		   == USB_RECIP_ENDPOINT) {
+	} else if ((setup->bRequestType & USB_RECIP_MASK) ==
+							USB_RECIP_ENDPOINT) {
 		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
 			TX : RX;
 		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
@@ -2491,7 +2553,7 @@
 	struct ci13xxx *udc = req->context;
 	unsigned long flags;
 
-	trace("%p, %p", ep, req);
+	trace("%pK, %pK", ep, req);
 
 	spin_lock_irqsave(udc->lock, flags);
 	if (udc->test_mode)
@@ -2512,7 +2574,7 @@
 	int retval;
 	struct ci13xxx_ep *mEp;
 
-	trace("%p", udc);
+	trace("%pK", udc);
 
 	mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
 	udc->status->context = udc;
@@ -2539,11 +2601,11 @@
 {
 	struct ci13xxx_req *mReq, *mReqTemp;
 	struct ci13xxx_ep *mEpTemp = mEp;
-	int uninitialized_var(retval);
+	int retval = 0;
 	int req_dequeue = 1;
 	struct ci13xxx *udc = _udc;
 
-	trace("%p", mEp);
+	trace("%pK", mEp);
 
 	if (list_empty(&mEp->qh.queue))
 		return 0;
@@ -2574,7 +2636,7 @@
 		req_dequeue = 0;
 
 		if (mEp->multi_req) { /* Large request in progress */
-			unsigned remain_len;
+			unsigned int remain_len;
 
 			mReq->multi.actual += mReq->req.actual;
 			remain_len = mReq->multi.len - mReq->multi.actual;
@@ -2585,8 +2647,9 @@
 			} else {
 				mReq->req.buf = mReq->multi.buf +
 						mReq->multi.actual;
-				mReq->req.length = min_t(unsigned, remain_len,
-						(4 * CI13XXX_PAGE_SIZE));
+				mReq->req.length = min_t(unsigned int,
+							remain_len,
+							4 * CI13XXX_PAGE_SIZE);
 
 				mReq->req.status = -EINPROGRESS;
 				mReq->req.actual = 0;
@@ -2638,10 +2701,10 @@
 __releases(udc->lock)
 __acquires(udc->lock)
 {
-	unsigned i;
+	unsigned int i;
 	u8 tmode = 0;
 
-	trace("%p", udc);
+	trace("%pK", udc);
 
 	if (udc == NULL) {
 		err("EINVAL");
@@ -2728,7 +2791,7 @@
 					USB_DEVICE_REMOTE_WAKEUP) {
 				if (req.wLength != 0)
 					break;
-				udc->remote_wakeup = 0;
+				udc->gadget.remote_wakeup = 0;
 				err = isr_setup_status_phase(udc);
 			} else {
 				goto delegate;
@@ -2739,7 +2802,8 @@
 			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
 			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
 				goto delegate;
-			if (le16_to_cpu(req.wValue)  != 0)
+			if (le16_to_cpu(req.wLength) != 2 ||
+			    le16_to_cpu(req.wValue)  != 0)
 				break;
 			err = isr_get_status_response(udc, &req);
 			break;
@@ -2780,19 +2844,9 @@
 					break;
 				switch (le16_to_cpu(req.wValue)) {
 				case USB_DEVICE_REMOTE_WAKEUP:
-					udc->remote_wakeup = 1;
+					udc->gadget.remote_wakeup = 1;
 					err = isr_setup_status_phase(udc);
 					break;
-				case USB_DEVICE_B_HNP_ENABLE:
-					udc->gadget.b_hnp_enable = 1;
-					err = isr_setup_status_phase(udc);
-					break;
-				case USB_DEVICE_A_HNP_SUPPORT:
-					udc->gadget.a_hnp_support = 1;
-					err = isr_setup_status_phase(udc);
-					break;
-				case USB_DEVICE_A_ALT_HNP_SUPPORT:
-					break;
 				case USB_DEVICE_TEST_MODE:
 					tmode = le16_to_cpu(req.wIndex) >> 8;
 					switch (tmode) {
@@ -2805,21 +2859,11 @@
 						err = isr_setup_status_phase(
 								udc);
 						break;
-					case TEST_OTG_SRP_REQD:
-						udc->gadget.otg_srp_reqd = 1;
-						err = isr_setup_status_phase(
-								udc);
-						break;
-					case TEST_OTG_HNP_REQD:
-						udc->gadget.host_request = 1;
-						err = isr_setup_status_phase(
-								udc);
-						break;
 					default:
 						break;
 					}
 				default:
-					break;
+					goto delegate;
 				}
 			} else {
 				goto delegate;
@@ -2861,9 +2905,9 @@
 	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
 	int retval = 0;
 	unsigned long flags;
-	unsigned mult = 0;
+	unsigned int mult = 0;
 
-	trace("ep = %p, desc = %p", ep, desc);
+	trace("ep = %pK, desc = %pK", ep, desc);
 
 	if (ep == NULL || desc == NULL)
 		return -EINVAL;
@@ -2926,7 +2970,7 @@
 	int direction, retval = 0;
 	unsigned long flags;
 
-	trace("%p", ep);
+	trace("%pK", ep);
 
 	if (ep == NULL)
 		return -EINVAL;
@@ -2949,12 +2993,6 @@
 
 	} while (mEp->dir != direction);
 
-	if (mEp->last_zptr) {
-		dma_pool_free(mEp->td_pool, mEp->last_zptr,
-				mEp->last_zdma);
-		mEp->last_zptr = NULL;
-	}
-
 	mEp->desc = NULL;
 	mEp->ep.desc = NULL;
 	mEp->ep.maxpacket = USHRT_MAX;
@@ -2973,7 +3011,7 @@
 	struct ci13xxx_ep  *mEp  = container_of(ep, struct ci13xxx_ep, ep);
 	struct ci13xxx_req *mReq = NULL;
 
-	trace("%p, %i", ep, gfp_flags);
+	trace("%pK, %i", ep, gfp_flags);
 
 	if (ep == NULL) {
 		err("EINVAL");
@@ -2983,7 +3021,7 @@
 	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
 	if (mReq != NULL) {
 		INIT_LIST_HEAD(&mReq->queue);
-		mReq->req.dma = DMA_ADDR_INVALID;
+		mReq->req.dma = DMA_ERROR_CODE;
 
 		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
 					   &mReq->dma);
@@ -3009,7 +3047,7 @@
 	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
 	unsigned long flags;
 
-	trace("%p, %p", ep, req);
+	trace("%pK, %pK", ep, req);
 
 	if (ep == NULL || req == NULL) {
 		err("EINVAL");
@@ -3044,10 +3082,13 @@
 	unsigned long flags;
 	struct ci13xxx *udc = _udc;
 
-	trace("%p, %p, %X", ep, req, gfp_flags);
+	trace("%pK, %pK, %X", ep, req, gfp_flags);
+
+	if (ep == NULL)
+		return -EINVAL;
 
 	spin_lock_irqsave(mEp->lock, flags);
-	if (ep == NULL || req == NULL || mEp->desc == NULL) {
+	if (req == NULL || mEp->desc == NULL) {
 		retval = -EINVAL;
 		goto done;
 	}
@@ -3059,8 +3100,7 @@
 
 	if (!udc->configured && mEp->type !=
 		USB_ENDPOINT_XFER_CONTROL) {
-		trace("usb is not configured"
-			"ept #%d, ept name#%s\n",
+		trace("usb is not configured ept #%d, ept name#%s\n",
 			mEp->num, mEp->ep.name);
 		retval = -ESHUTDOWN;
 		goto done;
@@ -3077,6 +3117,12 @@
 		}
 	}
 
+	if (ep->endless && udc->gadget.speed == USB_SPEED_FULL) {
+		err("Queueing endless req is not supported for FS");
+		retval = -EINVAL;
+		goto done;
+	}
+
 	/* first nuke then test link, e.g. previous status has not sent */
 	if (!list_empty(&mReq->queue)) {
 		retval = -EBUSY;
@@ -3113,6 +3159,36 @@
 	mReq->req.status = -EINPROGRESS;
 	mReq->req.actual = 0;
 
+	if (udc->rw_pending) {
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+		retval = 0;
+		goto done;
+	}
+
+	if (udc->suspended) {
+		/* Remote Wakeup */
+		if (!udc->gadget.remote_wakeup) {
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+			mEp->multi_req = false;
+
+			retval = -EAGAIN;
+			goto done;
+		}
+
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+
+		udc->rw_pending = true;
+		schedule_delayed_work(&udc->rw_work,
+				      REMOTE_WAKEUP_DELAY);
+
+		retval = 0;
+		goto done;
+	}
+
 	retval = _hardware_enqueue(mEp, mReq);
 
 	if (retval == -EALREADY) {
@@ -3139,16 +3215,27 @@
 	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
 	struct ci13xxx_ep *mEpTemp = mEp;
 	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	struct ci13xxx *udc = _udc;
 	unsigned long flags;
 
-	trace("%p, %p", ep, req);
+	trace("%pK, %pK", ep, req);
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to dequeue while in LPM\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	if (ep == NULL)
+		return -EINVAL;
 
 	spin_lock_irqsave(mEp->lock, flags);
 	/*
 	 * Only ep0 IN is exposed to composite.  When a req is dequeued
 	 * on ep0, check both ep0 IN and ep0 OUT queues.
 	 */
-	if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
+	if (req == NULL || mReq->req.status != -EALREADY ||
 		mEp->desc == NULL || list_empty(&mReq->queue) ||
 		(list_empty(&mEp->qh.queue) && ((mEp->type !=
 			USB_ENDPOINT_XFER_CONTROL) ||
@@ -3159,7 +3246,7 @@
 
 	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
 
-	if ((mEp->type == USB_ENDPOINT_XFER_CONTROL)) {
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
 		hw_ep_flush(_udc->ep0out.num, RX);
 		hw_ep_flush(_udc->ep0in.num, TX);
 	} else {
@@ -3171,10 +3258,23 @@
 	if (mReq->map) {
 		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
 				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-		mReq->req.dma = DMA_ADDR_INVALID;
+		mReq->req.dma = DMA_ERROR_CODE;
 		mReq->map     = 0;
 	}
 	req->status = -ECONNRESET;
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
 	if (mEp->multi_req) {
 		restore_original_req(mReq);
 		mEp->multi_req = false;
@@ -3209,14 +3309,21 @@
 static int ep_set_halt(struct usb_ep *ep, int value)
 {
 	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx *udc = _udc;
 	int direction, retval = 0;
 	unsigned long flags;
 
-	trace("%p, %i", ep, value);
+	trace("%pK, %i", ep, value);
 
 	if (ep == NULL || mEp->desc == NULL)
 		return -EINVAL;
 
+	if (udc->suspended) {
+		dev_err(udc->transceiver->dev,
+			"%s: Unable to halt EP while suspended\n", __func__);
+		return -EINVAL;
+	}
+
 	spin_lock_irqsave(mEp->lock, flags);
 
 #ifndef STALL_IN
@@ -3257,7 +3364,7 @@
 	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
 	unsigned long flags;
 
-	trace("%p", ep);
+	trace("%pK", ep);
 
 	if (ep == NULL || mEp->desc == NULL)
 		return -EINVAL;
@@ -3279,16 +3386,24 @@
  */
 static void ep_fifo_flush(struct usb_ep *ep)
 {
+	struct ci13xxx *udc = _udc;
 	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
 	unsigned long flags;
 
-	trace("%p", ep);
+	trace("%pK", ep);
 
 	if (ep == NULL) {
 		err("%02X: -EINVAL", _usb_addr(mEp));
 		return;
 	}
 
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to fifo_flush while in LPM\n",
+				__func__);
+		return;
+	}
+
 	spin_lock_irqsave(mEp->lock, flags);
 
 	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
@@ -3337,28 +3452,51 @@
 		gadget_ready = 1;
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	if (gadget_ready) {
-		if (is_active) {
-			pm_runtime_get_sync(&_gadget->dev);
-			hw_device_reset(udc);
-			if (udc->softconnect)
-				hw_device_state(udc->ep0out.qh.dma);
-		} else {
-			hw_device_state(0);
-			_gadget_stop_activity(&udc->gadget);
-			if (udc->udc_driver->notify_event)
-				udc->udc_driver->notify_event(udc,
-					CI13XXX_CONTROLLER_DISCONNECT_EVENT);
-			pm_runtime_put_sync(&_gadget->dev);
+	if (!gadget_ready)
+		return 0;
+
+	if (is_active) {
+		hw_device_reset(udc);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		/* Enable BAM (if needed) before starting controller */
+		if (udc->softconnect) {
+			dbg_event(0xFF, "BAM EN2",
+				_gadget->bam2bam_func_enabled);
+			msm_usb_bam_enable(CI_CTRL,
+				_gadget->bam2bam_func_enabled);
+			hw_device_state(udc->ep0out.qh.dma);
 		}
+	} else {
+		hw_device_state(0);
+		_gadget_stop_activity(&udc->gadget);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_DISCONNECT_EVENT);
 	}
 
 	return 0;
 }
 
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+#define VBUS_DRAW_BUF_LEN 10
+#define MAX_OVERRIDE_VBUS_ALLOWED 900	/* 900 mA */
+static char vbus_draw_mA[VBUS_DRAW_BUF_LEN];
+module_param_string(vbus_draw_mA, vbus_draw_mA, VBUS_DRAW_BUF_LEN, 0644);
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned int mA)
 {
 	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned int override_mA = 0;
+
+	/* override param to draw more current if battery draining faster */
+	if ((mA == CONFIG_USB_GADGET_VBUS_DRAW) &&
+		(vbus_draw_mA[0] != '\0')) {
+		if ((!kstrtoint(vbus_draw_mA, 10, &override_mA)) &&
+				(override_mA <= MAX_OVERRIDE_VBUS_ALLOWED)) {
+			mA = override_mA;
+		}
+	}
 
 	if (udc->transceiver)
 		return usb_phy_set_power(udc->transceiver, mA);
@@ -3379,17 +3517,41 @@
 	}
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	if (is_active)
+	pm_runtime_get_sync(&_gadget->dev);
+
+	/* Enable BAM (if needed) before starting controller */
+	if (is_active) {
+		dbg_event(0xFF, "BAM EN1", _gadget->bam2bam_func_enabled);
+		msm_usb_bam_enable(CI_CTRL, _gadget->bam2bam_func_enabled);
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!udc->vbus_active) {
+		spin_unlock_irqrestore(udc->lock, flags);
+		pm_runtime_put_sync(&_gadget->dev);
+		return 0;
+	}
+	if (is_active) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		spin_lock(udc->lock);
 		hw_device_state(udc->ep0out.qh.dma);
-	else
+	} else {
 		hw_device_state(0);
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
 
 	return 0;
 }
 
-static int ci13xxx_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int ci13xxx_stop(struct usb_gadget_driver *driver);
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget);
 
 /**
  * Device operations part of the API to the USB controller hardware,
@@ -3401,31 +3563,27 @@
 	.wakeup		= ci13xxx_wakeup,
 	.vbus_draw	= ci13xxx_vbus_draw,
 	.pullup		= ci13xxx_pullup,
-	.start		= ci13xxx_start,
-	.stop		= ci13xxx_stop,
+	.udc_start	= ci13xxx_start,
+	.udc_stop	= ci13xxx_stop,
 };
 
 /**
  * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
  * @driver: the driver being registered
- * @bind: the driver's bind callback
  *
- * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
  * Interrupts are enabled here.
  */
-static int ci13xxx_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver)
 {
 	struct ci13xxx *udc = _udc;
 	unsigned long flags;
-	int i, j;
 	int retval = -ENOMEM;
-	bool put = false;
 
-	trace("%p", driver);
+	trace("%pK", driver);
 
 	if (driver             == NULL ||
-	    bind               == NULL ||
 	    driver->setup      == NULL ||
 	    driver->disconnect == NULL)
 		return -EINVAL;
@@ -3434,82 +3592,37 @@
 	else if (udc->driver != NULL)
 		return -EBUSY;
 
-	/* alloc resources */
-	udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
-				       sizeof(struct ci13xxx_qh),
-				       64, CI13XXX_PAGE_SIZE);
-	if (udc->qh_pool == NULL)
-		return -ENOMEM;
-
-	udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
-				       sizeof(struct ci13xxx_td),
-				       64, CI13XXX_PAGE_SIZE);
-	if (udc->td_pool == NULL) {
-		dma_pool_destroy(udc->qh_pool);
-		udc->qh_pool = NULL;
-		return -ENOMEM;
-	}
-
 	spin_lock_irqsave(udc->lock, flags);
 
 	info("hw_ep_max = %d", hw_ep_max);
 
 	udc->gadget.dev.driver = NULL;
 
-	retval = 0;
-	for (i = 0; i < hw_ep_max/2; i++) {
-		for (j = RX; j <= TX; j++) {
-			int k = i + j * hw_ep_max/2;
-			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
-
-			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
-					(j == TX)  ? "in" : "out");
-
-			mEp->lock         = udc->lock;
-			mEp->device       = &udc->gadget.dev;
-			mEp->td_pool      = udc->td_pool;
-
-			mEp->ep.name      = mEp->name;
-			mEp->ep.ops       = &usb_ep_ops;
-			mEp->ep.maxpacket =
-				k ? USHRT_MAX : CTRL_PAYLOAD_MAX;
-
-			INIT_LIST_HEAD(&mEp->qh.queue);
-			spin_unlock_irqrestore(udc->lock, flags);
-			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
-					&mEp->qh.dma);
-			spin_lock_irqsave(udc->lock, flags);
-			if (mEp->qh.ptr == NULL)
-				retval = -ENOMEM;
-			else
-				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
-
-			/* skip ep0 out and in endpoints */
-			if (i == 0)
-				continue;
-
-			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
-		}
-	}
-	if (retval)
-		goto done;
 	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&udc->gadget.dev);
+
 	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
 	retval = usb_ep_enable(&udc->ep0out.ep);
 	if (retval)
-		return retval;
+		goto pm_put;
 
 	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
 	retval = usb_ep_enable(&udc->ep0in.ep);
 	if (retval)
-		return retval;
+		goto pm_put;
 	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_KERNEL);
-	if (!udc->status)
-		return -ENOMEM;
-	udc->status_buf = kzalloc(2, GFP_KERNEL); /* for GET_STATUS */
+	if (!udc->status) {
+		retval = -ENOMEM;
+		goto pm_put;
+	}
+
+	udc->status_buf = kzalloc(2 + udc->gadget.extra_buf_alloc,
+				GFP_KERNEL); /* for GET_STATUS */
 	if (!udc->status_buf) {
 		usb_ep_free_request(&udc->ep0in.ep, udc->status);
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto pm_put;
 	}
 	spin_lock_irqsave(udc->lock, flags);
 
@@ -3517,17 +3630,6 @@
 	/* bind gadget */
 	driver->driver.bus     = NULL;
 	udc->gadget.dev.driver = &driver->driver;
-	udc->softconnect = 1;
-
-	spin_unlock_irqrestore(udc->lock, flags);
-	pm_runtime_get_sync(&udc->gadget.dev);
-	retval = bind(&udc->gadget);                /* MAY SLEEP */
-	spin_lock_irqsave(udc->lock, flags);
-
-	if (retval) {
-		udc->gadget.dev.driver = NULL;
-		goto done;
-	}
 
 	udc->driver = driver;
 	if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
@@ -3535,26 +3637,23 @@
 			if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
 				hw_device_reset(udc);
 		} else {
-			put = true;
 			goto done;
 		}
 	}
 
-	if (!udc->softconnect) {
-		put = true;
+	if (!udc->softconnect)
 		goto done;
-	}
 
 	retval = hw_device_state(udc->ep0out.qh.dma);
 
- done:
+done:
 	spin_unlock_irqrestore(udc->lock, flags);
-	if (retval || put)
-		pm_runtime_put_sync(&udc->gadget.dev);
 
 	if (udc->udc_driver->notify_event)
-			udc->udc_driver->notify_event(udc,
+		udc->udc_driver->notify_event(udc,
 				CI13XXX_CONTROLLER_UDC_STARTED_EVENT);
+pm_put:
+	pm_runtime_put(&udc->gadget.dev);
 
 	return retval;
 }
@@ -3564,19 +3663,10 @@
  *
  * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
  */
-static int ci13xxx_stop(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget *gadget)
 {
 	struct ci13xxx *udc = _udc;
-	unsigned long i, flags;
-
-	trace("%p", driver);
-
-	if (driver             == NULL ||
-	    driver->unbind     == NULL ||
-	    driver->setup      == NULL ||
-	    driver->disconnect == NULL ||
-	    driver             != udc->driver)
-		return -EINVAL;
+	unsigned long flags;
 
 	spin_lock_irqsave(udc->lock, flags);
 
@@ -3586,44 +3676,13 @@
 		spin_unlock_irqrestore(udc->lock, flags);
 		_gadget_stop_activity(&udc->gadget);
 		spin_lock_irqsave(udc->lock, flags);
-		pm_runtime_put(&udc->gadget.dev);
 	}
 
-	/* unbind gadget */
 	spin_unlock_irqrestore(udc->lock, flags);
-	driver->unbind(&udc->gadget);               /* MAY SLEEP */
-	spin_lock_irqsave(udc->lock, flags);
 
 	usb_ep_free_request(&udc->ep0in.ep, udc->status);
 	kfree(udc->status_buf);
 
-	udc->gadget.dev.driver = NULL;
-
-	/* free resources */
-	for (i = 0; i < hw_ep_max; i++) {
-		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-
-		if (!list_empty(&mEp->ep.ep_list))
-			list_del_init(&mEp->ep.ep_list);
-
-		if (mEp->qh.ptr != NULL)
-			dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
-	}
-
-	udc->gadget.ep0 = NULL;
-	udc->driver = NULL;
-
-	spin_unlock_irqrestore(udc->lock, flags);
-
-	if (udc->td_pool != NULL) {
-		dma_pool_destroy(udc->td_pool);
-		udc->td_pool = NULL;
-	}
-	if (udc->qh_pool != NULL) {
-		dma_pool_destroy(udc->qh_pool);
-		udc->qh_pool = NULL;
-	}
-
 	return 0;
 }
 
@@ -3651,6 +3710,11 @@
 
 	spin_lock(udc->lock);
 
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		spin_unlock(udc->lock);
+		return IRQ_NONE;
+	}
+
 	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
 		if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
 				USBMODE_CM_DEVICE) {
@@ -3667,6 +3731,9 @@
 		/* order defines priority - do NOT change it */
 		if (USBi_URI & intr) {
 			isr_statistics.uri++;
+			if (!hw_cread(CAP_PORTSC, PORTSC_PR))
+				pr_info("%s: USB reset interrupt is delayed\n",
+								__func__);
 			isr_reset_handler(udc);
 		}
 		if (USBi_PCI & intr) {
@@ -3693,18 +3760,15 @@
 	return retval;
 }
 
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
+static void destroy_eps(struct ci13xxx *ci)
 {
-	trace("%p", dev);
+	int i;
 
-	if (dev == NULL)
-		err("EINVAL");
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+
+		dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+	}
 }
 
 /**
@@ -3722,9 +3786,9 @@
 {
 	struct ci13xxx *udc;
 	struct ci13xxx_platform_data *pdata;
-	int retval = 0, i;
+	int retval = 0, i, j;
 
-	trace("%p, %p, %p", dev, regs, driver->name);
+	trace("%pK, %pK, %pK", dev, regs, driver->name);
 
 	if (dev == NULL || regs == NULL || driver == NULL ||
 			driver->name == NULL)
@@ -3741,100 +3805,146 @@
 	udc->gadget.ops          = &usb_gadget_ops;
 	udc->gadget.speed        = USB_SPEED_UNKNOWN;
 	udc->gadget.max_speed    = USB_SPEED_HIGH;
-	if (udc->udc_driver->flags & CI13XXX_IS_OTG)
-		udc->gadget.is_otg       = 1;
-	else
-		udc->gadget.is_otg       = 0;
+	udc->gadget.is_otg       = 0;
 	udc->gadget.name         = driver->name;
 
-	INIT_LIST_HEAD(&udc->gadget.ep_list);
-	udc->gadget.ep0 = NULL;
+	/* alloc resources */
+	udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+				       sizeof(struct ci13xxx_qh),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->qh_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_udc;
+	}
 
-	pdata = dev->platform_data;
-	if (pdata)
-		udc->gadget.usb_core_id = pdata->usb_core_id;
-
-	dev_set_name(&udc->gadget.dev, "gadget");
-	udc->gadget.dev.dma_mask = dev->dma_mask;
-	udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
-	udc->gadget.dev.parent   = dev;
-	udc->gadget.dev.release  = udc_release;
-
-	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
-		udc->transceiver = usb_get_transceiver();
-		if (udc->transceiver == NULL) {
-			retval = -ENODEV;
-			goto free_udc;
-		}
+	udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+				       sizeof(struct ci13xxx_td),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->td_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_qh_pool;
 	}
 
 	INIT_DELAYED_WORK(&udc->rw_work, usb_do_remote_wakeup);
 
 	retval = hw_device_init(regs);
 	if (retval < 0)
-		goto put_transceiver;
+		goto free_qh_pool;
 
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
 	for (i = 0; i < hw_ep_max; i++) {
 		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
 		INIT_LIST_HEAD(&mEp->ep.ep_list);
+		INIT_LIST_HEAD(&mEp->rw_queue);
 		setup_timer(&mEp->prime_timer, ep_prime_timer_func,
 			(unsigned long) mEp);
 	}
 
+	for (i = 0; i < hw_ep_max/2; i++) {
+		for (j = RX; j <= TX; j++) {
+			int k = i + j * hw_ep_max/2;
+			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+					(j == TX)  ? "in" : "out");
+
+			mEp->lock         = udc->lock;
+			mEp->device       = &udc->gadget.dev;
+			mEp->td_pool      = udc->td_pool;
+
+			mEp->ep.name      = mEp->name;
+			mEp->ep.ops       = &usb_ep_ops;
+			usb_ep_set_maxpacket_limit(&mEp->ep,
+				k ? USHRT_MAX : CTRL_PAYLOAD_MAX);
+
+			INIT_LIST_HEAD(&mEp->qh.queue);
+			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+					&mEp->qh.dma);
+			if (mEp->qh.ptr == NULL)
+				retval = -ENOMEM;
+			else
+				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+			/* skip ep0 out and in endpoints  */
+			if (i == 0)
+				continue;
+
+			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+		}
+	}
+
+	if (retval)
+		goto free_dma_pools;
+
+	udc->gadget.ep0 = &udc->ep0in.ep;
+
+	pdata = dev->platform_data;
+	if (pdata) {
+		if (pdata->enable_axi_prefetch)
+			udc->gadget.extra_buf_alloc = EXTRA_ALLOCATION_SIZE;
+	}
+
+	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (udc->transceiver == NULL) {
+			retval = -ENODEV;
+			goto destroy_eps;
+		}
+	}
+
 	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
 		retval = hw_device_reset(udc);
 		if (retval)
 			goto put_transceiver;
 	}
 
-	retval = device_register(&udc->gadget.dev);
-	if (retval) {
-		put_device(&udc->gadget.dev);
-		goto put_transceiver;
-	}
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-	retval = dbg_create_files(&udc->gadget.dev);
-#endif
-	if (retval)
-		goto unreg_device;
-
 	if (udc->transceiver) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 		if (retval)
-			goto remove_dbg;
+			goto put_transceiver;
 	}
 
 	retval = usb_add_gadget_udc(dev, &udc->gadget);
 	if (retval)
 		goto remove_trans;
 
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	retval = dbg_create_files(&udc->gadget.dev);
+	if (retval) {
+		pr_err("Registering sysfs files for debug failed!!!!\n");
+		goto del_udc;
+	}
+#endif
+
 	pm_runtime_no_callbacks(&udc->gadget.dev);
+	pm_runtime_set_active(&udc->gadget.dev);
 	pm_runtime_enable(&udc->gadget.dev);
 
-	if (register_trace_usb_daytona_invalid_access(dump_usb_info, NULL))
-		pr_err("Registering trace failed\n");
+	/* Use delayed LPM especially for composition-switch in LPM (suspend) */
+	pm_runtime_set_autosuspend_delay(&udc->gadget.dev, 2000);
+	pm_runtime_use_autosuspend(&udc->gadget.dev);
 
 	_udc = udc;
 	return retval;
 
+del_udc:
+	usb_del_gadget_udc(&udc->gadget);
 remove_trans:
-	if (udc->transceiver) {
+	if (udc->transceiver)
 		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
-		usb_put_transceiver(udc->transceiver);
-	}
 
 	err("error = %i", retval);
-remove_dbg:
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-	dbg_remove_files(&udc->gadget.dev);
-#endif
-unreg_device:
-	device_unregister(&udc->gadget.dev);
 put_transceiver:
 	if (udc->transceiver)
-		usb_put_transceiver(udc->transceiver);
+		usb_put_phy(udc->transceiver);
+destroy_eps:
+	destroy_eps(udc);
+free_dma_pools:
+	dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+	dma_pool_destroy(udc->qh_pool);
 free_udc:
 	kfree(udc);
 	_udc = NULL;
@@ -3849,27 +3959,24 @@
 static void udc_remove(void)
 {
 	struct ci13xxx *udc = _udc;
-	int retval;
 
 	if (udc == NULL) {
 		err("EINVAL");
 		return;
 	}
-	retval = unregister_trace_usb_daytona_invalid_access(dump_usb_info,
-									NULL);
-	if (retval)
-		pr_err("Unregistering trace failed\n");
 
 	usb_del_gadget_udc(&udc->gadget);
 
 	if (udc->transceiver) {
 		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
-		usb_put_transceiver(udc->transceiver);
+		usb_put_phy(udc->transceiver);
 	}
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	dbg_remove_files(&udc->gadget.dev);
 #endif
-	device_unregister(&udc->gadget.dev);
+	destroy_eps(udc);
+	dma_pool_destroy(udc->td_pool);
+	dma_pool_destroy(udc->qh_pool);
 
 	kfree(udc);
 	_udc = NULL;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..8c93080 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -57,7 +57,7 @@
 #define TD_CURR_OFFSET        (0x0FFFUL <<  0)
 #define TD_FRAME_NUM          (0x07FFUL <<  0)
 #define TD_RESERVED_MASK      (0x0FFFUL <<  0)
-} __attribute__ ((packed, aligned(4)));
+} __packed __aligned(4);
 
 /* DMA layout of queue heads */
 struct ci13xxx_qh {
@@ -75,19 +75,19 @@
 	/* 9 */
 	u32 RESERVED;
 	struct usb_ctrlrequest   setup;
-} __attribute__ ((packed, aligned(4)));
+} __packed __aligned(4);
 
 /* cache of larger request's original attributes */
 struct ci13xxx_multi_req {
-	unsigned             len;
-	unsigned             actual;
+	unsigned int	     len;
+	unsigned int	     actual;
 	void                *buf;
 };
 
 /* Extension of usb_request */
 struct ci13xxx_req {
 	struct usb_request   req;
-	unsigned             map;
+	unsigned int	     map;
 	struct list_head     queue;
 	struct ci13xxx_td   *ptr;
 	dma_addr_t           dma;
@@ -109,6 +109,7 @@
 		struct ci13xxx_qh *ptr;
 		dma_addr_t         dma;
 	}                                      qh;
+	struct list_head                       rw_queue;
 	int                                    wedge;
 
 	/* global resources */
@@ -117,7 +118,8 @@
 	struct dma_pool                       *td_pool;
 	struct ci13xxx_td                     *last_zptr;
 	dma_addr_t                            last_zdma;
-	unsigned long dTD_update_fail_count;
+	unsigned long                         dTD_update_fail_count;
+	unsigned long                         dTD_active_re_q_count;
 	unsigned long			      prime_fail_count;
 	int				      prime_timer_count;
 	struct timer_list		      prime_timer;
@@ -135,7 +137,7 @@
 #define CI13XXX_PULLUP_ON_VBUS		BIT(2)
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 #define CI13XXX_ZERO_ITC		BIT(4)
-#define CI13XXX_IS_OTG			BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT			0
 #define CI13XXX_CONTROLLER_CONNECT_EVENT		1
@@ -144,8 +146,10 @@
 #define CI13XXX_CONTROLLER_RESUME_EVENT		4
 #define CI13XXX_CONTROLLER_DISCONNECT_EVENT		5
 #define CI13XXX_CONTROLLER_UDC_STARTED_EVENT		6
+#define CI13XXX_CONTROLLER_ERROR_EVENT			7
 
-	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
+	void	(*notify_event)(struct ci13xxx *udc, unsigned int event);
+	bool    (*in_lpm)(struct ci13xxx *udc);
 };
 
 /* CI13XXX UDC descriptor & global resources */
@@ -163,12 +167,10 @@
 	u32                        ep0_dir;    /* ep0 direction */
 #define ep0out ci13xxx_ep[0]
 #define ep0in  ci13xxx_ep[hw_ep_max / 2]
-	u8                         remote_wakeup; /* Is remote wakeup feature
-							enabled by the host? */
 	u8                         suspended;  /* suspended by the host */
 	u8                         configured;  /* is device configured */
 	u8                         test_mode;  /* the selected test mode */
-
+	bool                       rw_pending; /* Remote wakeup pending flag */
 	struct delayed_work        rw_work;    /* remote wakeup delayed work */
 	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
 	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
@@ -176,9 +178,11 @@
 	int                        softconnect; /* is pull-up enable allowed */
 	unsigned long dTD_update_fail_count;
 	struct usb_phy            *transceiver; /* Transceiver struct */
-	bool                      skip_flush; /* skip flushing remaining EP
-						upon flush timeout for the
-						first EP. */
+	bool                      skip_flush;   /*
+						 * skip flushing remaining EP
+						 * upon flush timeout for the
+						 * first EP.
+						 */
 };
 
 /******************************************************************************
@@ -197,6 +201,9 @@
 /* TESTMODE */
 #define TESTMODE_FORCE        BIT(0)
 
+/* AHB_MODE */
+#define AHB2AHB_BYPASS	      BIT(31)
+
 /* USBCMD */
 #define USBCMD_RS             BIT(0)
 #define USBCMD_RST            BIT(1)
@@ -217,6 +224,7 @@
 /* PORTSC */
 #define PORTSC_FPR            BIT(6)
 #define PORTSC_SUSP           BIT(7)
+#define PORTSC_PR             BIT(8)
 #define PORTSC_HSP            BIT(9)
 #define PORTSC_PTC            (0x0FUL << 16)
 
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 4bdfadf..41aa62d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1655,11 +1655,10 @@
 
 	buf = (rndis_init_msg_type *)req->buf;
 	if (buf->MessageType == RNDIS_MSG_INIT) {
-		gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
-						gsi->params->dl_max_xfer_size);
-		log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
-				gsi->params->dl_max_xfer_size,
-				gsi->d_port.in_aggr_size);
+		/* honor host dl aggr size */
+		gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
+		log_event_dbg("RNDIS host dl_aggr_size:%d\n",
+				gsi->params->dl_max_xfer_size);
 	}
 }
 
@@ -2565,7 +2564,7 @@
 		info.out_epname = "gsi-epout";
 		info.in_req_buf_len = GSI_IN_BUFF_SIZE;
 		gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE;
-		info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
+		info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS;
 		gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
 		info.out_req_buf_len = GSI_OUT_AGGR_SIZE;
 		info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 58a7706..71bea5e 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -34,13 +34,13 @@
 #define GSI_MAX_CTRL_PKT_SIZE 4096
 #define GSI_CTRL_DTR (1 << 0)
 
-
+#define GSI_NUM_IN_RNDIS_BUFFERS 50
 #define GSI_NUM_IN_BUFFERS 15
 #define GSI_IN_BUFF_SIZE 2048
 #define GSI_NUM_OUT_BUFFERS 14
 #define GSI_OUT_AGGR_SIZE 24576
 
-#define GSI_IN_RNDIS_AGGR_SIZE 9216
+#define GSI_IN_RNDIS_AGGR_SIZE 16384
 #define GSI_IN_MBIM_AGGR_SIZE 16384
 #define GSI_IN_RMNET_AGGR_SIZE 16384
 #define GSI_ECM_AGGR_SIZE 2048
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 54220a5..d50510f 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -21,6 +21,8 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/msm_rmnet.h>
 
 #include "u_ether.h"
 
@@ -89,6 +91,8 @@
 	struct work_struct	rx_work;
 
 	unsigned long		todo;
+	unsigned long		flags;
+	unsigned short		rx_needed_headroom;
 #define	WORK_RX_MEMORY		0
 
 	bool			zlp;
@@ -161,6 +165,25 @@
 	return 0;
 }
 
+static int ueth_change_mtu_ip(struct net_device *net, int new_mtu)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	unsigned long	flags;
+	int		status = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (new_mtu <= 0)
+		status = -EINVAL;
+	else
+		net->mtu = new_mtu;
+
+	DBG(dev, "[%s] MTU change: old=%d new=%d\n", net->name,
+					net->mtu, new_mtu);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return status;
+}
+
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
 	struct eth_dev *dev = netdev_priv(net);
@@ -900,15 +923,176 @@
 	return 18;
 }
 
+static int ether_ioctl(struct net_device *, struct ifreq *, int);
+
 static const struct net_device_ops eth_netdev_ops = {
 	.ndo_open		= eth_open,
 	.ndo_stop		= eth_stop,
 	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
 	.ndo_change_mtu		= ueth_change_mtu,
 	.ndo_set_mac_address 	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
+static const struct net_device_ops eth_netdev_ops_ip = {
+	.ndo_open		= eth_open,
+	.ndo_stop		= eth_stop,
+	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
+	.ndo_change_mtu		= ueth_change_mtu_ip,
+	.ndo_set_mac_address	= NULL,
+	.ndo_validate_addr	= NULL,
+};
+
+static int rmnet_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
+{
+	struct rmnet_ioctl_extended_s ext_cmd;
+	struct eth_dev *eth_dev = netdev_priv(dev);
+	int rc = 0;
+
+	rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data,
+			    sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc) {
+		DBG(eth_dev, "%s(): copy_from_user() failed\n", __func__);
+		return rc;
+	}
+
+	switch (ext_cmd.extended_ioctl) {
+	case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
+		ext_cmd.u.data = 0;
+		break;
+
+	case RMNET_IOCTL_SET_MRU:
+		if (netif_running(dev))
+			return -EBUSY;
+
+		/* 16K max */
+		if ((size_t)ext_cmd.u.data > 0x4000)
+			return -EINVAL;
+
+		if (eth_dev->port_usb) {
+			eth_dev->port_usb->is_fixed = true;
+			eth_dev->port_usb->fixed_out_len =
+				(size_t) ext_cmd.u.data;
+			DBG(eth_dev, "[%s] rmnet_ioctl(): SET MRU to %u\n",
+				dev->name, eth_dev->port_usb->fixed_out_len);
+		} else {
+			pr_err("[%s]: %s: SET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_MRU:
+		if (eth_dev->port_usb) {
+			ext_cmd.u.data = eth_dev->port_usb->is_fixed ?
+					eth_dev->port_usb->fixed_out_len :
+					dev->mtu;
+		} else {
+			pr_err("[%s]: %s: GET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_DRIVER_NAME:
+		strlcpy(ext_cmd.u.if_name, dev->name,
+			sizeof(ext_cmd.u.if_name));
+		break;
+
+	default:
+		break;
+	}
+
+	rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd,
+			  sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc)
+		DBG(eth_dev, "%s(): copy_to_user() failed\n", __func__);
+	return rc;
+}
+
+static int ether_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct eth_dev	*eth_dev = netdev_priv(dev);
+	void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
+	int		prev_mtu = dev->mtu;
+	u32		state, old_opmode;
+	int		rc = -EFAULT;
+
+	old_opmode = eth_dev->flags;
+	/* Process IOCTL command */
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_ETHERNET:	/*Set Ethernet protocol*/
+		/* Perform Ethernet config only if in IP mode currently*/
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags)) {
+			ether_setup(dev);
+			dev->mtu = prev_mtu;
+			dev->netdev_ops = &eth_netdev_ops;
+			clear_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set Ethernet proto mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_LLP_IP:		/* Set RAWIP protocol*/
+		/* Perform IP config only if in Ethernet mode currently*/
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags)) {
+			/* Undo config done in ether_setup() */
+			dev->header_ops = NULL;  /* No header */
+			dev->type = ARPHRD_RAWIP;
+			dev->hard_header_len = 0;
+			dev->mtu = prev_mtu;
+			dev->addr_len = 0;
+			dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+			dev->netdev_ops = &eth_netdev_ops_ip;
+			clear_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set IP protocol mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_GET_LLP:	/* Get link protocol state */
+		state = eth_dev->flags & (RMNET_MODE_LLP_ETH
+						| RMNET_MODE_LLP_IP);
+		if (copy_to_user(addr, &state, sizeof(state)))
+			break;
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_RX_HEADROOM:	/* Set RX headroom */
+		if (copy_from_user(&eth_dev->rx_needed_headroom, addr,
+					sizeof(eth_dev->rx_needed_headroom)))
+			break;
+		DBG(eth_dev, "[%s] ioctl(): set RX HEADROOM: %x\n",
+				dev->name, eth_dev->rx_needed_headroom);
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_EXTENDED:
+		rc = rmnet_ioctl_extended(dev, ifr);
+		break;
+
+	default:
+		pr_err("[%s] error: ioctl called for unsupported cmd[%d]",
+			dev->name, cmd);
+		rc = -EINVAL;
+	}
+
+	DBG(eth_dev, "[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+		dev->name, __func__, cmd, old_opmode, eth_dev->flags);
+
+	return rc;
+}
+
 static struct device_type gadget_type = {
 	.name	= "gadget",
 };
@@ -968,6 +1152,9 @@
 
 	net->ethtool_ops = &ops;
 
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	dev->gadget = g;
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
@@ -1025,6 +1212,10 @@
 	net->netdev_ops = &eth_netdev_ops;
 
 	net->ethtool_ops = &ops;
+
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
 
 	return net;
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index f472b2b..42028cc 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -391,7 +391,6 @@
 
 config USB_CI13XXX_MSM
 	tristate "MIPS USB CI13xxx for MSM"
-	depends on ARCH_MSM
 	select USB_MSM_OTG
 	help
 	  MSM SoC has chipidea USB controller.  This driver uses
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 19f3f18..95105d1 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -71,6 +71,8 @@
 #define SQ_CTRL1_CHIRP_DISABLE		0x20
 #define SQ_CTRL2_CHIRP_DISABLE		0x80
 
+#define DEBUG_CTRL1_OVERRIDE_VAL	0x09
+
 /* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
 #define BANDGAP_BYPASS			BIT(0)
 
@@ -84,6 +86,7 @@
 	BIAS_CTRL_2,
 	SQ_CTRL1,
 	SQ_CTRL2,
+	DEBUG_CTRL1,
 	USB2_PHY_REG_MAX,
 };
 
@@ -553,6 +556,11 @@
 			writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
 				qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
 
+	/* if soc revision is mentioned override DEBUG_CTRL1 value */
+	if (qphy->soc_min_rev)
+		writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+				qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+
 	/* ensure above writes are completed before re-enabling PHY */
 	wmb();
 
@@ -1228,7 +1236,7 @@
 	 * qusb_phy_disable_chirp is not required if soc version is
 	 * mentioned and is not base version.
 	 */
-	if (qphy->soc_min_rev == 0)
+	if (!qphy->soc_min_rev)
 		qphy->phy.disable_chirp	= qusb_phy_disable_chirp;
 
 	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index fd84889..3482c93 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -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
@@ -422,6 +422,28 @@
 
 static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
 {
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+	if (phy->suspended && suspend) {
+		dev_dbg(uphy->dev, "%s: USB PHY is already suspended\n",
+			__func__);
+		return 0;
+	}
+
+	if (suspend) { /* Bus suspend */
+		if (phy->cable_connected ||
+			(phy->phy.flags & PHY_HOST_MODE)) {
+			msm_hsphy_enable_clocks(phy, false);
+		} else {/* Cable disconnect */
+			msm_hsphy_enable_clocks(phy, false);
+			msm_hsphy_enable_power(phy, false);
+		}
+		phy->suspended = true;
+	} else { /* Bus resume and cable connect */
+			msm_hsphy_enable_clocks(phy, true);
+			phy->suspended = false;
+		}
+
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c
index b7c8d43..089d32d 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.c
+++ b/drivers/video/fbdev/msm/mdp3_dma.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
  * only version 2 as published by the Free Software Foundation.
diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h
index 6c8e7fe..24caedb9 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.h
+++ b/drivers/video/fbdev/msm/mdp3_dma.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
  * only version 2 as published by the Free Software Foundation.
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index d84cf5e..1cbaa44 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -79,10 +79,10 @@
 
 	if (level == 0) {
 		if (ctrl->pwm_enabled) {
-			ret = pwm_config_us(ctrl->pwm_bl, level,
-					ctrl->pwm_period);
+			ret = pwm_config(ctrl->pwm_bl, 0,
+					ctrl->pwm_period * NSEC_PER_USEC);
 			if (ret)
-				pr_err("%s: pwm_config_us() failed err=%d.\n",
+				pr_err("%s: pwm_config() failed err=%d.\n",
 						__func__, ret);
 			pwm_disable(ctrl->pwm_bl);
 		}
diff --git a/drivers/video/fbdev/msm/mdss_edp_aux.c b/drivers/video/fbdev/msm/mdss_edp_aux.c
index 8ba715d..268daaa 100644
--- a/drivers/video/fbdev/msm/mdss_edp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_edp_aux.c
@@ -607,7 +607,6 @@
 
 /*
  * EDID structure can be found in VESA standard here:
- * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
  *
  * following table contains default edid
  * static char edid_raw_data[128] = {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index 02ddced..44817c3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index fffaad4..0b3b223 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -32,23 +32,20 @@
 	ci->data->under_android = pi->data->under_android;
 	ci->data->under_cache = pi->data->under_cache;
 	ci->data->under_obb = pi->data->under_obb;
-	set_top(ci, pi->top_data);
 }
 
 /* helper function for derived state */
 void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
-					uid_t uid, bool under_android,
-					struct sdcardfs_inode_data *top)
+					uid_t uid)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 
 	info->data->perm = perm;
 	info->data->userid = userid;
 	info->data->d_uid = uid;
-	info->data->under_android = under_android;
+	info->data->under_android = false;
 	info->data->under_cache = false;
 	info->data->under_obb = false;
-	set_top(info, top);
 }
 
 /* While renaming, there is a point where we want the path from dentry,
@@ -58,8 +55,8 @@
 				const struct qstr *name)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
-	struct sdcardfs_inode_data *parent_data =
-			SDCARDFS_I(d_inode(parent))->data;
+	struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent));
+	struct sdcardfs_inode_data *parent_data = parent_info->data;
 	appid_t appid;
 	unsigned long user_num;
 	int err;
@@ -80,13 +77,15 @@
 	inherit_derived_state(d_inode(parent), d_inode(dentry));
 
 	/* Files don't get special labels */
-	if (!S_ISDIR(d_inode(dentry)->i_mode))
+	if (!S_ISDIR(d_inode(dentry)->i_mode)) {
+		set_top(info, parent_info);
 		return;
+	}
 	/* Derive custom permissions based on parent and current node */
 	switch (parent_data->perm) {
 	case PERM_INHERIT:
 	case PERM_ANDROID_PACKAGE_CACHE:
-		/* Already inherited above */
+		set_top(info, parent_info);
 		break;
 	case PERM_PRE_ROOT:
 		/* Legacy internal layout places users at top level */
@@ -96,7 +95,6 @@
 			info->data->userid = 0;
 		else
 			info->data->userid = user_num;
-		set_top(info, info->data);
 		break;
 	case PERM_ROOT:
 		/* Assume masked off by default. */
@@ -104,24 +102,24 @@
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID;
 			info->data->under_android = true;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID:
 		if (qstr_case_eq(name, &q_data)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_DATA;
-			set_top(info, info->data);
 		} else if (qstr_case_eq(name, &q_obb)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_OBB;
 			info->data->under_obb = true;
-			set_top(info, info->data);
 			/* Single OBB directory is always shared */
 		} else if (qstr_case_eq(name, &q_media)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_MEDIA;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID_OBB:
@@ -132,13 +130,13 @@
 		if (appid != 0 && !is_excluded(name->name, parent_data->userid))
 			info->data->d_uid =
 				multiuser_get_uid(parent_data->userid, appid);
-		set_top(info, info->data);
 		break;
 	case PERM_ANDROID_PACKAGE:
 		if (qstr_case_eq(name, &q_cache)) {
 			info->data->perm = PERM_ANDROID_PACKAGE_CACHE;
 			info->data->under_cache = true;
 		}
+		set_top(info, parent_info);
 		break;
 	}
 }
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 8ed0ea1..137d876 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -821,8 +821,8 @@
 	return err;
 }
 
-static int sdcardfs_fillattr(struct vfsmount *mnt,
-				struct inode *inode, struct kstat *stat)
+static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode,
+				struct kstat *lower_stat, struct kstat *stat)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 	struct sdcardfs_inode_data *top = top_data_get(info);
@@ -837,12 +837,12 @@
 	stat->uid = make_kuid(&init_user_ns, top->d_uid);
 	stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
 	stat->rdev = inode->i_rdev;
-	stat->size = i_size_read(inode);
-	stat->atime = inode->i_atime;
-	stat->mtime = inode->i_mtime;
-	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
-	stat->blocks = inode->i_blocks;
+	stat->size = lower_stat->size;
+	stat->atime = lower_stat->atime;
+	stat->mtime = lower_stat->mtime;
+	stat->ctime = lower_stat->ctime;
+	stat->blksize = lower_stat->blksize;
+	stat->blocks = lower_stat->blocks;
 	data_put(top);
 	return 0;
 }
@@ -868,8 +868,7 @@
 		goto out;
 	sdcardfs_copy_and_fix_attrs(d_inode(dentry),
 			      d_inode(lower_path.dentry));
-	err = sdcardfs_fillattr(mnt, d_inode(dentry), stat);
-	stat->blocks = lower_stat.blocks;
+	err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat);
 out:
 	sdcardfs_put_lower_path(dentry, &lower_path);
 	return err;
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 0a2b516..37d4864 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -334,13 +334,11 @@
 	mutex_lock(&sdcardfs_super_list_lock);
 	if (sb_info->options.multiuser) {
 		setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
 	} else {
 		setup_derived_state(d_inode(sb->s_root), PERM_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
 	}
 	fixup_tmp_permissions(d_inode(sb->s_root));
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index d1d8bab..eda8e7a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -201,6 +201,7 @@
 	struct sdcardfs_inode_data *data;
 
 	/* top folder for ownership */
+	spinlock_t top_lock;
 	struct sdcardfs_inode_data *top_data;
 
 	struct inode vfs_inode;
@@ -379,7 +380,12 @@
 static inline struct sdcardfs_inode_data *top_data_get(
 		struct sdcardfs_inode_info *info)
 {
-	return data_get(info->top_data);
+	struct sdcardfs_inode_data *top_data;
+
+	spin_lock(&info->top_lock);
+	top_data = data_get(info->top_data);
+	spin_unlock(&info->top_lock);
+	return top_data;
 }
 
 extern void data_release(struct kref *ref);
@@ -401,15 +407,20 @@
 }
 
 static inline void set_top(struct sdcardfs_inode_info *info,
-			struct sdcardfs_inode_data *top)
+			struct sdcardfs_inode_info *top_owner)
 {
-	struct sdcardfs_inode_data *old_top = info->top_data;
+	struct sdcardfs_inode_data *old_top;
+	struct sdcardfs_inode_data *new_top = NULL;
 
-	if (top)
-		data_get(top);
-	info->top_data = top;
+	if (top_owner)
+		new_top = top_data_get(top_owner);
+
+	spin_lock(&info->top_lock);
+	old_top = info->top_data;
+	info->top_data = new_top;
 	if (old_top)
 		data_put(old_top);
+	spin_unlock(&info->top_lock);
 }
 
 static inline int get_gid(struct vfsmount *mnt,
@@ -513,8 +524,7 @@
 };
 
 extern void setup_derived_state(struct inode *inode, perm_t perm,
-		userid_t userid, uid_t uid, bool under_android,
-		struct sdcardfs_inode_data *top);
+			userid_t userid, uid_t uid);
 extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
 extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name);
 extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index b89947d..72d89b9 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -215,6 +215,9 @@
 
 	i->data = d;
 	kref_init(&d->refcount);
+	i->top_data = d;
+	spin_lock_init(&i->top_lock);
+	kref_get(&d->refcount);
 
 	i->vfs_inode.i_version = 1;
 	return &i->vfs_inode;
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6..07b2e96 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -59,6 +59,23 @@
 	void (*detach)(struct drm_bridge *bridge);
 
 	/**
+	 * @connector_init:
+	 *
+	 * This callback is used to init the connector from bridge side. In some
+	 * cases connector and bridge are created in different modules, and the
+	 * connector ops might need extra info from bridge. This callback offers
+	 * the opportunity to overwrite connector's behavior in external bridge.
+	 *
+	 * The connector_init callback is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * Zero on success, error code on failure.
+	 */
+	int (*connector_init)(struct drm_bridge *bridge,
+				struct drm_connector *connector);
+
+	/**
 	 * @mode_fixup:
 	 *
 	 * This callback is used to validate and adjust a mode. The paramater
@@ -214,5 +231,7 @@
 			struct drm_display_mode *adjusted_mode);
 void drm_bridge_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_enable(struct drm_bridge *bridge);
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector);
 
 #endif
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index b28c4a3..9a5114d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -560,6 +560,7 @@
  * @tile_v_loc: vertical location of this tile
  * @tile_h_size: horizontal size of this tile.
  * @tile_v_size: vertical size of this tile.
+ * @private: connector private data.
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -726,6 +727,8 @@
 	uint8_t num_h_tile, num_v_tile;
 	uint8_t tile_h_loc, tile_v_loc;
 	uint16_t tile_h_size, tile_v_size;
+
+	void *private;
 };
 
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 0dbddb3..3c2024d 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -140,6 +140,10 @@
 #define MIPI_DSI_CLOCK_NON_CONTINUOUS	BIT(10)
 /* transmit data in low power */
 #define MIPI_DSI_MODE_LPM		BIT(11)
+/* disable BLLP area */
+#define MIPI_DSI_MODE_VIDEO_BLLP	BIT(12)
+/* disable EOF BLLP area */
+#define MIPI_DSI_MODE_VIDEO_EOF_BLLP	BIT(13)
 
 enum mipi_dsi_pixel_format {
 	MIPI_DSI_FMT_RGB888,
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
index afaa08a20..d5a5457 100644
--- a/include/linux/msm_hdmi.h
+++ b/include/linux/msm_hdmi.h
@@ -1,10 +1,6 @@
 /* include/linux/msm_hdmi.h
  *
-<<<<<<< HEAD
  * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
-=======
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
->>>>>>> dfa46f9... fbdev: msm: fix compilation error
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 164abe2..61c557a 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -272,8 +272,11 @@
 	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_RECHARGE_SOC,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 62c770d..290e2b2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1777,7 +1777,7 @@
 	u32 init_load_pct;
 	u64 last_wake_ts;
 	u64 last_switch_out_ts;
-	u64 last_cpu_selected_ts;
+	u64 last_enqueued_ts;
 	struct related_thread_group *grp;
 	struct list_head grp_list;
 	u64 cpu_cycles;
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 12bd032..3e97574 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -34,6 +34,7 @@
 extern unsigned int sysctl_sched_boost;
 extern unsigned int sysctl_sched_group_upmigrate_pct;
 extern unsigned int sysctl_sched_group_downmigrate_pct;
+extern unsigned int sysctl_sched_walt_rotate_big_tasks;
 
 extern int
 walt_proc_update_handler(struct ctl_table *table, int write,
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3fda92f..6acd229 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -478,6 +478,9 @@
  * @deactivated: True if gadget is deactivated - in deactivated state it cannot
  *	be connected.
  * @connected: True if gadget is connected.
+ * @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
+ * @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
+ * boundary access is protected.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -531,6 +534,9 @@
 	unsigned			deactivated:1;
 	unsigned			connected:1;
 	bool				remote_wakeup;
+	bool				bam2bam_func_enabled;
+	u32				extra_buf_alloc;
+	bool				l1_supported;
 };
 #define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
 
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index daa245d..2f90ddc 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -21,6 +21,7 @@
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG        (MSM_USB_BASE + 0x009C)
 #define USB_GENCONFIG_2      (MSM_USB_BASE + 0x00a0)
 #define ULPI_TX_PKT_EN_CLR_FIX	BIT(19)
 
@@ -47,6 +48,14 @@
 #define AHB2AHB_BYPASS          BIT(31)
 #define AHB2AHB_BYPASS_BIT_MASK        BIT(31)
 #define AHB2AHB_BYPASS_CLEAR   (0 << 31)
+#define USB_L1_EP_CTRL       (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG        (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN        BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK	BIT(7)
+#define L1_CONFIG_PHY_LPM	BIT(10)
+#define L1_CONFIG_PLL		BIT(11)
 
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK        (3 << 30)
@@ -64,6 +73,10 @@
 #define ULPI_DATA(n)          ((n) & 255)
 #define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
 
+#define GENCONFIG_BAM_DISABLE (1 << 13)
+#define GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE (1 << 4)
+#define GENCONFIG_ULPI_SERIAL_EN (1 << 5)
+
 /* synopsys 28nm phy registers */
 #define ULPI_PWR_CLK_MNG_REG	0x88
 #define OTG_COMP_DISABLE	BIT(0)
diff --git a/include/net/cnss.h b/include/net/cnss.h
new file mode 100644
index 0000000..368d01e
--- /dev/null
+++ b/include/net/cnss.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013-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.
+ */
+#ifndef _NET_CNSS_H_
+#define _NET_CNSS_H_
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_CNSS
+#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+#define CNSS_MAX_FILE_NAME	20
+#define PINCTRL_SLEEP  0
+#define PINCTRL_ACTIVE 1
+
+enum cnss_bus_width_type {
+	CNSS_BUS_WIDTH_NONE,
+	CNSS_BUS_WIDTH_LOW,
+	CNSS_BUS_WIDTH_MEDIUM,
+	CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_cc_src {
+	CNSS_SOURCE_CORE,
+	CNSS_SOURCE_11D,
+	CNSS_SOURCE_USER
+};
+
+/* FW image files */
+struct cnss_fw_files {
+	char image_file[CNSS_MAX_FILE_NAME];
+	char board_data[CNSS_MAX_FILE_NAME];
+	char otp_data[CNSS_MAX_FILE_NAME];
+	char utf_file[CNSS_MAX_FILE_NAME];
+	char utf_board_data[CNSS_MAX_FILE_NAME];
+	char epping_file[CNSS_MAX_FILE_NAME];
+	char evicted_data[CNSS_MAX_FILE_NAME];
+};
+
+struct cnss_wlan_runtime_ops {
+	int (*runtime_suspend)(struct pci_dev *pdev);
+	int (*runtime_resume)(struct pci_dev *pdev);
+};
+
+struct cnss_wlan_driver {
+	char *name;
+	int  (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*remove)(struct pci_dev *pdev);
+	int  (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*shutdown)(struct pci_dev *pdev);
+	void (*crash_shutdown)(struct pci_dev *pdev);
+	int  (*suspend)(struct pci_dev *pdev, pm_message_t state);
+	int  (*resume)(struct pci_dev *pdev);
+	void (*modem_status)(struct pci_dev *, int state);
+	void (*update_status)(struct pci_dev *pdev, uint32_t status);
+	struct cnss_wlan_runtime_ops *runtime_ops;
+	const struct pci_device_id *id_table;
+};
+
+/*
+ * codeseg_total_bytes: Total bytes across all the codesegment blocks
+ * num_codesegs: No of Pages used
+ * codeseg_size: Size of each segment. Should be power of 2 and multiple of 4K
+ * codeseg_size_log2: log2(codeseg_size)
+ * codeseg_busaddr: Physical address of the DMAble memory;4K aligned
+ */
+
+#define CODESWAP_MAX_CODESEGS 16
+struct codeswap_codeseg_info {
+	u32   codeseg_total_bytes;
+	u32   num_codesegs;
+	u32   codeseg_size;
+	u32   codeseg_size_log2;
+	void *codeseg_busaddr[CODESWAP_MAX_CODESEGS];
+};
+
+struct image_desc_info {
+	dma_addr_t fw_addr;
+	u32 fw_size;
+	dma_addr_t bdata_addr;
+	u32 bdata_size;
+};
+
+/* platform capabilities */
+enum cnss_platform_cap_flag {
+	CNSS_HAS_EXTERNAL_SWREG = 0x01,
+	CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+	u32 cap_flag;
+};
+
+/* WLAN driver status */
+enum cnss_driver_status {
+	CNSS_UNINITIALIZED,
+	CNSS_INITIALIZED,
+	CNSS_LOAD_UNLOAD
+};
+
+enum cnss_runtime_request {
+	CNSS_PM_RUNTIME_GET,
+	CNSS_PM_RUNTIME_PUT,
+	CNSS_PM_RUNTIME_MARK_LAST_BUSY,
+	CNSS_PM_RUNTIME_RESUME,
+	CNSS_PM_RUNTIME_PUT_NOIDLE,
+	CNSS_PM_REQUEST_RESUME,
+	CNSS_PM_RUNTIME_PUT_AUTO,
+	CNSS_PM_GET_NORESUME,
+};
+
+extern int cnss_get_fw_image(struct image_desc_info *image_desc_info);
+extern void cnss_runtime_init(struct device *dev, int auto_delay);
+extern void cnss_runtime_exit(struct device *dev);
+extern void cnss_wlan_pci_link_down(void);
+extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable);
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files);
+extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+					u32 target_type, u32 target_version);
+extern void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+					u32 size, u32 tufello_dual_fw);
+
+extern int cnss_request_bus_bandwidth(int bandwidth);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+extern int cnss_get_sha_hash(const u8 *data, u32 data_len,
+					u8 *hash_idx, u8 *out);
+extern void *cnss_get_fw_ptr(void);
+#endif
+
+extern int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg);
+extern int cnss_get_bmi_setup(void);
+
+#ifdef CONFIG_PCI_MSM
+extern int cnss_wlan_pm_control(bool vote);
+#endif
+extern void cnss_lock_pm_sem(void);
+extern void cnss_release_pm_sem(void);
+
+extern void cnss_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_request_pm_qos(u32 qos_val);
+extern void cnss_remove_pm_qos(void);
+
+extern void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_pci_request_pm_qos(u32 qos_val);
+extern void cnss_pci_remove_pm_qos(void);
+
+extern void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_sdio_request_pm_qos(u32 qos_val);
+extern void cnss_sdio_remove_pm_qos(void);
+
+extern int cnss_get_platform_cap(struct cnss_platform_cap *cap);
+extern void cnss_set_driver_status(enum cnss_driver_status driver_status);
+
+#ifndef CONFIG_WCNSS_MEM_PRE_ALLOC
+static inline int wcnss_pre_alloc_reset(void) { return 0; }
+#endif
+
+extern int msm_pcie_enumerate(u32 rc_idx);
+extern int cnss_auto_suspend(void);
+extern int cnss_auto_resume(void);
+extern int cnss_prevent_auto_suspend(const char *caller_func);
+extern int cnss_allow_auto_suspend(const char *caller_func);
+extern int cnss_is_auto_suspend_allowed(const char *caller_func);
+
+extern int cnss_pm_runtime_request(struct device *dev, enum
+		cnss_runtime_request request);
+extern void cnss_set_cc_source(enum cnss_cc_src cc_source);
+extern enum cnss_cc_src cnss_get_cc_source(void);
+#endif
+
+extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name);
+extern void cnss_pm_wake_lock(struct wakeup_source *ws);
+
+extern void cnss_device_crashed(void);
+extern void cnss_device_self_recovery(void);
+extern void *cnss_get_virt_ramdump_mem(unsigned long *size);
+
+extern void cnss_schedule_recovery_work(void);
+extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
+extern u8 *cnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
+
+enum {
+	CNSS_RESET_SOC = 0,
+	CNSS_RESET_SUBSYS_COUPLED,
+	CNSS_RESET_LEVEL_MAX
+};
+extern int cnss_get_restart_level(void);
+
+struct cnss_sdio_wlan_driver {
+	const char *name;
+	const struct sdio_device_id *id_table;
+	int (*probe)(struct sdio_func *, const struct sdio_device_id *);
+	void (*remove)(struct sdio_func *);
+	int (*reinit)(struct sdio_func *, const struct sdio_device_id *);
+	void (*shutdown)(struct sdio_func *);
+	void (*crash_shutdown)(struct sdio_func *);
+	int (*suspend)(struct device *);
+	int (*resume)(struct device *);
+};
+
+extern int cnss_sdio_wlan_register_driver(
+	struct cnss_sdio_wlan_driver *driver);
+extern void cnss_sdio_wlan_unregister_driver(
+	struct cnss_sdio_wlan_driver *driver);
+
+typedef void (*oob_irq_handler_t)(void *dev_para);
+extern int cnss_wlan_query_oob_status(void);
+extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler,
+	    void *pm_oob);
+extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob);
+
+
+extern void cnss_dump_stack(struct task_struct *task);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern void cnss_init_work(struct work_struct *work, work_func_t func);
+extern void cnss_flush_delayed_work(void *dwork);
+extern void cnss_flush_work(void *work);
+extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
+extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
+extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
+extern void cnss_get_monotonic_boottime(struct timespec *ts);
+extern void cnss_get_boottime(struct timespec *ts);
+extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t
+				   func);
+extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
+extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
+extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
+extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
+					u16 buf_len);
+extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
+extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern int cnss_common_request_bus_bandwidth(struct device *dev, int
+					     bandwidth);
+extern void cnss_common_device_crashed(struct device *dev);
+extern void cnss_common_device_self_recovery(struct device *dev);
+extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long
+					      *size);
+extern void cnss_common_schedule_recovery_work(struct device *dev);
+extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in,
+					    uint32_t len);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern int cnss_sdio_configure_spdt(bool state);
+
+extern int cnss_common_register_tsf_captured_handler(struct device *dev,
+						     irq_handler_t handler,
+						     void *ctx);
+extern int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						       void *ctx);
+#endif /* _NET_CNSS_H_ */
diff --git a/include/net/cnss_logger.h b/include/net/cnss_logger.h
new file mode 100644
index 0000000..f06ec9b
--- /dev/null
+++ b/include/net/cnss_logger.h
@@ -0,0 +1,59 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _NET_CNSS_LOGGER_H_
+#define _NET_CNSS_LOGGER_H_
+
+struct sk_buff;
+struct wiphy;
+
+#ifdef CONFIG_CNSS_LOGGER
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb));
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb));
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name);
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy);
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag);
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag);
+#else
+static inline int cnss_logger_event_register(int radio, int event,
+					     int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_event_unregister(int radio, int event,
+					       int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_device_register(struct wiphy *wiphy,
+					      const char *name)
+{
+	return 0;
+}
+static inline int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_ucast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_bcast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+#endif /* CONFIG_CNSS_LOGGER */
+#endif /* _NET_CNSS_H_ */
+
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index cbfe7e4..a872c9a 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -114,6 +114,10 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm450")
 #define early_machine_is_sdm632()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm632")
+#define early_machine_is_sdm439()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm439")
+#define early_machine_is_sdm429()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429")
 #else
 #define of_board_is_sim()		0
 #define of_board_is_rumi()		0
@@ -160,6 +164,8 @@
 #define early_machine_is_msm8937()	0
 #define early_machine_is_sdm450()	0
 #define early_machine_is_sdm632()	0
+#define early_machine_is_sdm439()	0
+#define early_machine_is_sdm429()	0
 #endif
 
 #define PLATFORM_SUBTYPE_MDM	1
@@ -228,7 +234,9 @@
 	MSM_CPU_SDM450,
 	MSM_CPU_SDM632,
 	MSM_CPU_SDA632,
-	MSM_CPU_8937
+	MSM_CPU_8937,
+	MSM_CPU_SDM439,
+	MSM_CPU_SDM429,
 };
 
 struct msm_soc_info {
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 0125cde..63f2baf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -596,8 +596,8 @@
 
 TRACE_EVENT(sched_load_to_gov,
 
-	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy),
-	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy),
+	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy, int big_task_rotation),
+	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy, big_task_rotation),
 
 	TP_STRUCT__entry(
 		__field(	int,	cpu			)
@@ -612,6 +612,7 @@
 		__field(	u64,	grp_nt_ps		)
 		__field(	u64,	pl			)
 		__field(	u64,    load			)
+		__field(	int,    big_task_rotation	)
 	),
 
 	TP_fast_assign(
@@ -627,13 +628,15 @@
 		__entry->grp_nt_ps	= rq->grp_time.nt_prev_runnable_sum;
 		__entry->pl		= rq->walt_stats.pred_demands_sum;
 		__entry->load		= load;
+		__entry->big_task_rotation = big_task_rotation;
 	),
 
-	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu",
+	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu big_task_rotation=%d",
 		__entry->cpu, __entry->policy, __entry->ed_task_pid,
 		__entry->aggr_grp_load, __entry->freq_aggr_thresh,
 		__entry->tt_load, __entry->rq_ps, __entry->grp_rq_ps,
-		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load)
+		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load,
+		__entry->big_task_rotation)
 );
 #endif
 
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7b02ae6..31b45b7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -775,6 +775,7 @@
 	if (!(flags & ENQUEUE_RESTORE))
 		sched_info_queued(rq, p);
 	p->sched_class->enqueue_task(rq, p, flags);
+	walt_update_last_enqueue(p);
 	trace_sched_enq_deq_task(p, 1, cpumask_bits(&p->cpus_allowed)[0]);
 }
 
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index cc5a97c..c0a8a2a 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -482,6 +482,7 @@
 
 	sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg,
 				 &max_nr, &big_max_nr);
+	walt_rotation_checkpoint(big_avg);
 
 	spin_lock_irqsave(&state_lock, flags);
 	for_each_cluster(cluster, index) {
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 1ff2e5e..55c3957 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -11430,6 +11430,141 @@
 	return rc;
 }
 
+#ifdef CONFIG_SCHED_WALT
+struct walt_rotate_work {
+	struct work_struct w;
+	struct task_struct *src_task;
+	struct task_struct *dst_task;
+	int src_cpu;
+	int dst_cpu;
+};
+
+static DEFINE_PER_CPU(struct walt_rotate_work, walt_rotate_works);
+
+static void walt_rotate_work_func(struct work_struct *work)
+{
+	struct walt_rotate_work *wr = container_of(work,
+				struct walt_rotate_work, w);
+
+	migrate_swap(wr->src_task, wr->dst_task);
+
+	put_task_struct(wr->src_task);
+	put_task_struct(wr->dst_task);
+
+	clear_reserved(wr->src_cpu);
+	clear_reserved(wr->dst_cpu);
+}
+
+void walt_rotate_work_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		struct walt_rotate_work *wr = &per_cpu(walt_rotate_works, i);
+
+		INIT_WORK(&wr->w, walt_rotate_work_func);
+	}
+}
+
+#define WALT_ROTATION_THRESHOLD_NS	16000000
+static void walt_check_for_rotation(struct rq *src_rq)
+{
+	u64 wc, wait, max_wait = 0, run, max_run = 0;
+	int deserved_cpu = nr_cpu_ids, dst_cpu = nr_cpu_ids;
+	int i, src_cpu = cpu_of(src_rq);
+	struct rq *dst_rq;
+	struct walt_rotate_work *wr = NULL;
+
+	if (!walt_rotation_enabled)
+		return;
+
+	if (got_boost_kick())
+		return;
+
+	if (is_max_capacity_cpu(src_cpu))
+		return;
+
+	wc = ktime_get_ns();
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (is_max_capacity_cpu(i))
+			break;
+
+		if (is_reserved(i))
+			continue;
+
+		if (!rq->misfit_task || rq->curr->sched_class !=
+						&fair_sched_class)
+			continue;
+
+		wait = wc - rq->curr->last_enqueued_ts;
+		if (wait > max_wait) {
+			max_wait = wait;
+			deserved_cpu = i;
+		}
+	}
+
+	if (deserved_cpu != src_cpu)
+		return;
+
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (!is_max_capacity_cpu(i))
+			continue;
+
+		if (is_reserved(i))
+			continue;
+
+		if (rq->curr->sched_class != &fair_sched_class)
+			continue;
+
+		if (rq->nr_running > 1)
+			continue;
+
+		run = wc - rq->curr->last_enqueued_ts;
+
+		if (run < WALT_ROTATION_THRESHOLD_NS)
+			continue;
+
+		if (run > max_run) {
+			max_run = run;
+			dst_cpu = i;
+		}
+	}
+
+	if (dst_cpu == nr_cpu_ids)
+		return;
+
+	dst_rq = cpu_rq(dst_cpu);
+
+	double_rq_lock(src_rq, dst_rq);
+	if (dst_rq->curr->sched_class == &fair_sched_class) {
+		get_task_struct(src_rq->curr);
+		get_task_struct(dst_rq->curr);
+
+		mark_reserved(src_cpu);
+		mark_reserved(dst_cpu);
+		wr = &per_cpu(walt_rotate_works, src_cpu);
+
+		wr->src_task = src_rq->curr;
+		wr->dst_task = dst_rq->curr;
+
+		wr->src_cpu = src_cpu;
+		wr->dst_cpu = dst_cpu;
+	}
+	double_rq_unlock(src_rq, dst_rq);
+
+	if (wr)
+		queue_work_on(src_cpu, system_highpri_wq, &wr->w);
+}
+#else
+static inline void walt_check_for_rotation(struct rq *rq)
+{
+}
+#endif
+
 static DEFINE_RAW_SPINLOCK(migration_lock);
 void check_for_migration(struct rq *rq, struct task_struct *p)
 {
@@ -11459,6 +11594,8 @@
 					&rq->active_balance_work);
 				return;
 			}
+		} else {
+			walt_check_for_rotation(rq);
 		}
 		raw_spin_unlock(&migration_lock);
 	}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5508248..e0aa30d 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -943,8 +943,8 @@
 };
 extern void sched_setnuma(struct task_struct *p, int node);
 extern int migrate_task_to(struct task_struct *p, int cpu);
-extern int migrate_swap(struct task_struct *, struct task_struct *);
 #endif /* CONFIG_NUMA_BALANCING */
+extern int migrate_swap(struct task_struct *cur, struct task_struct *p);
 
 #ifdef CONFIG_SMP
 
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index b7da03f..23fd885 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -88,6 +88,9 @@
 
 __read_mostly unsigned int sysctl_sched_cpu_high_irqload = (10 * NSEC_PER_MSEC);
 
+unsigned int sysctl_sched_walt_rotate_big_tasks;
+unsigned int walt_rotation_enabled;
+
 /*
  * sched_window_stats_policy and sched_ravg_hist_size have a 'sysctl' copy
  * associated with them. This is required for atomic update of those variables
@@ -316,7 +319,8 @@
 	struct task_struct *p;
 	int loop_max = 10;
 
-	if (sched_boost_policy() == SCHED_BOOST_NONE || !rq->cfs.h_nr_running)
+	if ((!walt_rotation_enabled && sched_boost_policy() ==
+			SCHED_BOOST_NONE) || !rq->cfs.h_nr_running)
 		return 0;
 
 	rq->ed_task = NULL;
@@ -487,7 +491,7 @@
 
 done:
 	trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, freq_aggr_thresh,
-				load, reporting_policy);
+				load, reporting_policy, walt_rotation_enabled);
 	return load;
 }
 
@@ -2019,7 +2023,7 @@
 
 	wallclock = ktime_get_ns();
 	p->ravg.mark_start = p->last_wake_ts = wallclock;
-	p->last_cpu_selected_ts = wallclock;
+	p->last_enqueued_ts = wallclock;
 	p->last_switch_out_ts = 0;
 	update_task_cpu_cycles(p, cpu_of(rq));
 }
@@ -3143,6 +3147,19 @@
 		core_ctl_check(this_rq()->window_start);
 }
 
+void walt_rotation_checkpoint(int nr_big)
+{
+	if (!hmp_capable())
+		return;
+
+	if (!sysctl_sched_walt_rotate_big_tasks || sched_boost() != NO_BOOST) {
+		walt_rotation_enabled = 0;
+		return;
+	}
+
+	walt_rotation_enabled = nr_big >= num_possible_cpus();
+}
+
 int walt_proc_update_handler(struct ctl_table *table, int write,
 			     void __user *buffer, size_t *lenp,
 			     loff_t *ppos)
@@ -3178,6 +3195,8 @@
 	cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
 	init_irq_work(&walt_migration_irq_work, walt_irq_work);
 	init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
+	walt_rotate_work_init();
+
 	rq->walt_stats.cumulative_runnable_avg = 0;
 	rq->window_start = 0;
 	rq->cum_window_start = 0;
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index c8780cf..da53ea4 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -291,9 +291,20 @@
 	return sysctl_sched_is_big_little ? prev_cpu : min_power_cpu;
 }
 
+static inline void walt_update_last_enqueue(struct task_struct *p)
+{
+	p->last_enqueued_ts = ktime_get_ns();
+}
+extern void walt_rotate_work_init(void);
+extern void walt_rotation_checkpoint(int nr_big);
+extern unsigned int walt_rotation_enabled;
+
 #else /* CONFIG_SCHED_WALT */
 
 static inline void walt_sched_init(struct rq *rq) { }
+static inline void walt_rotate_work_init(void) { }
+static inline void walt_rotation_checkpoint(int nr_big) { }
+static inline void walt_update_last_enqueue(struct task_struct *p) { }
 
 static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
 				int event, u64 wallclock, u64 irqtime) { }
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index a01c821..b057784 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -325,6 +325,15 @@
 		.extra1         = &zero,
 		.extra2		= &three,
 	},
+	{
+		.procname	= "sched_walt_rotate_big_tasks",
+		.data		= &sysctl_sched_walt_rotate_big_tasks,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
 #endif
 	{
 		.procname	= "sched_upmigrate",
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4a60459..d3ea11f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3288,6 +3288,46 @@
 	return NULL;
 }
 
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	/* Let costly order requests check for compaction progress */
+	if (order > PAGE_ALLOC_COSTLY_ORDER)
+		return false;
+
+	/*
+	 * For (0 < order < PAGE_ALLOC_COSTLY_ORDER) allow the shrinkers
+	 * to run and free up memory. Do not let these allocations fail
+	 * if shrinkers can free up memory. This is similar to
+	 * should_compact_retry implementation for !CONFIG_COMPACTION.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
+				ac->high_zoneidx, ac->nodemask) {
+		unsigned long available;
+
+		available = zone_reclaimable_pages(zone);
+		available +=
+			zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+		if (__zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+			ac_classzone_idx(ac), alloc_flags, available))
+			return true;
+	}
+
+	return false;
+}
+#else
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	return false;
+}
+#endif
+
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 		     enum compact_result compact_result,
@@ -3300,6 +3340,9 @@
 	if (!order)
 		return false;
 
+	if (should_compact_lmk_retry(ac, order, alloc_flags))
+		return true;
+
 	if (compaction_made_progress(compact_result))
 		(*compaction_retries)++;
 
@@ -3537,7 +3580,8 @@
 	 * their order will become available due to high fragmentation so
 	 * always increment the no progress counter for them
 	 */
-	if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+	if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		*no_progress_loops = 0;
 	else
 		(*no_progress_loops)++;
@@ -3815,7 +3859,8 @@
 	 * implementation of the compaction depends on the sufficient amount
 	 * of free memory (see __compaction_suitable)
 	 */
-	if (did_some_progress > 0 &&
+	if ((did_some_progress > 0 ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER)) &&
 			should_compact_retry(ac, order, alloc_flags,
 				compact_result, &compact_priority,
 				&compaction_retries))
diff --git a/mm/vmscan.c b/mm/vmscan.c
index bb18b47..2740973 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -212,7 +212,8 @@
 
 	nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
 		zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
-	if (get_nr_swap_pages() > 0)
+	if (get_nr_swap_pages() > 0
+			|| IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
 			zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f7e685f..558d566 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -393,14 +393,11 @@
 	struct net_device *loopback_dev =
 		dev_net(dev)->loopback_dev;
 
-	if (dev != loopback_dev) {
-		if (idev && idev->dev == dev) {
-			struct inet6_dev *loopback_idev =
-				in6_dev_get(loopback_dev);
-			if (loopback_idev) {
-				rt->rt6i_idev = loopback_idev;
-				in6_dev_put(idev);
-			}
+	if (idev && idev->dev != loopback_dev) {
+		struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+		if (loopback_idev) {
+			rt->rt6i_idev = loopback_idev;
+			in6_dev_put(idev);
 		}
 	}
 }
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index ac5f1267..aab8585 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -9,7 +9,6 @@
 dev_pm_ops
 dma_map_ops
 driver_info
-drm_connector_funcs
 drm_encoder_funcs
 drm_encoder_helper_funcs
 ethtool_ops
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index e2cebf15..1c5b36d 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -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
@@ -173,6 +173,9 @@
 	USB_QMI_PCM_FORMAT_U32_BE,
 };
 
+static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
+	size_t iova_size, size_t mapped_iova_size);
+
 static enum usb_audio_device_speed_enum_v01
 get_speed_info(enum usb_device_speed udev_speed)
 {
@@ -279,11 +282,14 @@
 }
 
 static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
-		size_t size)
+		size_t size, struct sg_table *sgt)
 {
-	unsigned long va = 0;
+	unsigned long va_sg, va = 0;
 	bool map = true;
-	int ret;
+	int i, ret;
+	size_t sg_len, total_len = 0;
+	struct scatterlist *sg;
+	phys_addr_t pa_sg;
 
 	switch (mtype) {
 	case MEM_EVENT_RING:
@@ -306,18 +312,48 @@
 		pr_err("%s: unknown mem type %d\n", __func__, mtype);
 	}
 
-	if (!va)
-		map = false;
-
-	if (!map)
+	if (!va || !map)
 		goto done;
 
-	pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
-		va, mtype);
+	if (!sgt)
+		goto skip_sgt_map;
+
+	va_sg = va;
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		sg_len = PAGE_ALIGN(sg->offset + sg->length);
+		pa_sg = page_to_phys(sg_page(sg));
+		ret = iommu_map(uaudio_qdev->domain, va_sg, pa_sg, sg_len,
+			IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
+		if (ret) {
+			pr_err("%s:mapping failed ret%d\n", __func__, ret);
+			pr_err("memtype:%d, pa:%pK iova:%lu sg_len:%zu\n",
+				mtype, &pa_sg, va_sg, sg_len);
+			uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+			va = 0;
+			goto done;
+		}
+		pr_debug("%s:memtype %d:map pa:%pK to iova:%lu len:%zu\n",
+			__func__, mtype, &pa_sg, va_sg, sg_len);
+		va_sg += sg_len;
+		total_len += sg_len;
+	}
+
+	if (size != total_len) {
+		pr_err("%s: iova size %zu != mapped iova size %zu\n", __func__,
+			size, total_len);
+		uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+		va = 0;
+	}
+	return va;
+
+skip_sgt_map:
+	pr_debug("%s:memtype:%d map pa:%pK to iova %lu size:%zu\n", __func__,
+		mtype, &pa, va, size);
+
 	ret = iommu_map(uaudio_qdev->domain, va, pa, size,
 		IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
 	if (ret)
-		pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
+		pr_err("%s:failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
 			__func__, &pa, va, mtype, ret);
 done:
 	return va;
@@ -361,12 +397,12 @@
 }
 
 static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
-	size_t size)
+	size_t iova_size, size_t mapped_iova_size)
 {
 	size_t umap_size;
 	bool unmap = true;
 
-	if (!va || !size)
+	if (!va || !iova_size)
 		return;
 
 	switch (mtype) {
@@ -378,11 +414,11 @@
 		break;
 
 	case MEM_XFER_RING:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_ring_list,
 		&uaudio_qdev->xfer_ring_iova_size);
 		break;
 	case MEM_XFER_BUF:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_buf_list,
 		&uaudio_qdev->xfer_buf_iova_size);
 		break;
 	default:
@@ -390,15 +426,16 @@
 		unmap = false;
 	}
 
-	if (!unmap)
+	if (!unmap || !mapped_iova_size)
 		return;
 
-	pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
+	pr_debug("%s:memtype %d: unmap iova %lu size %zu\n", __func__, mtype,
+		va, mapped_iova_size);
 
-	umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
-	if (umap_size != size)
-		pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
-		umap_size, va);
+	umap_size = iommu_unmap(uaudio_qdev->domain, va, mapped_iova_size);
+	if (umap_size != mapped_iova_size)
+		pr_err("%s:unmapped size %zu for iova %lu of mapped size %zu\n",
+		__func__, umap_size, va, mapped_iova_size);
 }
 
 static int prepare_qmi_response(struct snd_usb_substream *subs,
@@ -418,12 +455,11 @@
 	void *hdr_ptr;
 	u8 *xfer_buf;
 	unsigned int data_ep_pipe = 0, sync_ep_pipe = 0;
-	u32 len, mult, remainder, xfer_buf_len, sg_len, i, total_len = 0;
-	unsigned long va, va_sg, tr_data_va = 0, tr_sync_va = 0;
+	u32 len, mult, remainder, xfer_buf_len;
+	unsigned long va, tr_data_va = 0, tr_sync_va = 0;
 	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
 	dma_addr_t dma;
 	struct sg_table sgt;
-	struct scatterlist *sg;
 
 	iface = usb_ifnum_to_if(subs->dev, subs->interface);
 	if (!iface) {
@@ -593,7 +629,7 @@
 		goto err;
 	}
 
-	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto err;
 
@@ -610,7 +646,7 @@
 	resp->speed_info_valid = 1;
 
 	/* data transfer ring */
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_er;
 
@@ -624,7 +660,7 @@
 		goto skip_sync;
 
 	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_data;
 
@@ -655,20 +691,9 @@
 
 	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
 			len);
-
-	va = 0;
-	for_each_sg(sgt.sgl, sg, sgt.nents, i) {
-		sg_len = PAGE_ALIGN(sg->offset + sg->length);
-		va_sg = uaudio_iommu_map(MEM_XFER_BUF,
-			page_to_phys(sg_page(sg)), sg_len);
-		if (!va_sg)
-			goto unmap_xfer_buf;
-
-		if (!va)
-			va = va_sg;
-
-		total_len += sg_len;
-	}
+	va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
+	if (!va)
+		goto unmap_sync;
 
 	resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
 	resp->xhci_mem_info.xfer_buff.size = len;
@@ -690,7 +715,7 @@
 			uadev[card_num].num_intf, GFP_KERNEL);
 		if (!uadev[card_num].info) {
 			ret = -ENOMEM;
-			goto unmap_xfer_buf;
+			goto unmap_sync;
 		}
 		uadev[card_num].udev = subs->dev;
 		atomic_set(&uadev[card_num].in_use, 1);
@@ -722,16 +747,13 @@
 
 	return 0;
 
-unmap_xfer_buf:
-	if (va)
-		uaudio_iommu_unmap(MEM_XFER_BUF, va, total_len);
 unmap_sync:
 	usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE, PAGE_SIZE);
 unmap_data:
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE, PAGE_SIZE);
 unmap_er:
-	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, PAGE_SIZE);
 err:
 	return ret;
 }
@@ -760,17 +782,17 @@
 	}
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
-		info->data_xfer_ring_size);
+		info->data_xfer_ring_size, info->data_xfer_ring_size);
 	info->data_xfer_ring_va = 0;
 	info->data_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
-		info->sync_xfer_ring_size);
+		info->sync_xfer_ring_size, info->sync_xfer_ring_size);
 	info->sync_xfer_ring_va = 0;
 	info->sync_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
-		info->xfer_buf_size);
+		info->xfer_buf_size, info->xfer_buf_size);
 	info->xfer_buf_va = 0;
 
 	usb_free_coherent(udev, info->xfer_buf_size,
@@ -805,7 +827,8 @@
 
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}
@@ -881,7 +904,8 @@
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}