Merge "msm: mhi_dev: Skip channel doorbell interrupts on unused channels"
diff --git a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
index 5b1e25f..714919f 100644
--- a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
+++ b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
@@ -74,6 +74,8 @@
                           optional "supply-name" is "vdd-wlan-rfa".
   - qcom,<supply-name>-info: Specifies configuration for supply. Should be
                              specified in <min_uV max_uV load_uA delay_us>.
+  - pcie-disable-l1: Boolean property to decide whether to disable PCIe L1 PM.
+  - pcie-disable-l1ss: Boolean property to decide whether to disable PCIe L1ss.
 
 List of chip specific sub nodes:
   - chip_cfg@X: represent chip specific configurations
diff --git a/Documentation/devicetree/bindings/iio/imu/st-asm330.txt b/Documentation/devicetree/bindings/iio/imu/st-asm330.txt
new file mode 100644
index 0000000..a8d1554
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/st-asm330.txt
@@ -0,0 +1,46 @@
+The ASM330 is a highly integrated, low power inertial measurement unit (IMU)
+that provides precise acceleration and angular rate (gyroscopic) measurement.
+
+To enable driver probing, add the asm330lhh node to the platform device tree as described below.
+
+Required properties:
+
+- compatible: "st,asm330lhh"
+- reg: the I2C address or SPI chip select the device will respond to
+- vio-supply: 1.8V regulator supply
+- vdd-supply: 3V regulator supply
+- interrupt-parent: phandle to the parent interrupt controller as documented in [interrupts][4]
+- interrupts: interrupt mapping for IRQ as documented in [interrupts][4]
+
+Recommended properties for SPI bus usage:
+- spi-max-frequency: maximum SPI bus frequency as documented in [SPI][3]
+
+Optional properties:
+- st,drdy-int-pin: MEMS sensor interrupt line to use (default 1)
+
+I2C example (based on Raspberry PI 3):
+
+	&i2c0 {
+		status = "ok";
+		#address-cells = <0x1>;
+		#size-cells = <0x0>;
+		asm330lhh@6b {
+			compatible = "st,asm330lhh";
+			reg = <0x6b>;
+			interrupt-parent = <&gpio>;
+			interrupts = <26 IRQ_TYPE_EDGE_RISING>;
+		};
+
+SPI example (based on Raspberry PI 3):
+
+	&spi0 {
+		status = "ok";
+		#address-cells = <0x1>;
+		#size-cells = <0x0>;
+		asm330lhh@0 {
+			spi-max-frequency = <500000>;
+			compatible = "st,asm330lhh";
+			reg = <0>;
+			interrupt-parent = <&gpio>;
+			interrupts = <26 IRQ_TYPE_EDGE_RISING>;
+		};
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index e52a65d..a8c949a 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -104,6 +104,8 @@
 				control.
 - qcom,entire-ipa-block-size: Complete size of the ipa block in which all
 				registers, collected upon crash, reside.
+- qcom,ipa-endp-delay-wa: Boolean context flag to indicate end point delay work around
+				supported or not.
 
 IPA pipe sub nodes (A2 static pipes configurations):
 
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt
index 74f7c8b..7ff7271 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt
@@ -65,6 +65,15 @@
 		    is not specified, then the default value used will be
 		    2812 mV.
 
+- qcom,fg-sys-min-voltage
+	Usage:      optional
+	Value type: <u32>
+	Definition: The voltage threshold (in mV) which describes the system
+		    minimum voltage as per the hardware recommendation. This
+		    is not used for any configuration but only for calculating
+		    the available power. If this property is not specified,
+		    then the default value used is 2800 mV.
+
 - qcom,fg-sys-term-current
 	Usage:      optional
 	Value type: <u32>
diff --git a/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt b/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt
index 0ee01dd..d62ccc0 100644
--- a/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt
@@ -189,6 +189,9 @@
    de-asserted, it will prevent random leakage from qusb2 phy resulting from
    out of sequence turn on/off of 1p8, 3p3 and DVDD regulators.
    "refgen_north_bg_reg" : address used to read REFGEN status for overriding QUSB PHY register.
+   "tcsr_conn_box_spare" : To enable/disable USB HS AC/DC coupling feature. When
+   enabled, DP/DM signals will take path through capacitor when USB HS device is
+   connected. This is a required property if 'qcom,usb-hs-ac-bitmask' property is present.
  - clocks: a list of phandles to the PHY clocks. Use as per
    Documentation/devicetree/bindings/clock/clock-bindings.txt
  - clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
@@ -205,8 +208,8 @@
  - qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
  - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
  - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
- - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Names represents "active"
-   state when attached in host mode and "suspend" state when detached.
+ - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Allowed names are
+   "default" and "sleep".
  - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
    improved rise/fall times.
  - qcom,host-chirp-erratum: Indicates host chirp fix is required.
@@ -216,6 +219,11 @@
    usually it is defined by qfprom device node.
  - nvmem-cell-names: specifies the given nvmem cell name as defined in
    qfprom node.
+ - qcom,usb-hs-ac-bitmask: Specifies the polarity and enable bitfields in
+   tcsr_conn_box_spare register so as to enable USB HS AC/DC coupling feature.
+ - qcom,usb-hs-ac-value: Specifies the value to be written to polarity and
+   enable bitfields so as to enable USB HS AC/DC coupling feature. This is a
+   required property if 'qcom,usb-hs-ac-bitmask' property is present.
 
 Example:
 	qusb_phy: qusb@f9b39000 {
diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig
index 4ad01c0..e8fd08a 100644
--- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig
+++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig
@@ -236,7 +236,6 @@
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
 CONFIG_SLIMBUS=y
-CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_SDXPRAIRIE=y
 CONFIG_GPIOLIB=y
@@ -370,6 +369,7 @@
 CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000
 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
+CONFIG_QCOM_DCC_V2=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_BUS_SCALING=y
diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig
index 91d25a8..0cbde7a 100644
--- a/arch/arm/configs/vendor/sdxprairie_defconfig
+++ b/arch/arm/configs/vendor/sdxprairie_defconfig
@@ -236,7 +236,6 @@
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
 CONFIG_SLIMBUS=y
-CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_SDXPRAIRIE=y
 CONFIG_GPIOLIB=y
@@ -330,6 +329,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_GSI_REGISTER_VERSION_2=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_ECM_IPA=y
@@ -373,6 +373,7 @@
 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000
 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_DCC_V2=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_BUS_SCALING=y
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku10.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku10.dts
index daad9fe5..f573c43 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku10.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku10.dts
@@ -49,3 +49,14 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 };
+
+&soc {
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku12.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku12.dts
index d234548..9546c43 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku12.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku12.dts
@@ -23,3 +23,14 @@
 	compatible = "qcom,qcs405-iot", "qcom,qcs405", "qcom,iot";
 	qcom,board-id = <0x080020 0x1>;
 };
+
+&soc {
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts
index b6d8c57..d7dd2c7 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts
@@ -82,6 +82,16 @@
 		qcom,mdss-fb-map = <&mdss_fb0>;
 	};
 
+	spi@78b5000 {
+		status = "okay";
+
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+
 	spi@7af5000 {  /* BLSP1 QUP2 */
 		status = "ok";
 		mdss_spi_client: qcom,mdss_spi_client {
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts
index 0bf2f58..bd92c17 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts
@@ -86,4 +86,12 @@
 	gpio_keys {
 		status = "disabled";
 	};
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts
index c6b124d..227b8e7 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts
@@ -50,3 +50,14 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 };
+
+&soc {
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts
index 879b5c4..8fa169c 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts
@@ -50,3 +50,14 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 };
+
+&soc {
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts
index 5d8a785d..0f99af0 100644
--- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts
+++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts
@@ -50,3 +50,14 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 };
+
+&soc {
+	spi@78b5000 {
+		status = "ok";
+		spi@0 {
+			compatible = "qcom,spi-msm-codec-slave";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi
index 2680c0e..8d0da04 100644
--- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -191,6 +191,7 @@
 };
 
 &usb0 {
+	qcom,default-mode-none;
 	qcom,host-poweroff-in-pm-suspend;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-alcor.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-alcor.dtsi
index 40d24d5..2c48865 100644
--- a/arch/arm64/boot/dts/qcom/sa8155-adp-alcor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8155-adp-alcor.dtsi
@@ -12,9 +12,3 @@
 
 #include "sa8155-adp-common.dtsi"
 #include "sa8155-adp-alcor-display.dtsi"
-
-&usb0 {
-	dwc3@a600000 {
-		maximum-speed = "high-speed";
-	};
-};
diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi
index ab11186..f420559 100644
--- a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi
@@ -45,6 +45,33 @@
 &qupv3_se4_i2c {
 	status = "ok";
 };
+
+&qupv3_se10_i2c {
+	status = "ok";
+	asm330@6a {
+		compatible = "st,asm330lhh";
+		reg = <0x6a>;
+		vio-supply = <&pm8150_2_l7>;
+		vdd-supply = <&pm8150_2_l16>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <41 IRQ_TYPE_EDGE_RISING>,
+				<42 IRQ_TYPE_EDGE_RISING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sensor_int1_default
+			&sensor_int2_default>;
+		sensor_int1_default: sensor_int1_default {
+			pins = "gpio41";
+			drive-strength = <16>;
+			bias-pull-up;
+		};
+		sensor_int2_default: sensor_int2_default {
+			pins = "gpio42";
+			drive-strength = <16>;
+			bias-pull-up;
+		};
+	};
+};
+
 &pil_modem {
 	status = "disabled";
 };
@@ -182,7 +209,12 @@
 };
 
 &usb0 {
+	qcom,default-mode-none;
 	qcom,host-poweroff-in-pm-suspend;
+	dwc3@a600000 {
+		usb-phy = <&usb2_phy0>, <&usb_nop_phy>;
+		maximum-speed = "high-speed";
+	};
 };
 
 &usb2_phy0 {
@@ -193,6 +225,10 @@
 	pinctrl-0 = <&usb2phy_ac_en1_default>;
 };
 
+&usb_qmp_dp_phy {
+	status = "disabled";
+};
+
 &usb1 {
 	status = "ok";
 	qcom,default-mode-host;
diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi
index 97f52f6..972a2cfd 100644
--- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi
@@ -2771,6 +2771,7 @@
 		qcom,smmu-fast-map;
 		qcom,use-ipa-pm;
 		qcom,bandwidth-vote-for-ipa;
+		qcom,ipa-endp-delay-wa;
 		qcom,msm-bus,name = "ipa";
 		qcom,msm-bus,num-cases = <5>;
 		qcom,msm-bus,num-paths = <4>;
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi
index 0e9495a..520e0a4 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi
@@ -16,6 +16,8 @@
 
 		compatible = "aquantia,aqc-107";
 
+		pci-ids = "1d6a:d107";
+
 		qcom,smmu;
 		qcom,smmu-iova-base = /bits/ 64 <0x0>;
 		qcom,smmu-iova-size = /bits/ 64 <0x80000000>;
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi
index 4e00c29..9cd11c5 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi
@@ -215,6 +215,7 @@
 
 		pcie0_rp: pcie0_rp {
 			reg = <0 0 0 0 0>;
+			pci-ids = "17cb:010c";
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
index 4b681d9..518e7f7 100644
--- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi
@@ -500,6 +500,15 @@
 		qcom,rmnet-ipa-ssr;
 	};
 
+	dcc: dcc_v2@10a2000 {
+		compatible = "qcom,dcc-v2";
+		reg = <0x10a2000 0x1000>,
+			<0x10ae800 0x1800>;
+		reg-names = "dcc-base", "dcc-ram-base";
+
+		dcc-ram-offset = <0x800>;
+	};
+
 	qcom,ipa_fws {
 		compatible = "qcom,pil-tz-generic";
 		qcom,pas-id = <0xf>;
@@ -1031,6 +1040,8 @@
 		pinctrl-1 = <&cnss_wlan_en_sleep>;
 		qcom,wlan-rc-num = <0>;
 		qcom,wlan-ramdump-dynamic = <0x400000>;
+		pcie-disable-l1;
+		pcie-disable-l1ss;
 
 		mhi,max-channels = <30>;
 		mhi,timeout = <10000>;
@@ -1358,7 +1369,7 @@
 &pcie0_rp {
 	cnss: qcom,qca6390@0 {
 		reg = <0 0 0 0 0>;
-		pci-ids = "1101:17cb";
+		pci-ids = "17cb:1101";
 
 		memory-region = <&cnss_wlan_mem>;
 	};
diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi
index 02c385b..7a925ed 100644
--- a/arch/arm64/boot/dts/qcom/sm6150.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi
@@ -2537,6 +2537,7 @@
 		qcom,smmu-fast-map;
 		qcom,use-ipa-pm;
 		qcom,bandwidth-vote-for-ipa;
+		qcom,ipa-endp-delay-wa;
 		qcom,msm-bus,name = "ipa";
 		qcom,msm-bus,num-cases = <5>;
 		qcom,msm-bus,num-paths = <4>;
diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi
index d16c507..f0741f6 100644
--- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi
@@ -17,6 +17,8 @@
 	mhi_0: qcom,mhi@0 {
 		reg = <0 0 0 0 0 >;
 
+		pci-ids = "17cb:0305", "17cb:0306";
+
 		/* controller specific configuration */
 		qcom,smmu-cfg = <0x3>;
 
@@ -548,6 +550,8 @@
 	mhi_1: qcom,mhi@0 {
 		reg = <0 0 0 0 0 >;
 
+		pci-ids = "17cb:0305", "17cb:0306";
+
 		/* controller specific configuration */
 		qcom,smmu-cfg = <0x3>;
 		qcom,msm-bus,name = "mhi";
diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi
index 115c6eb..7b7f34d 100644
--- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi
@@ -239,6 +239,7 @@
 
 		pcie_rc0: pcie_rc0 {
 			reg = <0 0 0 0 0>;
+			pci-ids = "17cb:0108";
 		};
 	};
 
@@ -556,6 +557,7 @@
 
 		pcie_rc1: pcie_rc1 {
 			reg = <0 0 0 0 0>;
+			pci-ids = "17cb:0108";
 		};
 	};
 
@@ -798,4 +800,20 @@
 		qcom,pcie-edma;
 		status = "disabled";
 	};
+
+	mhi_device: mhi_dev@1c0b000 {
+		compatible = "qcom,msm-mhi-dev";
+		reg = <0x1c0b000 0x1000>;
+		reg-names = "mhi_mmio_base";
+		qcom,mhi-ep-msi = <0>;
+		qcom,mhi-version = <0x1000000>;
+		qcom,use-pcie-edma;
+		dmas = <&pcie1_edma 0 0>, <&pcie1_edma 1 0>;
+		dma-names = "tx", "rx";
+		interrupts = <0 440 0>;
+		interrupt-names = "mhi-device-inta";
+		qcom,mhi-ifc-id = <0x010817cb>;
+		qcom,mhi-interrupt;
+		status = "disabled";
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/trinket-ion.dtsi b/arch/arm64/boot/dts/qcom/trinket-ion.dtsi
index aa8a2f2..3aec5ff 100644
--- a/arch/arm64/boot/dts/qcom/trinket-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket-ion.dtsi
@@ -52,5 +52,11 @@
 				token = <0x20000000>;
 			};
 		};
+
+		qcom,ion-heap@22 { /* ADSP HEAP */
+			reg = <22>;
+			memory-region = <&sdsp_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi b/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi
index 74e81c2..4916523 100644
--- a/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi
@@ -98,7 +98,7 @@
 	/delete-node/ camera-lowf;
 	/delete-node/ video-lowf;
 	/delete-node/ cpu-1-0-lowf;
-	/delete-node/ cpuss-2-lowf;
+	/delete-node/ cpuss-0-lowf;
 	/delete-node/ mdm-core-lowf;
 	/delete-node/ display-lowf;
 	/delete-node/ gpu-lowf;
diff --git a/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi b/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi
index dd70dca..c875b693 100644
--- a/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket-thermal.dtsi
@@ -600,11 +600,11 @@
 		};
 	};
 
-	cpuss-0-step {
+	cpuss-1-step {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		thermal-governor = "step_wise";
-		thermal-sensors = <&tsens0 6>;
+		thermal-sensors = <&tsens0 7>;
 		trips {
 			cpu5_7_config: cpu-5-7-config {
 				temperature = <110000>;
@@ -628,11 +628,11 @@
 		};
 	};
 
-	cpuss-1-step {
+	cpuss-2-step {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		thermal-governor = "step_wise";
-		thermal-sensors = <&tsens0 7>;
+		thermal-sensors = <&tsens0 8>;
 		trips {
 			cpu4_6_config: cpu-4-6-config {
 				temperature = <110000>;
@@ -656,11 +656,11 @@
 		};
 	};
 
-	cpuss-2-step {
+	cpuss-0-step {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		thermal-governor = "step_wise";
-		thermal-sensors = <&tsens0 8>;
+		thermal-sensors = <&tsens0 6>;
 		trips {
 			silv_cpus_config: silv-cpus-config {
 				temperature = <110000>;
@@ -1372,11 +1372,11 @@
 		};
 	};
 
-	cpuss-2-lowf {
+	cpuss-0-lowf {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 8>;
+		thermal-sensors = <&tsens0 6>;
 		tracks-low;
 		trips {
 			cpu0_lowf_trip: cpu0-lowf-trip {
@@ -1449,11 +1449,11 @@
 		};
 	};
 
-	cpuss-2-lowc {
+	cpuss-0-lowc {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		thermal-governor = "low_limits_cap";
-		thermal-sensors = <&tsens0 8>;
+		thermal-sensors = <&tsens0 6>;
 		tracks-low;
 		trips {
 			cpuss_2_lowc: cpuss-2-lowc {
diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi
index 28af2b3..3ce56d6 100644
--- a/arch/arm64/boot/dts/qcom/trinket.dtsi
+++ b/arch/arm64/boot/dts/qcom/trinket.dtsi
@@ -546,6 +546,14 @@
 			size = <0 0x800000>;
 		};
 
+		sdsp_mem: sdsp_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
 		dump_mem: mem_dump_region {
 			compatible = "shared-dma-pool";
 			reusable;
@@ -890,42 +898,6 @@
 		#clock-cells = <1>;
 	};
 
-	icnss: qcom,icnss@C800000 {
-		compatible = "qcom,icnss";
-		reg = <0xC800000 0x800000>,
-		      <0xa0000000 0x10000000>,
-		      <0xb0000000 0x10000>;
-		reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
-		iommus = <&apps_smmu 0x80 0x1>;
-		interrupts = <0 358 0 /* CE0 */ >,
-			     <0 359 0 /* CE1 */ >,
-			     <0 360 0 /* CE2 */ >,
-			     <0 361 0 /* CE3 */ >,
-			     <0 362 0 /* CE4 */ >,
-			     <0 363 0 /* CE5 */ >,
-			     <0 364 0 /* CE6 */ >,
-			     <0 365 0 /* CE7 */ >,
-			     <0 366 0 /* CE8 */ >,
-			     <0 367 0 /* CE9 */ >,
-			     <0 368 0 /* CE10 */ >,
-			     <0 369 0 /* CE11 */ >;
-		qcom,smmu-s1-bypass;
-		qcom,wlan-msa-memory = <0x100000>;
-		qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
-		vdd-cx-mx-supply = <&L8A>;
-		vdd-1.8-xo-supply = <&L16A>;
-		vdd-1.3-rfa-supply = <&L17A>;
-		vdd-3.3-ch0-supply = <&L23A>;
-		qcom,vdd-cx-mx-config = <640000 640000>;
-		qcom,smp2p_map_wlan_1_in {
-			interrupts-extended = <&smp2p_wlan_1_in 0 0>,
-					      <&smp2p_wlan_1_in 1 0>;
-			interrupt-names = "qcom,smp2p-force-fatal-error",
-					  "qcom,smp2p-early-crash-ind";
-		};
-
-	};
-
 	arm64-cpu-erp {
 		compatible = "arm,arm64-cpu-erp";
 		interrupts = <0 43 4>,
@@ -2849,6 +2821,46 @@
 #include "trinket-audio.dtsi"
 #include "trinket-thermal.dtsi"
 
+&soc {
+	icnss: qcom,icnss@C800000 {
+		compatible = "qcom,icnss";
+		reg = <0xC800000 0x800000>,
+		      <0xa0000000 0x10000000>,
+		      <0xb0000000 0x10000>;
+		reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
+		iommus = <&apps_smmu 0x80 0x1>;
+		interrupts = <0 358 0 /* CE0 */ >,
+			     <0 359 0 /* CE1 */ >,
+			     <0 360 0 /* CE2 */ >,
+			     <0 361 0 /* CE3 */ >,
+			     <0 362 0 /* CE4 */ >,
+			     <0 363 0 /* CE5 */ >,
+			     <0 364 0 /* CE6 */ >,
+			     <0 365 0 /* CE7 */ >,
+			     <0 366 0 /* CE8 */ >,
+			     <0 367 0 /* CE9 */ >,
+			     <0 368 0 /* CE10 */ >,
+			     <0 369 0 /* CE11 */ >;
+		qcom,smmu-s1-bypass;
+		qcom,wlan-msa-memory = <0x100000>;
+		qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
+		vdd-cx-mx-supply = <&L8A>;
+		vdd-1.8-xo-supply = <&L16A>;
+		vdd-1.3-rfa-supply = <&L17A>;
+		vdd-3.3-ch0-supply = <&L23A>;
+		qcom,vdd-cx-mx-config = <640000 640000>;
+		qcom,icnss-adc_tm = <&pmi632_adc_tm>;
+		io-channels = <&pmi632_vadc ADC_VBAT_SNS>;
+		io-channel-names = "icnss";
+		qcom,smp2p_map_wlan_1_in {
+		interrupts-extended = <&smp2p_wlan_1_in 0 0>,
+					      <&smp2p_wlan_1_in 1 0>;
+			interrupt-names = "qcom,smp2p-force-fatal-error",
+					  "qcom,smp2p-early-crash-ind";
+		};
+	};
+};
+
 &qupv3_se1_i2c {
 	status="ok";
 	#include "pm8008.dtsi"
diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig
index fdd12f6..26893a3 100644
--- a/arch/arm64/configs/vendor/sa8155_defconfig
+++ b/arch/arm64/configs/vendor/sa8155_defconfig
@@ -509,6 +509,7 @@
 CONFIG_USB_BAM=y
 CONFIG_MSM_MHI_DEV=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_RNDIS_IPA=y
diff --git a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig
index f48bdf7..6b4f83a 100644
--- a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig
+++ b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig
@@ -529,6 +529,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_RNDIS_IPA=y
diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig
index 70afcb5..517c070 100644
--- a/arch/arm64/configs/vendor/sdmsteppe_defconfig
+++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig
@@ -537,6 +537,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_RNDIS_IPA=y
diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig
index 17b7c6c..71f1bcc 100644
--- a/arch/arm64/configs/vendor/sm8150_defconfig
+++ b/arch/arm64/configs/vendor/sm8150_defconfig
@@ -530,6 +530,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_RNDIS_IPA=y
diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig
index 057b7a4..7fc275c 100644
--- a/arch/arm64/configs/vendor/trinket_defconfig
+++ b/arch/arm64/configs/vendor/trinket_defconfig
@@ -537,6 +537,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_IPA3=y
+CONFIG_IPA_DEBUG=y
 CONFIG_IPA_WDI_UNIFIED_API=y
 CONFIG_RMNET_IPA3=y
 CONFIG_RNDIS_IPA=y
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 156630a..463210d 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -40,6 +40,7 @@
 
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 source "drivers/iio/imu/st_lsm6dsx/Kconfig"
+source "drivers/iio/imu/st_asm330lhh/Kconfig"
 
 endmenu
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 68629c68..349a7de 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -20,3 +20,4 @@
 obj-$(CONFIG_KMX61) += kmx61.o
 
 obj-y += st_lsm6dsx/
+obj-y += st_asm330lhh/
diff --git a/drivers/iio/imu/st_asm330lhh/Kconfig b/drivers/iio/imu/st_asm330lhh/Kconfig
new file mode 100644
index 0000000..092cc48
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/Kconfig
@@ -0,0 +1,23 @@
+
+config IIO_ST_ASM330LHH
+	tristate "STMicroelectronics ASM330LHH sensor"
+	depends on (I2C || SPI)
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	select IIO_ST_ASM330LHH_I2C if (I2C)
+	select IIO_ST_ASM330LHH_SPI if (SPI_MASTER)
+	help
+	  Say yes here to build support for STMicroelectronics ASM330LHH imu
+	  sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called st_asm330lhh.
+
+config IIO_ST_ASM330LHH_I2C
+	tristate
+	depends on IIO_ST_ASM330LHH
+
+config IIO_ST_ASM330LHH_SPI
+	tristate
+	depends on IIO_ST_ASM330LHH
+
diff --git a/drivers/iio/imu/st_asm330lhh/Makefile b/drivers/iio/imu/st_asm330lhh/Makefile
new file mode 100644
index 0000000..7af80de
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/Makefile
@@ -0,0 +1,5 @@
+st_asm330lhh-y := st_asm330lhh_core.o st_asm330lhh_buffer.o
+
+obj-$(CONFIG_IIO_ST_ASM330LHH) += st_asm330lhh.o
+obj-$(CONFIG_IIO_ST_ASM330LHH_I2C) += st_asm330lhh_i2c.o
+obj-$(CONFIG_IIO_ST_ASM330LHH_SPI) += st_asm330lhh_spi.o
diff --git a/drivers/iio/imu/st_asm330lhh/README.md b/drivers/iio/imu/st_asm330lhh/README.md
new file mode 100644
index 0000000..d471530
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/README.md
@@ -0,0 +1,201 @@
+Index
+=======
+	* Introduction
+	* Driver Integration details
+	* Android SensorHAL integration
+	* Linux SensorHAL integration
+	* More information
+	* Copyright
+
+
+Introduction
+==============
+This repository contains asm330lhh IMU STMicroelectronics MEMS sensor linux driver support for kernel version 4.14.
+
+Data collected by asm330lhh STM sensor are pushed to userland through the kernel buffers of Linux IIO framework. User space applications can get sensor events by reading the related IIO devices created in the /dev directory (*/dev/iio{x}*). Please see [IIO][1] for more information.
+
+Asm330lhh IMU STM MEMS sensor support *I2C/SPI* digital interface. Please refer to [I2C][2] and [SPI][3] for detailed documentation.
+
+The STM Hardware Abstraction Layer (*HAL*) defines a standard interface for STM sensors allowing Android to be agnostic about low level driver implementation. The HAL library is packaged into modules (.so) file and loaded by the Android or Linux system at the appropriate time. For more information see [AOSP HAL Interface](https://source.android.com/devices/sensors/hal-interface.html) 
+
+STM Sensor HAL is leaning on [Linux IIO framework](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/iio) to gather data from sensor device drivers and to forward samples to the Android Framework
+
+Driver Integration details
+=====================
+
+In order to explain how to integrate Asm330lhh IMU STM sensor into the kernel, please consider the following example
+
+### Source code integration
+
+> * Copy driver source code into your linux kernel target directory (e.g. *drivers/iio/imu*)
+> * Edit related Kconfig (e.g. *drivers/iio/imu/Kconfig*) adding *ASM330LHH* support:
+
+>         source "drivers/iio/imu/st_asm330lhh/Kconfig"
+
+> * Edit related Makefile (e.g. *drivers/iio/imu/Makefile*) adding the following line:
+
+>         obj-y += st_asm330lhh/
+
+### Device Tree configuration
+
+> To enable driver probing, add the asm330lhh node to the platform device tree as described below.
+
+> **Required properties:**
+
+> *- compatible*: "st,asm330lhh"
+
+> *- reg*: the I2C address or SPI chip select the device will respond to
+
+> *- interrupt-parent*: phandle to the parent interrupt controller as documented in [interrupts][4]
+
+> *- interrupts*: interrupt mapping for IRQ as documented in [interrupts][4]
+> 
+>**Recommended properties for SPI bus usage:**
+
+> *- spi-max-frequency*: maximum SPI bus frequency as documented in [SPI][3]
+> 
+> **Optional properties:**
+
+> *- st,drdy-int-pin*: MEMS sensor interrupt line to use (default 1)
+
+> I2C example (based on Raspberry PI 3):
+
+>		&i2c0 {
+>			status = "ok";
+>			#address-cells = <0x1>;
+>			#size-cells = <0x0>;
+>			asm330lhh@6b {
+>				compatible = "st,asm330lhh";
+>				reg = <0x6b>;
+>				interrupt-parent = <&gpio>;
+>				interrupts = <26 IRQ_TYPE_EDGE_RISING>;
+>		};
+
+> SPI example (based on Raspberry PI 3):
+
+>		&spi0 {
+>			status = "ok";
+>			#address-cells = <0x1>;
+>			#size-cells = <0x0>;
+>			asm330lhh@0 {
+>				spi-max-frequency = <500000>;
+>				compatible = "st,asm330lhh";
+>				reg = <0>;
+>				interrupt-parent = <&gpio>;
+>				interrupts = <26 IRQ_TYPE_EDGE_RISING>;
+>			};
+
+### Kernel configuration
+
+Configure kernel with *make menuconfig* (alternatively use *make xconfig* or *make qconfig*)
+ 
+>		Device Drivers  --->
+>			<M> Industrial I/O support  --->
+>				Inertial measurement units  --->
+>				<M>   STMicroelectronics ASM330LHH sensor  --->
+
+
+Android SensorHAL integration
+==============
+
+STM Sensor HAL is written in *C++* language using object-oriented design. For each hw sensor there is a custom class file (*Accelerometer.cpp*, *Gyroscope.cpp*) which extends the common base class (*SensorBase.cpp*).
+
+Copy the HAL source code into *<AOSP_DIR\>/hardware/STMicroelectronics/SensorHAL_IIO* folder. During building process Android will include automatically the SensorHAL Android.mk.
+In *<AOSP_DIR\>/device/<vendor\>/<board\>/device.mk* add package build information:
+
+	PRODUCT_PACKAGES += sensors.{TARGET_BOARD_PLATFORM}
+
+	Note: device.mk can not read $(TARGET_BOARD_PLATFORM) variable, read and replace the value from your BoardConfig.mk (e.g. PRODUCT_PACKAGES += sensors.msm8974 for Nexus 5)
+
+To compile the SensorHAL_IIO just build AOSP source code from *$TOP* folder
+
+	$ cd <AOSP_DIR>
+	$ source build/envsetup.sh
+	$ lunch <select target platform>
+	$ make V=99
+
+The compiled library will be placed in *<AOSP_DIR\>/out/target/product/<board\>/system/vendor/lib/hw/sensor.{TARGET_BOARD_PLATFORM}.so*
+
+To configure sensor the Sensor HAL IIO use mm utility from HAL root folder
+
+    since Android 7
+	$mm sensors-defconfig (default configuration)
+	$mm sensors-menuconfig
+
+    after Android 7
+    make -f Makefile_config sensors-defconfig (default configuration)
+    make -f Makefile_config sensors-menuconfig
+    
+Linux SensorHAL integration
+==============
+
+Linux Sensor HAL share the same source code of Android Sensor HAL. Before compiling the Linux Sensor HAL IIO
+you need to follow the same procedure listed in previous chapter "Android SensorHAL integration"
+To cross compile Linux Sensor HAL must export the following shell variables 
+
+>   export AOSP_DIR=<AOSP_DIR>
+>   export ARCH=<your target architecture>
+>   export CROSS_COMPILE=<toolchain for your target>
+
+then in *<AOSP_DIR\>/hardware/STMicroelectronics/SensorHAL_IIO* folder type
+>   make
+
+it will produce a SensorHAL.so file containing the library. 
+In relative pat Documentation/LinuxHal/ there are some examples explaining how to use Linux Sensor HAL
+
+Copyright
+========
+Copyright (C) 2017 STMicroelectronics
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+More Information
+=================
+[http://st.com](http://st.com)
+
+[https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/iio](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/input)
+
+[https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/i2c](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/i2c)
+
+[https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/spi](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/spi)
+
+[https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bings/interrupt-controller/interrupts.txt](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt)
+
+
+Copyright Driver
+===========
+Copyright (C) 2017 STMicroelectronics
+
+This software is distributed under the GNU General Public License - see the accompanying COPYING file for more details.
+
+[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/iio/iio_configfs.txt "IIO"
+[2]: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/i2c "I2C"
+[3]: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/spi "SPI"
+[4]: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt "interrupts"
+
+Copyright SensorHAL
+========
+Copyright (C) 2017 STMicroelectronics
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h b/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h
new file mode 100644
index 0000000..52b293f
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh.h
@@ -0,0 +1,238 @@
+/*
+ * STMicroelectronics st_asm330lhh sensor driver
+ *
+ * Copyright 2018 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_ASM330LHH_H
+#define ST_ASM330LHH_H
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+
+#define ST_ASM330LHH_REVISION		"2.0.1"
+#define ST_ASM330LHH_PATCH		"1"
+
+#define ST_ASM330LHH_VERSION		"v"	\
+	ST_ASM330LHH_REVISION			\
+	"-"					\
+	ST_ASM330LHH_PATCH
+
+#define ST_ASM330LHH_DEV_NAME		"asm330lhh"
+
+#define ST_ASM330LHH_SAMPLE_SIZE	6
+#define ST_ASM330LHH_TS_SAMPLE_SIZE	4
+#define ST_ASM330LHH_TAG_SIZE		1
+#define ST_ASM330LHH_FIFO_SAMPLE_SIZE	(ST_ASM330LHH_SAMPLE_SIZE + \
+					 ST_ASM330LHH_TAG_SIZE)
+#define ST_ASM330LHH_MAX_FIFO_DEPTH	416
+
+#define ST_ASM330LHH_REG_FIFO_BATCH_ADDR	0x09
+#define ST_ASM330LHH_REG_FIFO_CTRL4_ADDR	0x0a
+#define ST_ASM330LHH_REG_STATUS_ADDR		0x1e
+#define ST_ASM330LHH_REG_STATUS_TDA		BIT(2)
+#define ST_ASM330LHH_REG_OUT_TEMP_L_ADDR	0x20
+#define ST_ASM330LHH_REG_OUT_TEMP_H_ADDR	0x21
+
+#define ST_ASM330LHH_MAX_ODR			416
+
+/* Define Custom events for FIFO flush */
+#define CUSTOM_IIO_EV_DIR_FIFO_EMPTY (IIO_EV_DIR_NONE + 1)
+#define CUSTOM_IIO_EV_DIR_FIFO_DATA (IIO_EV_DIR_NONE + 2)
+#define CUSTOM_IIO_EV_TYPE_FIFO_FLUSH (IIO_EV_TYPE_CHANGE + 1)
+
+#define ST_ASM330LHH_CHANNEL(chan_type, addr, mod, ch2, scan_idx,	\
+			   rb, sb, sg)					\
+{									\
+	.type = chan_type,						\
+	.address = addr,						\
+	.modified = mod,						\
+	.channel2 = ch2,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
+			      BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = scan_idx,						\
+	.scan_type = {							\
+		.sign = sg,						\
+		.realbits = rb,						\
+		.storagebits = sb,					\
+		.endianness = IIO_LE,					\
+	},								\
+}
+
+static const struct iio_event_spec st_asm330lhh_flush_event = {
+	.type = CUSTOM_IIO_EV_TYPE_FIFO_FLUSH,
+	.dir = IIO_EV_DIR_EITHER,
+};
+
+#define ST_ASM330LHH_FLUSH_CHANNEL(dtype)		\
+{							\
+	.type = dtype,					\
+	.modified = 0,					\
+	.scan_index = -1,				\
+	.indexed = -1,					\
+	.event_spec = &st_asm330lhh_flush_event,	\
+	.num_event_specs = 1,				\
+}
+
+#define ST_ASM330LHH_RX_MAX_LENGTH	8
+#define ST_ASM330LHH_TX_MAX_LENGTH	8
+
+struct st_asm330lhh_transfer_buffer {
+	u8 rx_buf[ST_ASM330LHH_RX_MAX_LENGTH];
+	u8 tx_buf[ST_ASM330LHH_TX_MAX_LENGTH] ____cacheline_aligned;
+};
+
+struct st_asm330lhh_transfer_function {
+	int (*read)(struct device *dev, u8 addr, int len, u8 *data);
+	int (*write)(struct device *dev, u8 addr, int len, u8 *data);
+};
+
+struct st_asm330lhh_reg {
+	u8 addr;
+	u8 mask;
+};
+
+struct st_asm330lhh_odr {
+	u16 hz;
+	u8 val;
+};
+
+#define ST_ASM330LHH_ODR_LIST_SIZE	7
+struct st_asm330lhh_odr_table_entry {
+	struct st_asm330lhh_reg reg;
+	struct st_asm330lhh_odr odr_avl[ST_ASM330LHH_ODR_LIST_SIZE];
+};
+
+struct st_asm330lhh_fs {
+	u32 gain;
+	u8 val;
+};
+
+#define ST_ASM330LHH_FS_ACC_LIST_SIZE		4
+#define ST_ASM330LHH_FS_GYRO_LIST_SIZE		6
+#define ST_ASM330LHH_FS_TEMP_LIST_SIZE		1
+#define ST_ASM330LHH_FS_LIST_SIZE		6
+struct st_asm330lhh_fs_table_entry {
+	u32 size;
+	struct st_asm330lhh_reg reg;
+	struct st_asm330lhh_fs fs_avl[ST_ASM330LHH_FS_LIST_SIZE];
+};
+
+enum st_asm330lhh_sensor_id {
+	ST_ASM330LHH_ID_ACC,
+	ST_ASM330LHH_ID_GYRO,
+	ST_ASM330LHH_ID_TEMP,
+	ST_ASM330LHH_ID_MAX,
+};
+
+enum st_asm330lhh_fifo_mode {
+	ST_ASM330LHH_FIFO_BYPASS = 0x0,
+	ST_ASM330LHH_FIFO_CONT = 0x6,
+};
+
+enum {
+	ST_ASM330LHH_HW_FLUSH,
+	ST_ASM330LHH_HW_OPERATIONAL,
+};
+
+/**
+ * struct st_asm330lhh_sensor - ST IMU sensor instance
+ * @id: Sensor identifier.
+ * @hw: Pointer to instance of struct st_asm330lhh_hw.
+ * @gain: Configured sensor sensitivity.
+ * @odr: Output data rate of the sensor [Hz].
+ * @watermark: Sensor watermark level.
+ * @batch_mask: Sensor mask for FIFO batching register
+ */
+struct st_asm330lhh_sensor {
+	enum st_asm330lhh_sensor_id id;
+	struct st_asm330lhh_hw *hw;
+
+	u32 gain;
+	u16 odr;
+	u32 offset;
+
+	__le16 old_data;
+
+	u8 std_samples;
+	u8 std_level;
+
+	u16 watermark;
+	u8 batch_mask;
+	u8 batch_addr;
+};
+
+/**
+ * struct st_asm330lhh_hw - ST IMU MEMS hw instance
+ * @dev: Pointer to instance of struct device (I2C or SPI).
+ * @irq: Device interrupt line (I2C or SPI).
+ * @lock: Mutex to protect read and write operations.
+ * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
+ * @fifo_mode: FIFO operating mode supported by the device.
+ * @state: hw operational state.
+ * @enable_mask: Enabled sensor bitmask.
+ * @ts_offset: Hw timestamp offset.
+ * @hw_ts: Latest hw timestamp from the sensor.
+ * @ts: Latest timestamp from irq handler.
+ * @delta_ts: Delta time between two consecutive interrupts.
+ * @iio_devs: Pointers to acc/gyro iio_dev instances.
+ * @tf: Transfer function structure used by I/O operations.
+ * @tb: Transfer buffers used by SPI I/O operations.
+ */
+struct st_asm330lhh_hw {
+	struct device *dev;
+	int irq;
+
+	struct mutex lock;
+	struct mutex fifo_lock;
+
+	enum st_asm330lhh_fifo_mode fifo_mode;
+	unsigned long state;
+	u8 enable_mask;
+
+	s64 ts_offset;
+	s64 hw_ts;
+	s64 delta_ts;
+	s64 ts;
+	s64 tsample;
+	s64 hw_ts_old;
+	s64 delta_hw_ts;
+
+	/* Timestamp sample ODR */
+	u16 odr;
+
+	struct iio_dev *iio_devs[ST_ASM330LHH_ID_MAX];
+
+	const struct st_asm330lhh_transfer_function *tf;
+	struct st_asm330lhh_transfer_buffer tb;
+};
+
+extern const struct dev_pm_ops st_asm330lhh_pm_ops;
+
+int st_asm330lhh_probe(struct device *dev, int irq,
+		       const struct st_asm330lhh_transfer_function *tf_ops);
+int st_asm330lhh_sensor_set_enable(struct st_asm330lhh_sensor *sensor,
+				   bool enable);
+int st_asm330lhh_fifo_setup(struct st_asm330lhh_hw *hw);
+int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask,
+				 u8 val);
+int st_asm330lhh_get_odr_val(enum st_asm330lhh_sensor_id id, u16 odr, u8 *val);
+ssize_t st_asm330lhh_flush_fifo(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size);
+ssize_t st_asm330lhh_get_max_watermark(struct device *dev,
+				       struct device_attribute *attr, char *buf);
+ssize_t st_asm330lhh_get_watermark(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+ssize_t st_asm330lhh_set_watermark(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size);
+int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw,
+			       enum st_asm330lhh_fifo_mode fifo_mode);
+int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw);
+#endif /* ST_ASM330LHH_H */
diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c
new file mode 100644
index 0000000..a2f54a8
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_buffer.c
@@ -0,0 +1,533 @@
+/*
+ * STMicroelectronics st_asm330lhh FIFO buffer library driver
+ *
+ * Copyright 2018 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <asm/unaligned.h>
+#include <linux/of.h>
+
+#include "st_asm330lhh.h"
+
+#define ST_ASM330LHH_REG_FIFO_THL_ADDR		0x07
+#define ST_ASM330LHH_REG_FIFO_LEN_MASK		GENMASK(8, 0)
+#define ST_ASM330LHH_REG_FIFO_MODE_MASK		GENMASK(2, 0)
+#define ST_ASM330LHH_REG_DEC_TS_MASK		GENMASK(7, 6)
+#define ST_ASM330LHH_REG_HLACTIVE_ADDR		0x12
+#define ST_ASM330LHH_REG_HLACTIVE_MASK		BIT(5)
+#define ST_ASM330LHH_REG_PP_OD_ADDR		0x12
+#define ST_ASM330LHH_REG_PP_OD_MASK		BIT(4)
+#define ST_ASM330LHH_REG_FIFO_DIFFL_ADDR	0x3a
+#define ST_ASM330LHH_REG_TS0_ADDR		0x40
+#define ST_ASM330LHH_REG_TS2_ADDR		0x42
+#define ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR	0x78
+#define ST_ASM330LHH_GYRO_TAG			0x01
+#define ST_ASM330LHH_ACC_TAG			0x02
+#define ST_ASM330LHH_TS_TAG			0x04
+
+#define ST_ASM330LHH_TS_DELTA_NS		25000ULL /* 25us/LSB */
+
+static inline s64 st_asm330lhh_get_time_ns(void)
+{
+	struct timespec ts;
+
+	get_monotonic_boottime(&ts);
+	return timespec_to_ns(&ts);
+}
+
+#define ST_ASM330LHH_EWMA_LEVEL			120
+#define ST_ASM330LHH_EWMA_DIV			128
+static inline s64 st_asm330lhh_ewma(s64 old, s64 new, int weight)
+{
+	s64 diff, incr;
+
+	diff = new - old;
+	incr = div_s64((ST_ASM330LHH_EWMA_DIV - weight) * diff,
+		       ST_ASM330LHH_EWMA_DIV);
+
+	return old + incr;
+}
+
+static inline int st_asm330lhh_reset_hwts(struct st_asm330lhh_hw *hw)
+{
+	u8 data = 0xaa;
+
+	hw->ts = st_asm330lhh_get_time_ns();
+	hw->ts_offset = hw->ts;
+	hw->hw_ts_old = 0ull;
+	hw->tsample = 0ull;
+
+	return hw->tf->write(hw->dev, ST_ASM330LHH_REG_TS2_ADDR, sizeof(data),
+			     &data);
+}
+
+int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw,
+			       enum st_asm330lhh_fifo_mode fifo_mode)
+{
+	int err;
+
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR,
+					   ST_ASM330LHH_REG_FIFO_MODE_MASK,
+					   fifo_mode);
+	if (err < 0)
+		return err;
+
+	hw->fifo_mode = fifo_mode;
+
+	return 0;
+}
+
+static int st_asm330lhh_set_sensor_batching_odr(struct st_asm330lhh_sensor *sensor,
+						bool enable)
+{
+	struct st_asm330lhh_hw *hw = sensor->hw;
+	u8 data = 0;
+	int err;
+
+	if (enable) {
+		err = st_asm330lhh_get_odr_val(sensor->id, sensor->odr, &data);
+		if (err < 0)
+			return err;
+	}
+
+	return st_asm330lhh_write_with_mask(hw,
+					    sensor->batch_addr,
+					    sensor->batch_mask, data);
+}
+
+static u16 st_asm330lhh_ts_odr(struct st_asm330lhh_hw *hw)
+{
+	struct st_asm330lhh_sensor *sensor;
+	u16 odr = 0;
+	u8 i;
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
+		sensor = iio_priv(hw->iio_devs[i]);
+		if (hw->enable_mask & BIT(sensor->id))
+			odr = max_t(u16, odr, sensor->odr);
+	}
+
+	return odr;
+}
+
+static int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor,
+					 u16 watermark)
+{
+	u16 fifo_watermark = ST_ASM330LHH_MAX_FIFO_DEPTH, cur_watermark = 0;
+	struct st_asm330lhh_hw *hw = sensor->hw;
+	struct st_asm330lhh_sensor *cur_sensor;
+	__le16 wdata;
+	int i, err;
+	u8 data;
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		cur_sensor = iio_priv(hw->iio_devs[i]);
+
+		if (!(hw->enable_mask & BIT(cur_sensor->id)))
+			continue;
+
+		cur_watermark = (cur_sensor == sensor) ? watermark
+						       : cur_sensor->watermark;
+
+		fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
+	}
+
+	fifo_watermark = max_t(u16, fifo_watermark, 2);
+	mutex_lock(&hw->lock);
+
+	err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR + 1,
+			   sizeof(data), &data);
+	if (err < 0)
+		goto out;
+
+	fifo_watermark = ((data << 8) & ~ST_ASM330LHH_REG_FIFO_LEN_MASK) |
+			 (fifo_watermark & ST_ASM330LHH_REG_FIFO_LEN_MASK);
+	wdata = cpu_to_le16(fifo_watermark);
+	err = hw->tf->write(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR,
+			    sizeof(wdata), (u8 *)&wdata);
+
+out:
+	mutex_unlock(&hw->lock);
+
+	return err < 0 ? err : 0;
+}
+
+static inline void st_asm330lhh_sync_hw_ts(struct st_asm330lhh_hw *hw, s64 ts)
+{
+	s64 delta = ts - hw->hw_ts;
+
+	hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset, delta,
+					  ST_ASM330LHH_EWMA_LEVEL);
+}
+
+static struct iio_dev *st_asm330lhh_get_iiodev_from_tag(struct st_asm330lhh_hw *hw,
+							u8 tag)
+{
+	struct iio_dev *iio_dev;
+
+	switch (tag) {
+	case ST_ASM330LHH_GYRO_TAG:
+		iio_dev = hw->iio_devs[ST_ASM330LHH_ID_GYRO];
+		break;
+	case ST_ASM330LHH_ACC_TAG:
+		iio_dev = hw->iio_devs[ST_ASM330LHH_ID_ACC];
+		break;
+	default:
+		iio_dev = NULL;
+		break;
+	}
+
+	return iio_dev;
+}
+
+static int st_asm330lhh_read_fifo(struct st_asm330lhh_hw *hw)
+{
+	u8 iio_buf[ALIGN(ST_ASM330LHH_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
+	u8 buf[6 * ST_ASM330LHH_FIFO_SAMPLE_SIZE], tag, *ptr;
+	s64 ts_delta_hw_ts = 0, ts_irq;
+	s64 ts_delta_offs;
+	int i, err, read_len, word_len, fifo_len;
+	struct st_asm330lhh_sensor *sensor;
+	struct iio_dev *iio_dev;
+	__le16 fifo_status;
+	u16 fifo_depth;
+	u32 val;
+	int ts_processed = 0;
+	s64 hw_ts = 0ull, delta_hw_ts, cpu_timestamp;
+
+	ts_irq = hw->ts - hw->delta_ts;
+
+	do
+	{
+		err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_FIFO_DIFFL_ADDR,
+				   sizeof(fifo_status), (u8 *)&fifo_status);
+		if (err < 0)
+			return err;
+
+		fifo_depth = le16_to_cpu(fifo_status) & ST_ASM330LHH_REG_FIFO_LEN_MASK;
+		if (!fifo_depth)
+			return 0;
+
+		read_len = 0;
+		fifo_len = fifo_depth * ST_ASM330LHH_FIFO_SAMPLE_SIZE;
+		while (read_len < fifo_len) {
+			word_len = min_t(int, fifo_len - read_len, sizeof(buf));
+			err = hw->tf->read(hw->dev,
+					   ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR,
+					   word_len, buf);
+			if (err < 0)
+				return err;
+
+			for (i = 0; i < word_len; i += ST_ASM330LHH_FIFO_SAMPLE_SIZE) {
+				ptr = &buf[i + ST_ASM330LHH_TAG_SIZE];
+				tag = buf[i] >> 3;
+
+				if (tag == ST_ASM330LHH_TS_TAG) {
+					val = get_unaligned_le32(ptr);
+					hw->hw_ts = val * ST_ASM330LHH_TS_DELTA_NS;
+					ts_delta_hw_ts = hw->hw_ts - hw->hw_ts_old;
+					hw_ts += ts_delta_hw_ts;
+					ts_delta_offs =
+						div_s64(hw->delta_hw_ts * ST_ASM330LHH_MAX_ODR, hw->odr);
+
+					hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset, ts_irq -
+						hw->hw_ts + ts_delta_offs, ST_ASM330LHH_EWMA_LEVEL);
+
+					ts_irq += (hw->hw_ts + ts_delta_offs);
+					hw->hw_ts_old = hw->hw_ts;
+					ts_processed++;
+
+					if (!hw->tsample)
+						hw->tsample =
+							hw->ts_offset + (hw->hw_ts + ts_delta_offs);
+					else
+						hw->tsample =
+							hw->tsample + (ts_delta_hw_ts + ts_delta_offs);
+				} else {
+					iio_dev = st_asm330lhh_get_iiodev_from_tag(hw, tag);
+					if (!iio_dev)
+						continue;
+
+					sensor = iio_priv(iio_dev);
+					if (sensor->std_samples < sensor->std_level) {
+						sensor->std_samples++;
+						continue;
+					}
+
+					sensor = iio_priv(iio_dev);
+
+					/* Check if timestamp is in the future. */
+					cpu_timestamp = st_asm330lhh_get_time_ns();
+
+					/* Avoid samples in the future. */
+					if (hw->tsample > cpu_timestamp)
+						hw->tsample = cpu_timestamp;
+
+					memcpy(iio_buf, ptr, ST_ASM330LHH_SAMPLE_SIZE);
+					iio_push_to_buffers_with_timestamp(iio_dev,
+									   iio_buf,
+									   hw->tsample);
+				}
+			}
+			read_len += word_len;
+		}
+
+		delta_hw_ts = div_s64(hw->delta_ts - hw_ts, ts_processed);
+		delta_hw_ts = div_s64(delta_hw_ts * hw->odr, ST_ASM330LHH_MAX_ODR);
+		hw->delta_hw_ts = st_asm330lhh_ewma(hw->delta_hw_ts,
+							delta_hw_ts,
+							ST_ASM330LHH_EWMA_LEVEL);
+	} while(read_len);
+
+	return read_len;
+}
+
+ssize_t st_asm330lhh_get_max_watermark(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", ST_ASM330LHH_MAX_FIFO_DEPTH);
+}
+
+ssize_t st_asm330lhh_get_watermark(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+
+	return sprintf(buf, "%d\n", sensor->watermark);
+}
+
+ssize_t st_asm330lhh_set_watermark(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+	int err, val;
+
+	mutex_lock(&iio_dev->mlock);
+	if (iio_buffer_enabled(iio_dev)) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	err = kstrtoint(buf, 10, &val);
+	if (err < 0)
+		goto out;
+
+	err = st_asm330lhh_update_watermark(sensor, val);
+	if (err < 0)
+		goto out;
+
+	sensor->watermark = val;
+
+out:
+	mutex_unlock(&iio_dev->mlock);
+
+	return err < 0 ? err : size;
+}
+
+ssize_t st_asm330lhh_flush_fifo(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+	struct st_asm330lhh_hw *hw = sensor->hw;
+	s64 type, event;
+	int count;
+	s64 ts;
+
+	mutex_lock(&hw->fifo_lock);
+	ts = st_asm330lhh_get_time_ns();
+	hw->delta_ts = ts - hw->ts;
+	hw->ts = ts;
+	set_bit(ST_ASM330LHH_HW_FLUSH, &hw->state);
+
+	count = st_asm330lhh_read_fifo(hw);
+
+	mutex_unlock(&hw->fifo_lock);
+
+	type = count > 0 ? CUSTOM_IIO_EV_DIR_FIFO_DATA : CUSTOM_IIO_EV_DIR_FIFO_EMPTY;
+	event = IIO_UNMOD_EVENT_CODE(iio_dev->channels[0].type, -1,
+				     CUSTOM_IIO_EV_TYPE_FIFO_FLUSH, type);
+	iio_push_event(iio_dev, event, st_asm330lhh_get_time_ns());
+
+	return size;
+}
+
+int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw)
+{
+	int err;
+
+	mutex_lock(&hw->fifo_lock);
+
+	st_asm330lhh_read_fifo(hw);
+	err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS);
+
+	mutex_unlock(&hw->fifo_lock);
+
+	return err;
+}
+
+static int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable)
+{
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+	struct st_asm330lhh_hw *hw = sensor->hw;
+	int err;
+
+	mutex_lock(&hw->fifo_lock);
+
+	err = st_asm330lhh_sensor_set_enable(sensor, enable);
+	if (err < 0)
+		goto out;
+
+	err = st_asm330lhh_set_sensor_batching_odr(sensor, enable);
+	if (err < 0)
+		goto out;
+
+	err = st_asm330lhh_update_watermark(sensor, sensor->watermark);
+	if (err < 0)
+		goto out;
+
+	hw->odr = st_asm330lhh_ts_odr(hw);
+
+	if (enable && hw->fifo_mode == ST_ASM330LHH_FIFO_BYPASS) {
+		st_asm330lhh_reset_hwts(hw);
+		err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_CONT);
+	} else if (!hw->enable_mask) {
+		err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS);
+	}
+
+out:
+	mutex_unlock(&hw->fifo_lock);
+
+	return err;
+}
+
+static irqreturn_t st_asm330lhh_handler_irq(int irq, void *private)
+{
+	struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private;
+	s64 ts = st_asm330lhh_get_time_ns();
+
+	hw->delta_ts = ts - hw->ts;
+	hw->ts = ts;
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t st_asm330lhh_handler_thread(int irq, void *private)
+{
+	struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private;
+
+	mutex_lock(&hw->fifo_lock);
+
+	st_asm330lhh_read_fifo(hw);
+	clear_bit(ST_ASM330LHH_HW_FLUSH, &hw->state);
+
+	mutex_unlock(&hw->fifo_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int st_asm330lhh_buffer_preenable(struct iio_dev *iio_dev)
+{
+	return st_asm330lhh_update_fifo(iio_dev, true);
+}
+
+static int st_asm330lhh_buffer_postdisable(struct iio_dev *iio_dev)
+{
+	return st_asm330lhh_update_fifo(iio_dev, false);
+}
+
+static const struct iio_buffer_setup_ops st_asm330lhh_buffer_ops = {
+	.preenable = st_asm330lhh_buffer_preenable,
+	.postdisable = st_asm330lhh_buffer_postdisable,
+};
+
+static int st_asm330lhh_fifo_init(struct st_asm330lhh_hw *hw)
+{
+	return st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR,
+					    ST_ASM330LHH_REG_DEC_TS_MASK, 1);
+}
+
+int st_asm330lhh_fifo_setup(struct st_asm330lhh_hw *hw)
+{
+	struct device_node *np = hw->dev->of_node;
+	struct iio_buffer *buffer;
+	unsigned long irq_type;
+	bool irq_active_low;
+	int i, err;
+
+	irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
+
+	switch (irq_type) {
+	case IRQF_TRIGGER_HIGH:
+	case IRQF_TRIGGER_RISING:
+		irq_active_low = false;
+		break;
+	case IRQF_TRIGGER_LOW:
+	case IRQF_TRIGGER_FALLING:
+		irq_active_low = true;
+		break;
+	default:
+		dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
+		return -EINVAL;
+	}
+
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_HLACTIVE_ADDR,
+					   ST_ASM330LHH_REG_HLACTIVE_MASK,
+					   irq_active_low);
+	if (err < 0)
+		return err;
+
+	if (np && of_property_read_bool(np, "drive-open-drain")) {
+		err = st_asm330lhh_write_with_mask(hw,
+					ST_ASM330LHH_REG_PP_OD_ADDR,
+					ST_ASM330LHH_REG_PP_OD_MASK, 1);
+		if (err < 0)
+			return err;
+
+		irq_type |= IRQF_SHARED;
+	}
+
+	err = devm_request_threaded_irq(hw->dev, hw->irq,
+					st_asm330lhh_handler_irq,
+					st_asm330lhh_handler_thread,
+					irq_type | IRQF_ONESHOT,
+					"asm330lhh", hw);
+	if (err) {
+		dev_err(hw->dev, "failed to request trigger irq %d\n",
+			hw->irq);
+		return err;
+	}
+
+	for (i = ST_ASM330LHH_ID_ACC; i < ST_ASM330LHH_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
+		buffer = devm_iio_kfifo_allocate(hw->dev);
+		if (!buffer)
+			return -ENOMEM;
+
+		iio_device_attach_buffer(hw->iio_devs[i], buffer);
+		hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
+		hw->iio_devs[i]->setup_ops = &st_asm330lhh_buffer_ops;
+	}
+
+	return st_asm330lhh_fifo_init(hw);
+}
+
diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c
new file mode 100644
index 0000000..9d9ee20
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_core.c
@@ -0,0 +1,824 @@
+/*
+ * STMicroelectronics st_asm330lhh sensor driver
+ *
+ * Copyright 2018 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/pm.h>
+#include <linux/version.h>
+#include <linux/of.h>
+
+#include <linux/platform_data/st_sensors_pdata.h>
+
+#include "st_asm330lhh.h"
+
+#define ST_ASM330LHH_REG_INT1_ADDR		0x0d
+#define ST_ASM330LHH_REG_INT2_ADDR		0x0e
+#define ST_ASM330LHH_REG_FIFO_CTRL4_ADDR	0x0a
+#define ST_ASM330LHH_REG_FIFO_FTH_IRQ_MASK	BIT(3)
+#define ST_ASM330LHH_REG_WHOAMI_ADDR		0x0f
+#define ST_ASM330LHH_WHOAMI_VAL			0x6b
+#define ST_ASM330LHH_REG_CTRL1_XL_ADDR		0x10
+#define ST_ASM330LHH_REG_CTRL2_G_ADDR		0x11
+#define ST_ASM330LHH_REG_RESET_ADDR		0x12
+#define ST_ASM330LHH_REG_RESET_MASK		BIT(0)
+#define ST_ASM330LHH_REG_BDU_ADDR		0x12
+#define ST_ASM330LHH_REG_BDU_MASK		BIT(6)
+#define ST_ASM330LHH_REG_INT2_ON_INT1_ADDR	0x13
+#define ST_ASM330LHH_REG_INT2_ON_INT1_MASK	BIT(5)
+#define ST_ASM330LHH_REG_ROUNDING_ADDR		0x14
+#define ST_ASM330LHH_REG_ROUNDING_MASK		GENMASK(6, 5)
+#define ST_ASM330LHH_REG_TIMESTAMP_EN_ADDR	0x19
+#define ST_ASM330LHH_REG_TIMESTAMP_EN_MASK	BIT(5)
+
+#define ST_ASM330LHH_REG_GYRO_OUT_X_L_ADDR	0x22
+#define ST_ASM330LHH_REG_GYRO_OUT_Y_L_ADDR	0x24
+#define ST_ASM330LHH_REG_GYRO_OUT_Z_L_ADDR	0x26
+
+#define ST_ASM330LHH_REG_ACC_OUT_X_L_ADDR	0x28
+#define ST_ASM330LHH_REG_ACC_OUT_Y_L_ADDR	0x2a
+#define ST_ASM330LHH_REG_ACC_OUT_Z_L_ADDR	0x2c
+
+#define ST_ASM330LHH_REG_LIR_ADDR		0x56
+#define ST_ASM330LHH_REG_LIR_MASK		BIT(0)
+
+#define ST_ASM330LHH_ACC_FS_2G_GAIN		IIO_G_TO_M_S_2(61)
+#define ST_ASM330LHH_ACC_FS_4G_GAIN		IIO_G_TO_M_S_2(122)
+#define ST_ASM330LHH_ACC_FS_8G_GAIN		IIO_G_TO_M_S_2(244)
+#define ST_ASM330LHH_ACC_FS_16G_GAIN		IIO_G_TO_M_S_2(488)
+
+#define ST_ASM330LHH_GYRO_FS_125_GAIN		IIO_DEGREE_TO_RAD(4375)
+#define ST_ASM330LHH_GYRO_FS_250_GAIN		IIO_DEGREE_TO_RAD(8750)
+#define ST_ASM330LHH_GYRO_FS_500_GAIN		IIO_DEGREE_TO_RAD(17500)
+#define ST_ASM330LHH_GYRO_FS_1000_GAIN		IIO_DEGREE_TO_RAD(35000)
+#define ST_ASM330LHH_GYRO_FS_2000_GAIN		IIO_DEGREE_TO_RAD(70000)
+#define ST_ASM330LHH_GYRO_FS_4000_GAIN		IIO_DEGREE_TO_RAD(140000)
+
+/* Temperature in uC */
+#define ST_ASM330LHH_TEMP_GAIN			256
+#define ST_ASM330LHH_TEMP_FS_GAIN		(1000000 / ST_ASM330LHH_TEMP_GAIN)
+#define ST_ASM330LHH_OFFSET			(6400)
+
+struct st_asm330lhh_std_entry {
+	u16 odr;
+	u8 val;
+};
+
+/* Minimal number of sample to be discarded */
+struct st_asm330lhh_std_entry st_asm330lhh_std_table[] = {
+	{  13,  2 },
+	{  26,  3 },
+	{  52,  4 },
+	{ 104,  6 },
+	{ 208,  8 },
+	{ 416, 18 },
+};
+
+static const struct st_asm330lhh_odr_table_entry st_asm330lhh_odr_table[] = {
+	[ST_ASM330LHH_ID_ACC] = {
+		.reg = {
+			.addr = ST_ASM330LHH_REG_CTRL1_XL_ADDR,
+			.mask = GENMASK(7, 4),
+		},
+		.odr_avl[0] = {   0, 0x00 },
+		.odr_avl[1] = {  13, 0x01 },
+		.odr_avl[2] = {  26, 0x02 },
+		.odr_avl[3] = {  52, 0x03 },
+		.odr_avl[4] = { 104, 0x04 },
+		.odr_avl[5] = { 208, 0x05 },
+		.odr_avl[6] = { 416, 0x06 },
+	},
+	[ST_ASM330LHH_ID_GYRO] = {
+		.reg = {
+			.addr = ST_ASM330LHH_REG_CTRL2_G_ADDR,
+			.mask = GENMASK(7, 4),
+		},
+		.odr_avl[0] = {   0, 0x00 },
+		.odr_avl[1] = {  13, 0x01 },
+		.odr_avl[2] = {  26, 0x02 },
+		.odr_avl[3] = {  52, 0x03 },
+		.odr_avl[4] = { 104, 0x04 },
+		.odr_avl[5] = { 208, 0x05 },
+		.odr_avl[6] = { 416, 0x06 },
+	},
+	[ST_ASM330LHH_ID_TEMP] = {
+		.odr_avl[0] = {   0, 0x00 },
+		.odr_avl[1] = {  52, 0x01 },
+	}
+};
+
+static const struct st_asm330lhh_fs_table_entry st_asm330lhh_fs_table[] = {
+	[ST_ASM330LHH_ID_ACC] = {
+		.reg = {
+			.addr = ST_ASM330LHH_REG_CTRL1_XL_ADDR,
+			.mask = GENMASK(3, 2),
+		},
+		.size = ST_ASM330LHH_FS_ACC_LIST_SIZE,
+		.fs_avl[0] = {  ST_ASM330LHH_ACC_FS_2G_GAIN, 0x0 },
+		.fs_avl[1] = {  ST_ASM330LHH_ACC_FS_4G_GAIN, 0x2 },
+		.fs_avl[2] = {  ST_ASM330LHH_ACC_FS_8G_GAIN, 0x3 },
+		.fs_avl[3] = { ST_ASM330LHH_ACC_FS_16G_GAIN, 0x1 },
+	},
+	[ST_ASM330LHH_ID_GYRO] = {
+		.reg = {
+			.addr = ST_ASM330LHH_REG_CTRL2_G_ADDR,
+			.mask = GENMASK(3, 0),
+		},
+		.size = ST_ASM330LHH_FS_GYRO_LIST_SIZE,
+		.fs_avl[0] = {  ST_ASM330LHH_GYRO_FS_125_GAIN, 0x2 },
+		.fs_avl[1] = {  ST_ASM330LHH_GYRO_FS_250_GAIN, 0x0 },
+		.fs_avl[2] = {  ST_ASM330LHH_GYRO_FS_500_GAIN, 0x4 },
+		.fs_avl[3] = { ST_ASM330LHH_GYRO_FS_1000_GAIN, 0x8 },
+		.fs_avl[4] = { ST_ASM330LHH_GYRO_FS_2000_GAIN, 0xC },
+		.fs_avl[5] = { ST_ASM330LHH_GYRO_FS_4000_GAIN, 0x1 },
+	},
+	[ST_ASM330LHH_ID_TEMP] = {
+		.size = ST_ASM330LHH_FS_TEMP_LIST_SIZE,
+		.fs_avl[0] = {  ST_ASM330LHH_TEMP_FS_GAIN, 0x0 },
+	}
+};
+
+static const struct iio_chan_spec st_asm330lhh_acc_channels[] = {
+	ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_X_L_ADDR,
+			   1, IIO_MOD_X, 0, 16, 16, 's'),
+	ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_Y_L_ADDR,
+			   1, IIO_MOD_Y, 1, 16, 16, 's'),
+	ST_ASM330LHH_CHANNEL(IIO_ACCEL, ST_ASM330LHH_REG_ACC_OUT_Z_L_ADDR,
+			   1, IIO_MOD_Z, 2, 16, 16, 's'),
+	ST_ASM330LHH_FLUSH_CHANNEL(IIO_ACCEL),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec st_asm330lhh_gyro_channels[] = {
+	ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_X_L_ADDR,
+			   1, IIO_MOD_X, 0, 16, 16, 's'),
+	ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_Y_L_ADDR,
+			   1, IIO_MOD_Y, 1, 16, 16, 's'),
+	ST_ASM330LHH_CHANNEL(IIO_ANGL_VEL, ST_ASM330LHH_REG_GYRO_OUT_Z_L_ADDR,
+			   1, IIO_MOD_Z, 2, 16, 16, 's'),
+	ST_ASM330LHH_FLUSH_CHANNEL(IIO_ANGL_VEL),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec st_asm330lhh_temp_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.address = ST_ASM330LHH_REG_OUT_TEMP_L_ADDR,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+				| BIT(IIO_CHAN_INFO_OFFSET)
+				| BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = -1,
+	},
+};
+
+int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask,
+				 u8 val)
+{
+	u8 data;
+	int err;
+
+	mutex_lock(&hw->lock);
+
+	err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to read %02x register\n", addr);
+		goto out;
+	}
+
+	data = (data & ~mask) | ((val << __ffs(mask)) & mask);
+
+	err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
+	if (err < 0)
+		dev_err(hw->dev, "failed to write %02x register\n", addr);
+
+out:
+	mutex_unlock(&hw->lock);
+
+	return err;
+}
+
+static int st_asm330lhh_check_whoami(struct st_asm330lhh_hw *hw)
+{
+	int err;
+	u8 data;
+
+	err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_WHOAMI_ADDR, sizeof(data),
+			   &data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to read whoami register\n");
+		return err;
+	}
+
+	if (data != ST_ASM330LHH_WHOAMI_VAL) {
+		dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int st_asm330lhh_set_full_scale(struct st_asm330lhh_sensor *sensor,
+				       u32 gain)
+{
+	enum st_asm330lhh_sensor_id id = sensor->id;
+	int i, err;
+	u8 val;
+
+	for (i = 0; i < st_asm330lhh_fs_table[id].size; i++)
+		if (st_asm330lhh_fs_table[id].fs_avl[i].gain == gain)
+			break;
+
+	if (i == st_asm330lhh_fs_table[id].size)
+		return -EINVAL;
+
+	val = st_asm330lhh_fs_table[id].fs_avl[i].val;
+	err = st_asm330lhh_write_with_mask(sensor->hw,
+					st_asm330lhh_fs_table[id].reg.addr,
+					st_asm330lhh_fs_table[id].reg.mask,
+					val);
+	if (err < 0)
+		return err;
+
+	sensor->gain = gain;
+
+	return 0;
+}
+
+int st_asm330lhh_get_odr_val(enum st_asm330lhh_sensor_id id, u16 odr, u8 *val)
+{
+	int i;
+
+	for (i = 0; i < ST_ASM330LHH_ODR_LIST_SIZE; i++)
+		if (st_asm330lhh_odr_table[id].odr_avl[i].hz >= odr)
+			break;
+
+	if (i == ST_ASM330LHH_ODR_LIST_SIZE)
+		return -EINVAL;
+
+	*val = st_asm330lhh_odr_table[id].odr_avl[i].val;
+
+	return 0;
+}
+
+static int st_asm330lhh_set_std_level(struct st_asm330lhh_sensor *sensor,
+			u16 odr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(st_asm330lhh_std_table); i++)
+		if (st_asm330lhh_std_table[i].odr == odr)
+			break;
+
+	if (i == ARRAY_SIZE(st_asm330lhh_std_table))
+		return -EINVAL;
+
+	sensor->std_level = st_asm330lhh_std_table[i].val;
+	sensor->std_samples = 0;
+
+	return 0;
+}
+
+static int st_asm330lhh_set_odr(struct st_asm330lhh_sensor *sensor, u16 odr)
+{
+	struct st_asm330lhh_hw *hw = sensor->hw;
+	u8 val;
+
+	if (st_asm330lhh_get_odr_val(sensor->id, odr, &val) < 0)
+		return -EINVAL;
+
+	return st_asm330lhh_write_with_mask(hw,
+				st_asm330lhh_odr_table[sensor->id].reg.addr,
+				st_asm330lhh_odr_table[sensor->id].reg.mask, val);
+}
+
+int st_asm330lhh_sensor_set_enable(struct st_asm330lhh_sensor *sensor,
+				   bool enable)
+{
+	u16 odr = enable ? sensor->odr : 0;
+	int err;
+
+	if (sensor->id != ST_ASM330LHH_ID_TEMP) {
+		err = st_asm330lhh_set_odr(sensor, odr);
+		if (err < 0)
+			return err;
+	}
+
+	if (enable)
+		sensor->hw->enable_mask |= BIT(sensor->id);
+	else
+		sensor->hw->enable_mask &= ~BIT(sensor->id);
+
+	return 0;
+}
+
+static int st_asm330lhh_read_oneshot(struct st_asm330lhh_sensor *sensor,
+				     u8 addr, int *val)
+{
+	int err, delay;
+	__le16 data;
+
+	if (sensor->id == ST_ASM330LHH_ID_TEMP) {
+		u8 status;
+
+		mutex_lock(&sensor->hw->fifo_lock);
+		err = sensor->hw->tf->read(sensor->hw->dev,
+					   ST_ASM330LHH_REG_STATUS_ADDR, sizeof(status), &status);
+		if (err < 0)
+			goto unlock;
+
+		if (status & ST_ASM330LHH_REG_STATUS_TDA) {
+			err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data),
+					   (u8 *)&data);
+			if (err < 0)
+				goto unlock;
+
+			sensor->old_data = data;
+		} else
+			data = sensor->old_data;
+unlock:
+		mutex_unlock(&sensor->hw->fifo_lock);
+
+	} else {
+		err = st_asm330lhh_sensor_set_enable(sensor, true);
+		if (err < 0)
+			return err;
+
+		delay = 1000000 / sensor->odr;
+		usleep_range(delay, 2 * delay);
+
+		err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data),
+					   (u8 *)&data);
+		if (err < 0)
+			return err;
+
+		st_asm330lhh_sensor_set_enable(sensor, false);
+	}
+
+	*val = (s16)data;
+
+	return IIO_VAL_INT;
+}
+
+static int st_asm330lhh_read_raw(struct iio_dev *iio_dev,
+				 struct iio_chan_spec const *ch,
+				 int *val, int *val2, long mask)
+{
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&iio_dev->mlock);
+		if (iio_buffer_enabled(iio_dev)) {
+			ret = -EBUSY;
+			mutex_unlock(&iio_dev->mlock);
+			break;
+		}
+		ret = st_asm330lhh_read_oneshot(sensor, ch->address, val);
+		mutex_unlock(&iio_dev->mlock);
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		switch (ch->type) {
+		case IIO_TEMP:
+			*val = sensor->offset;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = sensor->odr;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		switch (ch->type) {
+		case IIO_TEMP:
+			*val = 1;
+			*val2 = ST_ASM330LHH_TEMP_GAIN;
+			ret = IIO_VAL_FRACTIONAL;
+			break;
+		case IIO_ACCEL:
+		case IIO_ANGL_VEL:
+			*val = 0;
+			*val2 = sensor->gain;
+			ret = IIO_VAL_INT_PLUS_MICRO;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int st_asm330lhh_write_raw(struct iio_dev *iio_dev,
+				  struct iio_chan_spec const *chan,
+				  int val, int val2, long mask)
+{
+	struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
+	int err;
+
+	mutex_lock(&iio_dev->mlock);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		err = st_asm330lhh_set_full_scale(sensor, val2);
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ: {
+		u8 data;
+
+		err = st_asm330lhh_set_std_level(sensor, val);
+		if (err < 0)
+			break;
+
+		err = st_asm330lhh_get_odr_val(sensor->id, val, &data);
+		if (!err)
+			sensor->odr = val;
+
+		err = st_asm330lhh_set_odr(sensor, sensor->odr);
+		break;
+	}
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&iio_dev->mlock);
+
+	return err;
+}
+
+static ssize_t
+st_asm330lhh_sysfs_sampling_frequency_avail(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+	enum st_asm330lhh_sensor_id id = sensor->id;
+	int i, len = 0;
+
+	for (i = 1; i < ST_ASM330LHH_ODR_LIST_SIZE; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 st_asm330lhh_odr_table[id].odr_avl[i].hz);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t st_asm330lhh_sysfs_scale_avail(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct st_asm330lhh_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+	enum st_asm330lhh_sensor_id id = sensor->id;
+	int i, len = 0;
+
+	for (i = 0; i < st_asm330lhh_fs_table[id].size; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+				 st_asm330lhh_fs_table[id].fs_avl[i].gain);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_asm330lhh_sysfs_sampling_frequency_avail);
+static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
+		       st_asm330lhh_sysfs_scale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
+		       st_asm330lhh_sysfs_scale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_temp_scale_available, 0444,
+		       st_asm330lhh_sysfs_scale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_watermark_max, 0444,
+		       st_asm330lhh_get_max_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_flush, 0200, NULL, st_asm330lhh_flush_fifo, 0);
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0644, st_asm330lhh_get_watermark,
+		       st_asm330lhh_set_watermark, 0);
+
+static struct attribute *st_asm330lhh_acc_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+	&iio_dev_attr_hwfifo_flush.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group st_asm330lhh_acc_attribute_group = {
+	.attrs = st_asm330lhh_acc_attributes,
+};
+
+static const struct iio_info st_asm330lhh_acc_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &st_asm330lhh_acc_attribute_group,
+	.read_raw = st_asm330lhh_read_raw,
+	.write_raw = st_asm330lhh_write_raw,
+};
+
+static struct attribute *st_asm330lhh_gyro_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+	&iio_dev_attr_hwfifo_flush.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group st_asm330lhh_gyro_attribute_group = {
+	.attrs = st_asm330lhh_gyro_attributes,
+};
+
+static const struct iio_info st_asm330lhh_gyro_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &st_asm330lhh_gyro_attribute_group,
+	.read_raw = st_asm330lhh_read_raw,
+	.write_raw = st_asm330lhh_write_raw,
+};
+
+static struct attribute *st_asm330lhh_temp_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_temp_scale_available.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+	&iio_dev_attr_hwfifo_flush.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group st_asm330lhh_temp_attribute_group = {
+	.attrs = st_asm330lhh_temp_attributes,
+};
+
+static const struct iio_info st_asm330lhh_temp_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &st_asm330lhh_temp_attribute_group,
+	.read_raw = st_asm330lhh_read_raw,
+	.write_raw = st_asm330lhh_write_raw,
+};
+
+static const unsigned long st_asm330lhh_available_scan_masks[] = { 0x7, 0x0 };
+
+static int st_asm330lhh_of_get_drdy_pin(struct st_asm330lhh_hw *hw, int *drdy_pin)
+{
+	struct device_node *np = hw->dev->of_node;
+
+	if (!np)
+		return -EINVAL;
+
+	return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
+}
+
+static int st_asm330lhh_get_drdy_reg(struct st_asm330lhh_hw *hw, u8 *drdy_reg)
+{
+	int err = 0, drdy_pin;
+
+	if (st_asm330lhh_of_get_drdy_pin(hw, &drdy_pin) < 0) {
+		struct st_sensors_platform_data *pdata;
+		struct device *dev = hw->dev;
+
+		pdata = (struct st_sensors_platform_data *)dev->platform_data;
+		drdy_pin = pdata ? pdata->drdy_int_pin : 1;
+	}
+
+	switch (drdy_pin) {
+	case 1:
+		*drdy_reg = ST_ASM330LHH_REG_INT1_ADDR;
+		break;
+	case 2:
+		*drdy_reg = ST_ASM330LHH_REG_INT2_ADDR;
+		break;
+	default:
+		dev_err(hw->dev, "unsupported data ready pin\n");
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int st_asm330lhh_init_device(struct st_asm330lhh_hw *hw)
+{
+	u8 drdy_int_reg;
+	int err;
+
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_RESET_ADDR,
+					   ST_ASM330LHH_REG_RESET_MASK, 1);
+	if (err < 0)
+		return err;
+
+	msleep(200);
+
+	/* latch interrupts */
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_LIR_ADDR,
+					   ST_ASM330LHH_REG_LIR_MASK, 1);
+	if (err < 0)
+		return err;
+
+	/* enable Block Data Update */
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_BDU_ADDR,
+					   ST_ASM330LHH_REG_BDU_MASK, 1);
+	if (err < 0)
+		return err;
+
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_ROUNDING_ADDR,
+					   ST_ASM330LHH_REG_ROUNDING_MASK, 3);
+	if (err < 0)
+		return err;
+
+	/* init timestamp engine */
+	err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_TIMESTAMP_EN_ADDR,
+					   ST_ASM330LHH_REG_TIMESTAMP_EN_MASK, 1);
+	if (err < 0)
+		return err;
+
+	/* enable FIFO watermak interrupt */
+	err = st_asm330lhh_get_drdy_reg(hw, &drdy_int_reg);
+	if (err < 0)
+		return err;
+
+	return st_asm330lhh_write_with_mask(hw, drdy_int_reg,
+					    ST_ASM330LHH_REG_FIFO_FTH_IRQ_MASK, 1);
+}
+
+static struct iio_dev *st_asm330lhh_alloc_iiodev(struct st_asm330lhh_hw *hw,
+						 enum st_asm330lhh_sensor_id id)
+{
+	struct st_asm330lhh_sensor *sensor;
+	struct iio_dev *iio_dev;
+
+	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
+	if (!iio_dev)
+		return NULL;
+
+	iio_dev->modes = INDIO_DIRECT_MODE;
+	iio_dev->dev.parent = hw->dev;
+	iio_dev->available_scan_masks = st_asm330lhh_available_scan_masks;
+
+	sensor = iio_priv(iio_dev);
+	sensor->id = id;
+	sensor->hw = hw;
+	sensor->odr = st_asm330lhh_odr_table[id].odr_avl[1].hz;
+	sensor->gain = st_asm330lhh_fs_table[id].fs_avl[0].gain;
+	sensor->watermark = 1;
+	sensor->old_data = 0;
+
+	switch (id) {
+	case ST_ASM330LHH_ID_ACC:
+		iio_dev->channels = st_asm330lhh_acc_channels;
+		iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_acc_channels);
+		iio_dev->name = "asm330lhh_accel";
+		iio_dev->info = &st_asm330lhh_acc_info;
+		sensor->batch_addr = ST_ASM330LHH_REG_FIFO_BATCH_ADDR;
+		sensor->batch_mask = GENMASK(3, 0);
+		sensor->offset = 0;
+		break;
+	case ST_ASM330LHH_ID_GYRO:
+		iio_dev->channels = st_asm330lhh_gyro_channels;
+		iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_gyro_channels);
+		iio_dev->name = "asm330lhh_gyro";
+		iio_dev->info = &st_asm330lhh_gyro_info;
+		sensor->batch_addr = ST_ASM330LHH_REG_FIFO_BATCH_ADDR;
+		sensor->batch_mask = GENMASK(7, 4);
+		sensor->offset = 0;
+		break;
+	case ST_ASM330LHH_ID_TEMP:
+		iio_dev->channels = st_asm330lhh_temp_channels;
+		iio_dev->num_channels = ARRAY_SIZE(st_asm330lhh_temp_channels);
+		iio_dev->name = "asm330lhh_temp";
+		iio_dev->info = &st_asm330lhh_temp_info;
+		sensor->offset = ST_ASM330LHH_OFFSET;
+		break;
+	default:
+		return NULL;
+	}
+
+	return iio_dev;
+}
+
+int st_asm330lhh_probe(struct device *dev, int irq,
+		       const struct st_asm330lhh_transfer_function *tf_ops)
+{
+	struct st_asm330lhh_hw *hw;
+	int i, err;
+
+	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+	if (!hw)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, (void *)hw);
+
+	mutex_init(&hw->lock);
+	mutex_init(&hw->fifo_lock);
+
+	hw->dev = dev;
+	hw->irq = irq;
+	hw->tf = tf_ops;
+
+	dev_info(hw->dev, "Ver: %s\n", ST_ASM330LHH_VERSION);
+	err = st_asm330lhh_check_whoami(hw);
+	if (err < 0)
+		return err;
+
+	err = st_asm330lhh_init_device(hw);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		hw->iio_devs[i] = st_asm330lhh_alloc_iiodev(hw, i);
+		if (!hw->iio_devs[i])
+			return -ENOMEM;
+	}
+
+	if (hw->irq > 0) {
+		err = st_asm330lhh_fifo_setup(hw);
+		if (err < 0)
+			return err;
+	}
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
+		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
+		if (err)
+			return err;
+	}
+
+	dev_info(hw->dev, "probe ok\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(st_asm330lhh_probe);
+
+static int __maybe_unused st_asm330lhh_suspend(struct device *dev)
+{
+	struct st_asm330lhh_hw *hw = dev_get_drvdata(dev);
+	struct st_asm330lhh_sensor *sensor;
+	int i, err = 0;
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
+		sensor = iio_priv(hw->iio_devs[i]);
+
+		if (!(hw->enable_mask & BIT(sensor->id)))
+			continue;
+
+		err = st_asm330lhh_set_odr(sensor, 0);
+		if (err < 0)
+			return err;
+	}
+
+	if (hw->enable_mask)
+		err = st_asm330lhh_suspend_fifo(hw);
+
+	return err;
+}
+
+static int __maybe_unused st_asm330lhh_resume(struct device *dev)
+{
+	struct st_asm330lhh_hw *hw = dev_get_drvdata(dev);
+	struct st_asm330lhh_sensor *sensor;
+	int i, err = 0;
+
+	for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
+		sensor = iio_priv(hw->iio_devs[i]);
+		if (!(hw->enable_mask & BIT(sensor->id)))
+			continue;
+
+		err = st_asm330lhh_set_odr(sensor, sensor->odr);
+		if (err < 0)
+			return err;
+	}
+
+	if (hw->enable_mask)
+		err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_CONT);
+
+	return err;
+}
+
+const struct dev_pm_ops st_asm330lhh_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(st_asm330lhh_suspend, st_asm330lhh_resume)
+};
+EXPORT_SYMBOL(st_asm330lhh_pm_ops);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ST_ASM330LHH_VERSION);
diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c
new file mode 100644
index 0000000..4875097
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_i2c.c
@@ -0,0 +1,94 @@
+/*
+ * STMicroelectronics st_asm330lhh i2c driver
+ *
+ * Copyright 2018 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_asm330lhh.h"
+
+static int st_asm330lhh_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msg[2];
+
+	msg[0].addr = client->addr;
+	msg[0].flags = client->flags;
+	msg[0].len = 1;
+	msg[0].buf = &addr;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = client->flags | I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = data;
+
+	return i2c_transfer(client->adapter, msg, 2);
+}
+
+static int st_asm330lhh_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msg;
+	u8 send[len + 1];
+
+	send[0] = addr;
+	memcpy(&send[1], data, len * sizeof(u8));
+
+	msg.addr = client->addr;
+	msg.flags = client->flags;
+	msg.len = len + 1;
+	msg.buf = send;
+
+	return i2c_transfer(client->adapter, &msg, 1);
+}
+
+static const struct st_asm330lhh_transfer_function st_asm330lhh_transfer_fn = {
+	.read = st_asm330lhh_i2c_read,
+	.write = st_asm330lhh_i2c_write,
+};
+
+static int st_asm330lhh_i2c_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	return st_asm330lhh_probe(&client->dev, client->irq,
+				&st_asm330lhh_transfer_fn);
+}
+
+static const struct of_device_id st_asm330lhh_i2c_of_match[] = {
+	{
+		.compatible = "st,asm330lhh",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, st_asm330lhh_i2c_of_match);
+
+static const struct i2c_device_id st_asm330lhh_i2c_id_table[] = {
+	{ ST_ASM330LHH_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, st_asm330lhh_i2c_id_table);
+
+static struct i2c_driver st_asm330lhh_driver = {
+	.driver = {
+		.name = "st_asm330lhh_i2c",
+		.pm = &st_asm330lhh_pm_ops,
+		.of_match_table = of_match_ptr(st_asm330lhh_i2c_of_match),
+	},
+	.probe = st_asm330lhh_i2c_probe,
+	.id_table = st_asm330lhh_i2c_id_table,
+};
+module_i2c_driver(st_asm330lhh_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh i2c driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ST_ASM330LHH_VERSION);
diff --git a/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c
new file mode 100644
index 0000000..07b8400
--- /dev/null
+++ b/drivers/iio/imu/st_asm330lhh/st_asm330lhh_spi.c
@@ -0,0 +1,109 @@
+/*
+ * STMicroelectronics st_asm330lhh spi driver
+ *
+ * Copyright 2018 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_asm330lhh.h"
+
+#define SENSORS_SPI_READ	BIT(7)
+
+static int st_asm330lhh_spi_read(struct device *dev, u8 addr, int len,
+			       u8 *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct st_asm330lhh_hw *hw = spi_get_drvdata(spi);
+	int err;
+
+	struct spi_transfer xfers[] = {
+		{
+			.tx_buf = hw->tb.tx_buf,
+			.bits_per_word = 8,
+			.len = 1,
+		},
+		{
+			.rx_buf = hw->tb.rx_buf,
+			.bits_per_word = 8,
+			.len = len,
+		}
+	};
+
+	hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
+
+	err = spi_sync_transfer(spi, xfers,  ARRAY_SIZE(xfers));
+	if (err < 0)
+		return err;
+
+	memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
+
+	return len;
+}
+
+static int st_asm330lhh_spi_write(struct device *dev, u8 addr, int len,
+				u8 *data)
+{
+	struct st_asm330lhh_hw *hw;
+	struct spi_device *spi;
+
+	if (len >= ST_ASM330LHH_TX_MAX_LENGTH)
+		return -ENOMEM;
+
+	spi = to_spi_device(dev);
+	hw = spi_get_drvdata(spi);
+
+	hw->tb.tx_buf[0] = addr;
+	memcpy(&hw->tb.tx_buf[1], data, len);
+
+	return spi_write(spi, hw->tb.tx_buf, len + 1);
+}
+
+static const struct st_asm330lhh_transfer_function st_asm330lhh_transfer_fn = {
+	.read = st_asm330lhh_spi_read,
+	.write = st_asm330lhh_spi_write,
+};
+
+static int st_asm330lhh_spi_probe(struct spi_device *spi)
+{
+	return st_asm330lhh_probe(&spi->dev, spi->irq,
+				&st_asm330lhh_transfer_fn);
+}
+
+static const struct of_device_id st_asm330lhh_spi_of_match[] = {
+	{
+		.compatible = "st,asm330lhh",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, st_asm330lhh_spi_of_match);
+
+static const struct spi_device_id st_asm330lhh_spi_id_table[] = {
+	{ ST_ASM330LHH_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(spi, st_asm330lhh_spi_id_table);
+
+static struct spi_driver st_asm330lhh_driver = {
+	.driver = {
+		.name = "st_asm330lhh_spi",
+		.pm = &st_asm330lhh_pm_ops,
+		.of_match_table = of_match_ptr(st_asm330lhh_spi_of_match),
+	},
+	.probe = st_asm330lhh_spi_probe,
+	.id_table = st_asm330lhh_spi_id_table,
+};
+module_spi_driver(st_asm330lhh_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_asm330lhh spi driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ST_ASM330LHH_VERSION);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 0d0fcfe..4bcc512 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -451,7 +451,7 @@ static int isp_vma_fault(struct vm_fault *vmf)
 {
 	struct page *page;
 	struct vfe_device *vfe_dev = vmf->vma->vm_private_data;
-	struct isp_proc *isp_page = NULL;
+	struct isp_kstate *isp_page = NULL;
 
 	isp_page = vfe_dev->isp_page;
 
@@ -743,7 +743,7 @@ int vfe_hw_probe(struct platform_device *pdev)
 	vfe_dev->buf_mgr->init_done = 1;
 	vfe_dev->vfe_open_cnt = 0;
 	/*Allocate a page in kernel and map it to camera user process*/
-	vfe_dev->isp_page = (struct isp_proc *)get_zeroed_page(GFP_KERNEL);
+	vfe_dev->isp_page = (struct isp_kstate *)get_zeroed_page(GFP_KERNEL);
 	if (vfe_dev->isp_page == NULL) {
 		pr_err("%s: no enough memory\n", __func__);
 		rc = -ENOMEM;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index d044d2b..40405a5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2019, 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
@@ -771,11 +771,6 @@ struct msm_vfe_common_subdev {
 	struct msm_vfe_common_dev_data *common_data;
 };
 
-struct isp_proc {
-	uint32_t  kernel_sofid;
-	uint32_t  vfeid;
-};
-
 struct vfe_device {
 	/* Driver private data */
 	struct platform_device *pdev;
@@ -862,7 +857,7 @@ struct vfe_device {
 	uint32_t recovery_irq1_mask;
 	/* total bandwidth per vfe */
 	uint64_t total_bandwidth;
-	struct isp_proc *isp_page;
+	struct isp_kstate *isp_page;
 
 	/* Dual VFE IRQ CAMSS Info*/
 	void __iomem *camss_base;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index d6ec8ae..60db435 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -737,13 +737,13 @@ static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev,
 		return;
 
 	if (irq_status0 & BIT(2)) {
-		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
 		ISP_DBG("%s: EPOCH0 IRQ\n", __func__);
 		msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
 					MSM_ISP_COMP_IRQ_EPOCH, ts);
 		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
 					MSM_ISP_COMP_IRQ_EPOCH);
 		msm_isp_update_error_frame_count(vfe_dev);
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
 		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
 		  && vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) {
 			ISP_DBG("%s: SOF IRQ\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index b1fe6bd..8f0f314 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -175,6 +175,8 @@ static void msm_isp_axi_destroy_stream(
 			stream_info->bufq_handle[k] = 0;
 		stream_info->vfe_mask = 0;
 		stream_info->state = AVAILABLE;
+		memset(&stream_info->request_queue_cmd,
+			0, sizeof(stream_info->request_queue_cmd));
 	}
 }
 
@@ -603,7 +605,8 @@ static int msm_isp_composite_irq(struct vfe_device *vfe_dev,
  *
  * Returns void
  */
-static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info)
+static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info,
+		uint32_t drop_reconfig)
 {
 	if (stream_info->stream_type == BURST_STREAM) {
 		if (stream_info->runtime_num_burst_capture == 0 ||
@@ -613,7 +616,8 @@ static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info)
 				MSM_VFE_STREAM_STOP_PERIOD;
 	}
 
-	if (stream_info->undelivered_request_cnt > 0)
+	if (stream_info->undelivered_request_cnt > 0 &&
+		drop_reconfig != 1)
 		stream_info->current_framedrop_period =
 			MSM_VFE_STREAM_STOP_PERIOD;
 
@@ -668,7 +672,8 @@ void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev,
 			break;
 		case MSM_ISP_COMP_IRQ_EPOCH:
 			if (stream_info->state == ACTIVE)
-				msm_isp_update_framedrop_reg(stream_info);
+				msm_isp_update_framedrop_reg(stream_info,
+					vfe_dev->isp_page->drop_reconfig);
 			break;
 		default:
 			WARN(1, "Invalid irq %d\n", irq);
@@ -3529,8 +3534,15 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
 
 	frame_src = SRC_TO_INTF(stream_info->stream_src);
 	pingpong_status =
-			vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(
-					vfe_dev);
+		vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
+
+	/* As MCT is still processing it, need to drop the additional requests*/
+	if (vfe_dev->isp_page->drop_reconfig) {
+		pr_err("%s: MCT has not yet delayed %d drop request %d\n",
+			__func__, vfe_dev->isp_page->drop_reconfig, frame_id);
+		goto error;
+	}
+
 	/*
 	 * If PIX stream is active then RDI path uses SOF frame ID of PIX
 	 * In case of standalone RDI streaming, SOF are used from
@@ -3544,9 +3556,18 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
 		vfe_dev->axi_data.src_info[frame_src].accept_frame == false) {
 		pr_debug("%s:%d invalid time to request frame %d\n",
 			__func__, __LINE__, frame_id);
-		goto error;
-	}
-	if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id !=
+		vfe_dev->isp_page->drop_reconfig = 1;
+	} else if ((vfe_dev->axi_data.src_info[frame_src].active) &&
+			(frame_id ==
+			vfe_dev->axi_data.src_info[frame_src].frame_id) &&
+			(stream_info->undelivered_request_cnt <=
+				MAX_BUFFERS_IN_HW)) {
+		vfe_dev->isp_page->drop_reconfig = 1;
+		pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d\n",
+			__func__, vfe_dev->pdev->id, frame_id,
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id,
+			vfe_dev->axi_data.src_info[VFE_PIX_0].active);
+	} else if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id !=
 		vfe_dev->axi_data.src_info[frame_src].frame_id +
 		vfe_dev->axi_data.src_info[frame_src].sof_counter_step)) ||
 		((!vfe_dev->axi_data.src_info[frame_src].active))) {
@@ -3650,6 +3671,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
 			stream_info->undelivered_request_cnt--;
 			pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n",
 				__func__, __LINE__);
+			queue_req->cmd_used = 0;
+			list_del(&queue_req->list);
+			stream_info->request_q_cnt--;
 			return rc;
 		}
 
@@ -3686,6 +3710,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
 						flags);
 			pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n",
 				__func__, __LINE__);
+			queue_req->cmd_used = 0;
+			list_del(&queue_req->list);
+			stream_info->request_q_cnt--;
 			return rc;
 		}
 	} else {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
index 1d86a10..3131989 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016, 2018-2019, 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
@@ -84,36 +84,72 @@ int msm_cpp_get_regulator_index(struct cpp_device *cpp_dev,
 	return -EINVAL;
 }
 
-static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info,
-	uint32_t min_clk_rate)
+static int cpp_get_clk_freq_tbl_dt(struct cpp_device *cpp_dev)
 {
-	uint32_t i;
+	uint32_t i, count, min_clk_rate;
 	uint32_t idx = 0;
-	signed long freq_tbl_entry = 0;
+	struct device_node *of_node;
+	uint32_t *rates;
+	int32_t rc = 0;
+	struct cpp_hw_info *hw_info;
 
-	if ((clk == NULL) || (hw_info == NULL)) {
+	if (cpp_dev == NULL) {
 		pr_err("Bad parameter\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto err;
 	}
 
-	for (i = 0; i < MAX_FREQ_TBL; i++) {
-		freq_tbl_entry = clk_round_rate(clk, min_clk_rate);
-		pr_debug("entry=%ld\n", freq_tbl_entry);
-		if (freq_tbl_entry >= 0) {
-			if (freq_tbl_entry >= min_clk_rate) {
-				hw_info->freq_tbl[idx++] = freq_tbl_entry;
-				pr_debug("tbl[%d]=%ld\n", idx-1,
-					freq_tbl_entry);
+	of_node = cpp_dev->pdev->dev.of_node;
+	min_clk_rate = cpp_dev->min_clk_rate;
+	hw_info = &cpp_dev->hw_info;
+	pr_debug("min_clk_rate=%d\n", min_clk_rate);
+
+	if ((hw_info == NULL) || (of_node == NULL)) {
+		pr_err("Invalid hw_info %pK or ofnode %pK\n", hw_info, of_node);
+		rc = -EINVAL;
+		goto err;
+	}
+	count = of_property_count_u32_elems(of_node, "qcom,src-clock-rates");
+	if ((count == 0) || (count > MAX_FREQ_TBL)) {
+		pr_err("Clock count is invalid\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rates = devm_kcalloc(&cpp_dev->pdev->dev, count, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!rates) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,src-clock-rates",
+		rates, count);
+	if (rc) {
+		rc = -EINVAL;
+		goto mem_free;
+	}
+
+	for (i = 0; i < count; i++) {
+		pr_debug("entry=%d\n", rates[i]);
+		if (rates[i] >= 0) {
+			if (rates[i] >= min_clk_rate) {
+				hw_info->freq_tbl[idx++] = rates[i];
+				pr_debug("tbl[%d]=%d\n", idx-1, rates[i]);
 			}
 		} else {
-			pr_debug("freq table returned invalid entry/end %ld\n",
-				freq_tbl_entry);
+			pr_debug("rate is invalid entry/end %d\n", rates[i]);
 			break;
 		}
 	}
-	pr_debug("%s: idx %d", __func__, idx);
+
+	pr_debug("%s: idx %d\n", __func__, idx);
 	hw_info->freq_tbl_count = idx;
-	return 0;
+
+mem_free:
+	devm_kfree(&cpp_dev->pdev->dev, rates);
+err:
+	return rc;
 }
 
 int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev)
@@ -162,8 +198,7 @@ int msm_update_freq_tbl(struct cpp_device *cpp_dev)
 		rc = msm_cpp_core_clk_idx;
 		return rc;
 	}
-	rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx],
-		&cpp_dev->hw_info, cpp_dev->min_clk_rate);
+	rc = cpp_get_clk_freq_tbl_dt(cpp_dev);
 	if (rc < 0)  {
 		pr_err("%s: fail to get frequency table\n", __func__);
 		return rc;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index bc13f78..98dba7c 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -428,6 +428,29 @@ static int get_qseecom_keymaster_status(char *str)
 }
 __setup("androidboot.keymaster=", get_qseecom_keymaster_status);
 
+
+#define QSEECOM_SCM_EBUSY_WAIT_MS 30
+#define QSEECOM_SCM_EBUSY_MAX_RETRY 67
+
+static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc)
+{
+	int ret = 0;
+	int retry_count = 0;
+
+	do {
+		ret = scm_call2_noretry(smc_id, desc);
+		if (ret == -EBUSY) {
+			mutex_unlock(&app_access_lock);
+			msleep(QSEECOM_SCM_EBUSY_WAIT_MS);
+			mutex_lock(&app_access_lock);
+		}
+		if (retry_count == 33)
+			pr_warn("secure world has been busy for 1 second!\n");
+	} while (ret == -EBUSY &&
+			(retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY));
+	return ret;
+}
+
 static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			const void *req_buf, void *resp_buf)
 {
@@ -455,7 +478,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				svc_id, tz_cmd_id);
 			return -EINVAL;
 		}
-		ret = scm_call2(smc_id, &desc);
+		ret = __qseecom_scm_call2_locked(smc_id, &desc);
 		break;
 	}
 	case SCM_SVC_ES: {
@@ -478,7 +501,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = p_hash_req->partition_id;
 			desc.args[1] = virt_to_phys(tzbuf);
 			desc.args[2] = SHA256_DIGEST_LENGTH;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -513,7 +536,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[2] = req_64bit->phy_addr;
 			}
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_APP_SHUTDOWN_COMMAND: {
@@ -523,7 +546,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			smc_id = TZ_OS_APP_SHUTDOWN_ID;
 			desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
 			desc.args[0] = req->app_id;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_APP_LOOKUP_COMMAND: {
@@ -542,7 +565,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = virt_to_phys(tzbuf);
 			desc.args[1] = strlen(req->app_name);
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -566,7 +589,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[1] = req_64bit->size;
 			}
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_LOAD_SERV_IMAGE_COMMAND: {
@@ -590,14 +613,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[2] = req_64bit->phy_addr;
 			}
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: {
 			smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
 			desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_REGISTER_LISTENER: {
@@ -622,12 +645,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			}
 			qseecom.smcinvoke_support = true;
 			smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			if (ret == -EIO) {
 				/* smcinvoke is not supported */
 				qseecom.smcinvoke_support = false;
 				smc_id = TZ_OS_REGISTER_LISTENER_ID;
-				ret = scm_call2(smc_id, &desc);
+				ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			}
 			break;
 		}
@@ -639,7 +662,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
 			desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
 			desc.args[0] = req->listener_id;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_LISTENER_DATA_RSP_COMMAND: {
@@ -652,7 +675,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
 			desc.args[0] = req->listener_id;
 			desc.args[1] = req->status;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
@@ -680,7 +703,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[2] = req_64->sglistinfo_ptr;
 				desc.args[3] = req_64->sglistinfo_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
@@ -702,14 +725,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[2] = req_64bit->phy_addr;
 			}
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: {
 			smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID;
 			desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 			}
 
@@ -737,7 +760,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[3] = req_64bit->rsp_ptr;
 				desc.args[4] = req_64bit->rsp_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
@@ -769,7 +792,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[5] = req_64bit->sglistinfo_ptr;
 				desc.args[6] = req_64bit->sglistinfo_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
@@ -781,21 +804,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
 			desc.args[0] = req->key_type;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_RPMB_ERASE_COMMAND: {
 			smc_id = TZ_OS_RPMB_ERASE_ID;
 			desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: {
 			smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID;
 			desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_GENERATE_KEY: {
@@ -816,7 +839,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = virt_to_phys(tzbuf);
 			desc.args[1] = tzbuflen;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -838,7 +861,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = virt_to_phys(tzbuf);
 			desc.args[1] = tzbuflen;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -860,7 +883,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = virt_to_phys(tzbuf);
 			desc.args[1] = tzbuflen;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -882,7 +905,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.args[0] = virt_to_phys(tzbuf);
 			desc.args[1] = tzbuflen;
 			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			kzfree(tzbuf);
 			break;
 		}
@@ -908,7 +931,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[3] = req_64bit->resp_ptr;
 				desc.args[4] = req_64bit->resp_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
@@ -938,7 +961,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[5] = req_64bit->sglistinfo_ptr;
 				desc.args[6] = req_64bit->sglistinfo_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_TEE_INVOKE_COMMAND: {
@@ -963,7 +986,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[3] = req_64bit->resp_ptr;
 				desc.args[4] = req_64bit->resp_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
@@ -993,7 +1016,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[5] = req_64bit->sglistinfo_ptr;
 				desc.args[6] = req_64bit->sglistinfo_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_TEE_CLOSE_SESSION: {
@@ -1018,7 +1041,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[3] = req_64bit->resp_ptr;
 				desc.args[4] = req_64bit->resp_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_TEE_REQUEST_CANCELLATION: {
@@ -1044,7 +1067,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 				desc.args[3] = req_64bit->resp_ptr;
 				desc.args[4] = req_64bit->resp_len;
 			}
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: {
@@ -1059,7 +1082,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
 			desc.arginfo =
 				TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID;
 			desc.args[0] = req->app_or_session_id;
-			ret = scm_call2(smc_id, &desc);
+			ret = __qseecom_scm_call2_locked(smc_id, &desc);
 			break;
 		}
 		default: {
@@ -6527,7 +6550,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
 		if (ret)
 			break;
 
-		ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc);
+		ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc);
 
 		__qseecom_disable_clk(CLK_QSEE);
 
@@ -8730,8 +8753,10 @@ static int qseecom_check_whitelist_feature(void)
 
 	desc.args[0] = FEATURE_ID_WHITELIST;
 	desc.arginfo = SCM_ARGS(1);
-	ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO,
+	mutex_lock(&app_access_lock);
+	ret = __qseecom_scm_call2_locked(SCM_SIP_FNID(SCM_SVC_INFO,
 		GET_FEAT_VERSION_CMD), &desc);
+	mutex_unlock(&app_access_lock);
 	if (!ret)
 		version = desc.ret[0];
 
@@ -8814,8 +8839,10 @@ static int qseecom_probe(struct platform_device *pdev)
 	qseecom.send_resp_flag = 0;
 
 	qseecom.qsee_version = QSEEE_VERSION_00;
+	mutex_lock(&app_access_lock);
 	rc = qseecom_scm_call(6, 3, &feature, sizeof(feature),
 		&resp, sizeof(resp));
+	mutex_unlock(&app_access_lock);
 	pr_info("qseecom.qsee_version = 0x%x\n", resp.result);
 	if (rc) {
 		pr_err("Failed to get QSEE version info %d\n", rc);
@@ -8968,9 +8995,11 @@ static int qseecom_probe(struct platform_device *pdev)
 				rc = -EIO;
 				goto exit_deinit_clock;
 			}
+			mutex_lock(&app_access_lock);
 			rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
 					cmd_buf, cmd_len,
 					&resp, sizeof(resp));
+			mutex_unlock(&app_access_lock);
 			__qseecom_disable_clk(CLK_QSEE);
 			if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
 				pr_err("send secapp reg fail %d resp.res %d\n",
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0d636b0..c95f8c3 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -708,6 +708,7 @@ static int mmc_devfreq_create_freq_table(struct mmc_host *host)
 int mmc_init_clk_scaling(struct mmc_host *host)
 {
 	int err;
+	struct devfreq *devfreq;
 
 	if (!host || !host->card) {
 		pr_err("%s: unexpected host/card parameters\n",
@@ -763,17 +764,20 @@ int mmc_init_clk_scaling(struct mmc_host *host)
 		host->clk_scaling.ondemand_gov_data.upthreshold,
 		host->clk_scaling.ondemand_gov_data.downdifferential,
 		host->clk_scaling.devfreq_profile.polling_ms);
-	host->clk_scaling.devfreq = devfreq_add_device(
+
+	devfreq = devfreq_add_device(
 		mmc_classdev(host),
 		&host->clk_scaling.devfreq_profile,
 		"simple_ondemand",
 		&host->clk_scaling.ondemand_gov_data);
-	if (!host->clk_scaling.devfreq) {
+
+	if (IS_ERR(devfreq)) {
 		pr_err("%s: unable to register with devfreq\n",
 			mmc_hostname(host));
-		return -EPERM;
+		return PTR_ERR(devfreq);
 	}
 
+	host->clk_scaling.devfreq = devfreq;
 	pr_debug("%s: clk scaling is enabled for device %s (%p) with devfreq %p (clock = %uHz)\n",
 		mmc_hostname(host),
 		dev_name(mmc_classdev(host)),
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 4d155e5..0ba5708 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -692,11 +692,6 @@ static void cnss_qca6290_crash_shutdown(struct cnss_pci_data *pci_priv)
 	cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
 		    plat_priv->driver_state);
 
-	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
-		cnss_pr_dbg("Ignore crash shutdown\n");
-		return;
-	}
-
 	cnss_pci_collect_dump_info(pci_priv, true);
 }
 
@@ -2830,6 +2825,63 @@ static int cnss_pci_get_smmu_cfg(struct cnss_plat_data *plat_priv)
 	return ret;
 }
 
+static void cnss_pci_disable_l1(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct pci_dev *pdev = pci_priv->pci_dev;
+	bool disable_l1 = false;
+	u32 lnkctl_offset;
+	u32 val;
+
+	if (of_property_read_bool(plat_priv->dev_node, "pcie-disable-l1"))
+		disable_l1 = true;
+
+	cnss_pr_dbg("disable_l1 %d\n", disable_l1);
+
+	if (!disable_l1)
+		return;
+
+	lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL;
+	pci_read_config_dword(pdev, lnkctl_offset, &val);
+	cnss_pr_dbg("lnkctl 0x%x\n", val);
+
+	val &= ~PCI_EXP_LNKCTL_ASPM_L1;
+	pci_write_config_dword(pdev, lnkctl_offset, val);
+}
+
+static void cnss_pci_disable_l1ss(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct pci_dev *pdev = pci_priv->pci_dev;
+	bool disable_l1ss = false;
+	u32 l1ss_cap_id_offset;
+	u32 l1ss_ctl1_offset;
+	u32 val;
+
+	if (of_property_read_bool(plat_priv->dev_node, "pcie-disable-l1ss"))
+		disable_l1ss = true;
+
+	cnss_pr_dbg("disable_l1ss %d\n", disable_l1ss);
+
+	if (!disable_l1ss)
+		return;
+
+	l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
+	if (!l1ss_cap_id_offset) {
+		cnss_pr_dbg("could not find L1ss capability register\n");
+		return;
+	}
+
+	l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1;
+
+	pci_read_config_dword(pdev, l1ss_ctl1_offset, &val);
+	cnss_pr_dbg("l1ss_ctl1 0x%x\n", val);
+
+	val &= ~(PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 |
+		 PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2);
+	pci_write_config_dword(pdev, l1ss_ctl1_offset, val);
+}
+
 static int cnss_pci_probe(struct pci_dev *pci_dev,
 			  const struct pci_device_id *id)
 {
@@ -2899,6 +2951,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
 	pci_save_state(pci_dev);
 	pci_priv->default_state = pci_store_saved_state(pci_dev);
 
+	cnss_pci_disable_l1(pci_priv);
+	cnss_pci_disable_l1ss(pci_priv);
+
 	switch (pci_dev->device) {
 	case QCA6174_DEVICE_ID:
 		pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index e9ec931..89115b2 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -8,6 +8,20 @@
 #include <linux/of_pci.h>
 #include <linux/slab.h>
 
+static inline bool __of_pci_pci_compare_id(struct device_node *node,
+					struct pci_dev *dev)
+{
+	char dev_id_str[10];
+
+	scnprintf(dev_id_str, sizeof(dev_id_str), "%04x:%04x", dev->vendor,
+		dev->device);
+
+	if (of_property_match_string(node, "pci-ids", dev_id_str) < 0)
+		return false;
+
+	return true;
+}
+
 static inline int __of_pci_pci_compare(struct device_node *node,
 				       unsigned int data)
 {
@@ -20,14 +34,17 @@ static inline int __of_pci_pci_compare(struct device_node *node,
 	return devfn == data;
 }
 
-struct device_node *of_pci_find_child_device(struct device_node *parent,
-					     unsigned int devfn)
+struct device_node *of_pci_find_child_device(struct pci_dev *dev)
 {
 	struct device_node *node, *node2;
+	struct device_node *parent = dev->bus->dev.of_node;
+	unsigned int devfn = dev->devfn;
 
 	for_each_child_of_node(parent, node) {
 		if (__of_pci_pci_compare(node, devfn))
-			return node;
+			if (__of_pci_pci_compare_id(node, dev))
+				return node;
+
 		/*
 		 * Some OFs create a parent node "multifunc-device" as
 		 * a fake root for all functions of a multi-function
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index e6731ba..cd86fa1 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -22,8 +22,7 @@ void pci_set_of_node(struct pci_dev *dev)
 {
 	if (!dev->bus->dev.of_node)
 		return;
-	dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
-						    dev->devfn);
+	dev->dev.of_node = of_pci_find_child_device(dev);
 
 	if (dev->dev.of_node)
 		of_reserved_mem_device_init_by_idx(&dev->dev, dev->dev.of_node,
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 030115a..cdf26bf 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -128,6 +128,15 @@
 	  Kernel and user-space processes can call the IPA driver
 	  to configure IPA core.
 
+config IPA_DEBUG
+	bool "IPA DEBUG for non-perf build"
+	depends on IPA3
+	help
+	  This driver support more debug info for non-perf build.
+	  If you use the non-perf build and want to have more debug
+	  info enabled, then this flag can be enabled.
+	  It is not suggested to enable this flag for perf build.
+
 config IPA_WDI_UNIFIED_API
 	bool "IPA WDI unified API support"
 	depends on IPA3
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 8fb3031..2733903 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2645,7 +2645,8 @@ void ipa3_q6_pre_shutdown_cleanup(void)
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
-	ipa3_q6_pipe_delay(true);
+	if (!ipa3_ctx->ipa_endp_delay_wa)
+		ipa3_q6_pipe_delay(true);
 	ipa3_q6_avoid_holb();
 	if (ipa3_ctx->ipa_config_is_mhi)
 		ipa3_set_reset_client_cons_pipe_sus_holb(true,
@@ -2669,12 +2670,20 @@ void ipa3_q6_pre_shutdown_cleanup(void)
 	/* Remove delay from Q6 PRODs to avoid pending descriptors
 	 * on pipe reset procedure
 	 */
-	ipa3_q6_pipe_delay(false);
-	ipa3_set_reset_client_prod_pipe_delay(true,
-		IPA_CLIENT_USB_PROD);
-	if (ipa3_ctx->ipa_config_is_mhi)
+	if (!ipa3_ctx->ipa_endp_delay_wa) {
+		ipa3_q6_pipe_delay(false);
 		ipa3_set_reset_client_prod_pipe_delay(true,
-		IPA_CLIENT_MHI_PROD);
+			IPA_CLIENT_USB_PROD);
+		if (ipa3_ctx->ipa_config_is_mhi)
+			ipa3_set_reset_client_prod_pipe_delay(true,
+				IPA_CLIENT_MHI_PROD);
+	} else {
+		ipa3_start_stop_client_prod_gsi_chnl(IPA_CLIENT_USB_PROD,
+						false);
+		if (ipa3_ctx->ipa_config_is_mhi)
+			ipa3_start_stop_client_prod_gsi_chnl(
+					IPA_CLIENT_MHI_PROD, false);
+	}
 
 	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	IPADBG_LOW("Exit with success\n");
@@ -2737,6 +2746,32 @@ void ipa3_q6_post_shutdown_cleanup(void)
 	IPADBG_LOW("Exit with success\n");
 }
 
+/*
+ * ipa3_client_prod_post_shutdown_cleanup () - As part of this function
+ * set end point delay client producer pipes and starting corresponding
+ * gsi channels
+ */
+
+void ipa3_client_prod_post_shutdown_cleanup(void)
+{
+	IPADBG_LOW("ENTER\n");
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	ipa3_set_reset_client_prod_pipe_delay(true,
+				IPA_CLIENT_USB_PROD);
+	ipa3_start_stop_client_prod_gsi_chnl(IPA_CLIENT_USB_PROD, true);
+
+	if (ipa3_ctx->ipa_config_is_mhi) {
+		ipa3_set_reset_client_prod_pipe_delay(true,
+						IPA_CLIENT_MHI_PROD);
+		ipa3_start_stop_client_prod_gsi_chnl(IPA_CLIENT_MHI_PROD, true);
+	}
+
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	IPADBG_LOW("Exit with success\n");
+}
+
 static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset)
 {
 	/* Set 4 bytes of CANARY before the offset */
@@ -5361,6 +5396,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
 	    resource_p->do_testbus_collection_on_crash;
 	ipa3_ctx->do_non_tn_collection_on_crash =
 	    resource_p->do_non_tn_collection_on_crash;
+	ipa3_ctx->ipa_endp_delay_wa = resource_p->ipa_endp_delay_wa;
 
 	WARN(ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL,
 		"Non NORMAL IPA HW mode, is this emulation platform ?");
@@ -5978,6 +6014,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
 	ipa_drv_res->mhi_evid_limits[0] = IPA_MHI_GSI_EVENT_RING_ID_START;
 	ipa_drv_res->mhi_evid_limits[1] = IPA_MHI_GSI_EVENT_RING_ID_END;
 	ipa_drv_res->ipa_fltrt_not_hashable = false;
+	ipa_drv_res->ipa_endp_delay_wa = false;
 
 	/* Get IPA HW Version */
 	result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
@@ -6063,6 +6100,12 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
 	IPADBG(": WDI-2.0 over gsi= %s\n",
 			ipa_drv_res->ipa_wdi2_over_gsi
 			? "True" : "False");
+	ipa_drv_res->ipa_endp_delay_wa =
+			of_property_read_bool(pdev->dev.of_node,
+			"qcom,ipa-endp-delay-wa");
+	IPADBG(": endppoint delay wa = %s\n",
+			ipa_drv_res->ipa_endp_delay_wa
+			? "True" : "False");
 
 	ipa_drv_res->ipa_wdi3_over_gsi =
 			of_property_read_bool(pdev->dev.of_node,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 7d2e947..c2d6945 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -1126,6 +1126,38 @@ int ipa3_set_reset_client_prod_pipe_delay(bool set_reset,
 	return result;
 }
 
+/*
+ * Start/stop the CLIENT PROD pipes in SSR scenarios
+ */
+
+int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client,
+		bool start_chnl)
+{
+	int result = 0;
+	int pipe_idx;
+	struct ipa3_ep_context *ep;
+
+	if (IPA_CLIENT_IS_CONS(client)) {
+		IPAERR("client (%d) not PROD\n", client);
+		return -EINVAL;
+	}
+
+	pipe_idx = ipa3_get_ep_mapping(client);
+
+	if (pipe_idx == IPA_EP_NOT_ALLOCATED) {
+		IPAERR("client (%d) not valid\n", client);
+		return -EINVAL;
+	}
+
+	client_lock_unlock_cb(pipe_idx, true);
+	ep = &ipa3_ctx->ep[pipe_idx];
+	if (start_chnl)
+		result = ipa3_start_gsi_channel(pipe_idx);
+	else
+		result = ipa3_stop_gsi_channel(pipe_idx);
+	client_lock_unlock_cb(pipe_idx, false);
+	return result;
+}
 int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset,
 		enum ipa_client_type client)
 {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index dd6c5e9..19dd608 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1625,6 +1625,7 @@ struct ipa3_context {
 	bool ipa_wdi2;
 	bool ipa_wdi2_over_gsi;
 	bool ipa_wdi3_over_gsi;
+	bool ipa_endp_delay_wa;
 	bool ipa_fltrt_not_hashable;
 	bool use_64_bit_dma_mask;
 	/* featurize if memory footprint becomes a concern */
@@ -1743,6 +1744,7 @@ struct ipa3_plat_drv_res {
 	bool do_register_collection_on_crash;
 	bool do_testbus_collection_on_crash;
 	bool do_non_tn_collection_on_crash;
+	bool ipa_endp_delay_wa;
 };
 
 /**
@@ -2024,6 +2026,11 @@ void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx);
 void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx);
 int ipa3_set_reset_client_prod_pipe_delay(bool set_reset,
 		enum ipa_client_type client);
+int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client,
+		bool start_chnl);
+void ipa3_client_prod_post_shutdown_cleanup(void);
+
+
 int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset,
 		enum ipa_client_type client);
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c
index 98cbcfa7..0b46190 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c
@@ -1091,7 +1091,6 @@ void imp_handle_modem_shutdown(void)
 		}
 	}
 
-	imp_ctx->state = IMP_PROBED;
 	mutex_unlock(&imp_ctx->mutex);
 
 	IMP_FUNC_EXIT();
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index f427140..269550e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -454,12 +454,19 @@ static void ipa3_del_dflt_wan_rt_tables(void)
 
 static void ipa3_copy_qmi_flt_rule_ex(
 	struct ipa_ioc_ext_intf_prop *q6_ul_flt_rule_ptr,
-	struct ipa_filter_spec_ex_type_v01 *flt_spec_ptr)
+	void *flt_spec_ptr_void)
 {
 	int j;
+	struct ipa_filter_spec_ex_type_v01 *flt_spec_ptr;
 	struct ipa_ipfltr_range_eq_16 *q6_ul_filter_nat_ptr;
 	struct ipa_ipfltr_range_eq_16_type_v01 *filter_spec_nat_ptr;
 
+	/*
+	 * pure_ack and tos has the same size and type and we will treat tos
+	 * field as pure_ack in ipa4.5 version
+	 */
+	flt_spec_ptr = (struct ipa_filter_spec_ex_type_v01 *) flt_spec_ptr_void;
+
 	q6_ul_flt_rule_ptr->ip = flt_spec_ptr->ip_type;
 	q6_ul_flt_rule_ptr->action = flt_spec_ptr->filter_action;
 	if (flt_spec_ptr->is_routing_table_index_valid == true)
@@ -571,7 +578,6 @@ static void ipa3_copy_qmi_flt_rule_ex(
 		flt_spec_ptr->filter_rule.ipv4_frag_eq_present;
 }
 
-
 int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01
 		*rule_req)
 {
@@ -602,8 +608,14 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01
 				rmnet_ipa3_ctx->num_q6_rules);
 			goto failure;
 		}
-		ipa3_copy_qmi_flt_rule_ex(&ipa3_qmi_ctx->q6_ul_filter_rule[i],
-			&rule_req->filter_spec_ex_list[i]);
+		if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
+			ipa3_copy_qmi_flt_rule_ex(
+				&ipa3_qmi_ctx->q6_ul_filter_rule[i],
+				&rule_req->filter_spec_ex2_list[i]);
+		else
+			ipa3_copy_qmi_flt_rule_ex(
+				&ipa3_qmi_ctx->q6_ul_filter_rule[i],
+				&rule_req->filter_spec_ex_list[i]);
 	}
 
 	if (rule_req->xlat_filter_indices_list_valid) {
@@ -2855,6 +2867,10 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
 		if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
 			ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
 			ipa3_q6_post_shutdown_cleanup();
+
+		if (ipa3_ctx->ipa_endp_delay_wa)
+			ipa3_client_prod_post_shutdown_cleanup();
+
 		IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
 		break;
 	case SUBSYS_BEFORE_POWERUP:
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index fc797c2..8a2a8dd 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -39,6 +39,8 @@
 #define GENI_SE_DMA_PTR_H(ptr) 0
 #endif
 
+/* Convert BCM threshold to actual frequency x 4 */
+#define CONV_TO_BW(x) (x*20000*4)
 #define NUM_LOG_PAGES 2
 #define MAX_CLK_PERF_LEVEL 32
 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000,
@@ -734,9 +736,9 @@ static int geni_se_rmv_ab_ib(struct geni_se_device *geni_se_dev,
 
 	if (geni_se_dev->num_paths == 2) {
 		geni_se_dev->pdata->usecase[1].vectors[0].ab  =
-			geni_se_dev->cur_ab;
+			CONV_TO_BW(geni_se_dev->cur_ab);
 		geni_se_dev->pdata->usecase[1].vectors[0].ib  =
-			geni_se_dev->cur_ib;
+			CONV_TO_BW(geni_se_dev->cur_ib);
 	}
 
 	if (bus_bw_update && geni_se_dev->num_paths != 2)
@@ -881,9 +883,9 @@ static int geni_se_add_ab_ib(struct geni_se_device *geni_se_dev,
 
 	if (geni_se_dev->num_paths == 2) {
 		geni_se_dev->pdata->usecase[1].vectors[0].ab  =
-			geni_se_dev->cur_ab;
+			CONV_TO_BW(geni_se_dev->cur_ab);
 		geni_se_dev->pdata->usecase[1].vectors[0].ib  =
-			geni_se_dev->cur_ib;
+			CONV_TO_BW(geni_se_dev->cur_ib);
 	}
 
 	if (bus_bw_update && geni_se_dev->num_paths != 2)
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 2c80fb9..0c19d0b 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -394,6 +394,7 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(voltage_vph),
 	POWER_SUPPLY_ATTR(chip_version),
 	POWER_SUPPLY_ATTR(therm_icl_limit),
+	POWER_SUPPLY_ATTR(dc_reset),
 	/* Charge pump properties */
 	POWER_SUPPLY_ATTR(cp_status1),
 	POWER_SUPPLY_ATTR(cp_status2),
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 604776c..7429fed 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -680,14 +680,15 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
 	icnss_pr_err("Received early crash indication from FW\n");
 
 	if (priv) {
+		set_bit(ICNSS_FW_DOWN, &priv->state);
+		icnss_ignore_fw_timeout(true);
+
 		if (test_bit(ICNSS_FW_READY, &priv->state) &&
 		    !test_bit(ICNSS_DRIVER_UNLOADING, &priv->state)) {
 			fw_down_data.crashed = true;
 			icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN,
 						 &fw_down_data);
 		}
-		set_bit(ICNSS_FW_DOWN, &priv->state);
-		icnss_ignore_fw_timeout(true);
 	}
 
 	icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
@@ -1230,9 +1231,14 @@ static int icnss_driver_event_unregister_driver(void *data)
 	}
 
 	set_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
+
+	icnss_block_shutdown(true);
+
 	if (penv->ops)
 		penv->ops->remove(&penv->pdev->dev);
 
+	icnss_block_shutdown(false);
+
 	clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
 	clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
 
diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c
index cce2647..ce079fa 100644
--- a/drivers/soc/qcom/qmi_rmnet.c
+++ b/drivers/soc/qcom/qmi_rmnet.c
@@ -453,7 +453,7 @@ __qmi_rmnet_delete_client(void *port, struct qmi_info *qmi, int idx)
 		qmi->dfc_pending[idx] = NULL;
 	}
 
-	if (!qmi_rmnet_has_client(qmi)) {
+	if (!qmi_rmnet_has_client(qmi) && !qmi_rmnet_has_pending(qmi)) {
 		rmnet_reset_qmi_pt(port);
 		kfree(qmi);
 		return 0;
diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c
index 22704b8..98ca413 100644
--- a/drivers/soc/qcom/rpmh_master_stat.c
+++ b/drivers/soc/qcom/rpmh_master_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, 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
@@ -41,6 +41,7 @@ enum master_smem_id {
 	SLPI,
 	GPU,
 	DISPLAY,
+	SLPI_ISLAND = 613,
 };
 
 enum master_pid {
@@ -70,8 +71,10 @@ struct msm_rpmh_master_data {
 static const struct msm_rpmh_master_data rpmh_masters[] = {
 	{"MPSS", MPSS, PID_MPSS},
 	{"ADSP", ADSP, PID_ADSP},
+	{"ADSP_ISLAND", SLPI_ISLAND, PID_ADSP},
 	{"CDSP", CDSP, PID_CDSP},
 	{"SLPI", SLPI, PID_SLPI},
+	{"SLPI_ISLAND", SLPI_ISLAND, PID_SLPI},
 	{"GPU", GPU, PID_GPU},
 	{"DISPLAY", DISPLAY, PID_DISPLAY},
 };
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index 5e733c4..b443a83 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -127,6 +127,7 @@ struct qusb_phy {
 	void __iomem		*tune2_efuse_reg;
 	void __iomem		*ref_clk_base;
 	void __iomem		*tcsr_clamp_dig_n;
+	void __iomem		*tcsr_conn_box_spare;
 
 	struct clk		*ref_clk_src;
 	struct clk		*ref_clk;
@@ -143,6 +144,8 @@ struct qusb_phy {
 	int			init_seq_len;
 	int			*qusb_phy_init_seq;
 	u32			major_rev;
+	u32			usb_hs_ac_bitmask;
+	u32			usb_hs_ac_value;
 
 	u32			tune2_val;
 	int			tune2_efuse_bit_pos;
@@ -904,6 +907,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
 	int ret = 0, size = 0;
 	const char *phy_type;
 	bool hold_phy_reset;
+	u32 temp;
 
 	qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
 	if (!qphy)
@@ -989,6 +993,32 @@ static int qusb_phy_probe(struct platform_device *pdev)
 		}
 	}
 
+	ret = of_property_read_u32(dev->of_node, "qcom,usb-hs-ac-bitmask",
+					&qphy->usb_hs_ac_bitmask);
+	if (!ret) {
+		ret = of_property_read_u32(dev->of_node, "qcom,usb-hs-ac-value",
+						&qphy->usb_hs_ac_value);
+		if (ret) {
+			dev_err(dev, "usb_hs_ac_value not passed\n", __func__);
+			return ret;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"tcsr_conn_box_spare_0");
+		if (!res) {
+			dev_err(dev, "tcsr_conn_box_spare_0 not passed\n",
+								__func__);
+			return -ENOENT;
+		}
+
+		qphy->tcsr_conn_box_spare = devm_ioremap_nocache(dev,
+						res->start, resource_size(res));
+		if (IS_ERR(qphy->tcsr_conn_box_spare)) {
+			dev_err(dev, "err reading tcsr_conn_box_spare\n");
+			return PTR_ERR(qphy->tcsr_conn_box_spare);
+		}
+	}
+
 	qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
 	if (IS_ERR(qphy->ref_clk_src))
 		dev_dbg(dev, "clk get failed for ref_clk_src\n");
@@ -1212,6 +1242,17 @@ static int qusb_phy_probe(struct platform_device *pdev)
 	if (qphy->tcsr_clamp_dig_n)
 		writel_relaxed(0x0, qphy->tcsr_clamp_dig_n);
 
+	/*
+	 * Write the usb_hs_ac_value to usb_hs_ac_bitmask of tcsr_conn_box_spare
+	 * reg to enable AC/DC coupling
+	 */
+	if (qphy->tcsr_conn_box_spare) {
+		temp = readl_relaxed(qphy->tcsr_conn_box_spare) &
+						~qphy->usb_hs_ac_bitmask;
+		writel_relaxed(temp | qphy->usb_hs_ac_value,
+						qphy->tcsr_conn_box_spare);
+	}
+
 	qphy->suspended = true;
 
 	return ret;
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index bf588a0..5f23aac 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -11,8 +11,7 @@ struct device_node;
 
 #ifdef CONFIG_OF_PCI
 int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq);
-struct device_node *of_pci_find_child_device(struct device_node *parent,
-					     unsigned int devfn);
+struct device_node *of_pci_find_child_device(struct pci_dev *dev);
 int of_pci_get_devfn(struct device_node *np);
 int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
@@ -28,8 +27,7 @@ static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle
 	return 0;
 }
 
-static inline struct device_node *of_pci_find_child_device(struct device_node *parent,
-					     unsigned int devfn)
+static inline struct device_node *of_pci_find_child_device(struct pci_dev *dev)
 {
 	return NULL;
 }
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 40708e2..45197e4 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -325,6 +325,7 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_VOLTAGE_VPH,
 	POWER_SUPPLY_PROP_CHIP_VERSION,
 	POWER_SUPPLY_PROP_THERM_ICL_LIMIT,
+	POWER_SUPPLY_PROP_DC_RESET,
 	/* Charge pump properties */
 	POWER_SUPPLY_PROP_CP_STATUS1,
 	POWER_SUPPLY_PROP_CP_STATUS2,
diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h
index 48baf45..4b734c9 100644
--- a/include/uapi/media/msmb_isp.h
+++ b/include/uapi/media/msmb_isp.h
@@ -27,10 +27,16 @@
 
 #define VFE_HW_LIMIT 1
 #define DUAL_ISP_SYNC 1
-
+#define ISP_KERNEL_STATE 1
 
 struct msm_vfe_cfg_cmd_list;
 
+struct isp_kstate {
+	uint32_t kernel_sofid;
+	uint32_t drop_reconfig;
+	uint32_t vfeid;
+};
+
 enum ISP_START_PIXEL_PATTERN {
 	ISP_BAYER_RGRGRG,
 	ISP_BAYER_GRGRGR,