Merge "Merge android-4.9.186 (cd46375) into msm-4.9"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 790e713..1c2f92c 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -210,14 +210,31 @@
 			echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
 			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) oldconfig; fi
 
-$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+TARGET_PREBUILT_INT_KERNEL_IMAGE := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image
+$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_USR)
+$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+	$(hide) echo "Building kernel modules..."
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) Image
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install
+	$(mv-modules)
+	$(clean-module-folder)
+
+$(TARGET_PREBUILT_INT_KERNEL): $(TARGET_PREBUILT_INT_KERNEL_IMAGE)
 	$(hide) echo "Building kernel..."
 	$(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts
 	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS)
+else
+TARGET_PREBUILT_INT_KERNEL_IMAGE := $(TARGET_PREBUILT_INT_KERNEL)
+$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+	$(hide) echo "Building kernel..."
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS)
 	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules
 	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install
 	$(mv-modules)
 	$(clean-module-folder)
+endif
 
 $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT)
 	$(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \
diff --git a/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt b/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt
new file mode 100644
index 0000000..716b0a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt
@@ -0,0 +1,31 @@
+* Microchip MCP2517 stand-alone CAN controller device tree bindings
+
+Required properties:
+ - compatible: Should be one of the following:
+   - "microchip,mcp2517fd" for MCP2517fd.
+ - reg: SPI chip select.
+ - clocks: The clock feeding the CAN controller.
+ - interrupt-parent: The parent interrupt controller.
+ - interrupts: Should contain IRQ line for the CAN controller.
+ - gpio-controller: Marks the device node as a GPIO controller
+
+Optional properties:
+ - vdd-supply: Regulator that powers the CAN controller.
+ - xceiver-supply: Regulator that powers the CAN transceiver.
+ - microchip,clock_out_div = <0|1|2|4|10>: Clock output pin divider
+					   0 = Start of Frame output
+					   default: 10
+ - microchip,clock_div2: bool: divide the internal clock by 2
+ - gpio_opendrain: bool: enable open-drain for all pins (except cantx)
+
+Example:
+	can0: can@1 {
+		compatible = "microchip,mcp2515";
+		reg = <1>;
+		clocks = <&clk24m>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <13 0x8>;
+		vdd-supply = <&reg5v0>;
+		xceiver-supply = <&reg5v0>;
+		gpio-controller;
+	};
diff --git a/arch/arm/boot/dts/qcom/sa415m-ccard-pcie-ep.dts b/arch/arm/boot/dts/qcom/sa415m-ccard-pcie-ep.dts
index c2a447b..2eaca02 100644
--- a/arch/arm/boot/dts/qcom/sa415m-ccard-pcie-ep.dts
+++ b/arch/arm/boot/dts/qcom/sa415m-ccard-pcie-ep.dts
@@ -31,6 +31,8 @@
 
 &ipa_hw {
 	qcom,use-ipa-in-mhi-mode;
+	qcom,ipa-config-is-auto;
+	qcom,mhi-event-ring-id-limits = <7 11>; /* start and end */
 };
 
 &cnss_pcie {
diff --git a/arch/arm/boot/dts/qcom/sa415m-ccard-usb-ep.dts b/arch/arm/boot/dts/qcom/sa415m-ccard-usb-ep.dts
index 1cf3a55..70e2849 100644
--- a/arch/arm/boot/dts/qcom/sa415m-ccard-usb-ep.dts
+++ b/arch/arm/boot/dts/qcom/sa415m-ccard-usb-ep.dts
@@ -20,3 +20,8 @@
 		"qcom,sdxpoorwills", "qcom,ccard";
 	qcom,board-id = <25 2>, <25 0x102>;
 };
+
+&ipa_hw {
+	qcom,ipa-config-is-auto;
+};
+
diff --git a/arch/arm/boot/dts/qcom/sa415m-ttp-usb-ep.dts b/arch/arm/boot/dts/qcom/sa415m-ttp-usb-ep.dts
index 802e8319..ffbc8de 100644
--- a/arch/arm/boot/dts/qcom/sa415m-ttp-usb-ep.dts
+++ b/arch/arm/boot/dts/qcom/sa415m-ttp-usb-ep.dts
@@ -29,3 +29,8 @@
 &mss_mem {
 	reg = <0x86400000 0x9300000>;
 };
+
+&ipa_hw {
+	qcom,ipa-config-is-auto;
+};
+
diff --git a/arch/arm/boot/dts/qcom/sa415m-ttp.dtsi b/arch/arm/boot/dts/qcom/sa415m-ttp.dtsi
index 27d4437..b0d746a 100644
--- a/arch/arm/boot/dts/qcom/sa415m-ttp.dtsi
+++ b/arch/arm/boot/dts/qcom/sa415m-ttp.dtsi
@@ -20,10 +20,17 @@
 	status = "okay";
 };
 
+&sdhc_1 {
+	qcom,nonremovable;
+};
+
 &usb {
 	status = "okay";
 	qcom,connector-type-uAB;
 	extcon = <0>, <0>, <0>, <&vbus_detect>;
+	dwc3@a600000 {
+		normal-eps-in-gsi-mode;
+	};
 };
 
 &soc {
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index b903f85..575cf5e 100755
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -384,6 +384,8 @@
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CP210X=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig
index 655d4db..2feff14 100755
--- a/arch/arm/configs/msm8937-perf_defconfig
+++ b/arch/arm/configs/msm8937-perf_defconfig
@@ -554,6 +554,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig
index 6e9f546..fa4dc50 100755
--- a/arch/arm/configs/msm8937_defconfig
+++ b/arch/arm/configs/msm8937_defconfig
@@ -565,6 +565,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/msm8937go-perf_defconfig b/arch/arm/configs/msm8937go-perf_defconfig
index 6ab6c96..8b9fd07 100755
--- a/arch/arm/configs/msm8937go-perf_defconfig
+++ b/arch/arm/configs/msm8937go-perf_defconfig
@@ -548,6 +548,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/msm8937go_defconfig b/arch/arm/configs/msm8937go_defconfig
index 41f11be..4ebb26b 100755
--- a/arch/arm/configs/msm8937go_defconfig
+++ b/arch/arm/configs/msm8937go_defconfig
@@ -557,6 +557,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index d072b67..e008aa1 100755
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -555,6 +555,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 8ba9cce..a4ccfb7 100755
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -565,6 +565,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/sa415m-perf_defconfig b/arch/arm/configs/sa415m-perf_defconfig
index a517020..5a9b777 100644
--- a/arch/arm/configs/sa415m-perf_defconfig
+++ b/arch/arm/configs/sa415m-perf_defconfig
@@ -229,7 +229,7 @@
 CONFIG_CLD_LL_CORE=y
 CONFIG_CNSS_GENL=y
 # CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
diff --git a/arch/arm/configs/sa415m_defconfig b/arch/arm/configs/sa415m_defconfig
index e10d4ef..c3ec5c5 100644
--- a/arch/arm/configs/sa415m_defconfig
+++ b/arch/arm/configs/sa415m_defconfig
@@ -230,7 +230,7 @@
 CONFIG_CLD_LL_CORE=y
 CONFIG_CNSS_GENL=y
 # CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
@@ -445,6 +445,7 @@
 CONFIG_PWM_QPNP=y
 CONFIG_QCOM_SHOW_RESUME_IRQ=y
 CONFIG_ANDROID=y
+CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_VFAT_FS=y
diff --git a/arch/arm/configs/sdm670-perf_defconfig b/arch/arm/configs/sdm670-perf_defconfig
index d597ff0..a4d1631 100755
--- a/arch/arm/configs/sdm670-perf_defconfig
+++ b/arch/arm/configs/sdm670-perf_defconfig
@@ -99,9 +99,11 @@
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
+CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
 CONFIG_INET_IPCOMP=y
+CONFIG_INET_UDP_DIAG=y
 CONFIG_INET_DIAG_DESTROY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -117,7 +119,6 @@
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
 CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=y
 CONFIG_NF_CONNTRACK_FTP=y
@@ -163,6 +164,7 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -196,6 +198,7 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_IP_SCTP=y
 CONFIG_L2TP=y
 CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=y
@@ -465,6 +468,7 @@
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MSM_QMP=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig
index 83aaf9b..8d9d85b 100755
--- a/arch/arm/configs/sdm670_defconfig
+++ b/arch/arm/configs/sdm670_defconfig
@@ -102,9 +102,11 @@
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
+CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
 CONFIG_INET_IPCOMP=y
+CONFIG_INET_UDP_DIAG=y
 CONFIG_INET_DIAG_DESTROY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -120,7 +122,6 @@
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
 CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=y
 CONFIG_NF_CONNTRACK_FTP=y
@@ -167,6 +168,7 @@
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -200,6 +202,7 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_IP_SCTP=y
 CONFIG_L2TP=y
 CONFIG_L2TP_DEBUGFS=y
 CONFIG_L2TP_V3=y
@@ -477,6 +480,7 @@
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
 CONFIG_MSM_QMP=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index d4ebf56..1d85857 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -92,7 +92,14 @@
 	u64 cval;
 
 	isb();
+#if IS_ENABLED(CONFIG_MSM_TIMER_LEAP)
+#define L32_BITS	0x00000000FFFFFFFF
+	do {
+		asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
+	} while ((cval & L32_BITS) == L32_BITS);
+#else
 	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
+#endif
 	return cval;
 }
 
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-rm69090-qvga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-rm69090-qvga-cmd.dtsi
new file mode 100644
index 0000000..9c0ffc5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-rm69090-qvga-cmd.dtsi
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_truly_rm69090_qvga_cmd: qcom,mdss_dsi_truly_rm69090_qvga_cmd {
+		qcom,mdss-dsi-panel-name = "rm69090 qvga cmd mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <368>;
+		qcom,mdss-dsi-panel-height = <448>;
+		qcom,mdss-dsi-h-front-porch = <40>;
+		qcom,mdss-dsi-h-back-porch = <20>;
+		qcom,mdss-dsi-h-pulse-width = <2>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <8>;
+		qcom,mdss-dsi-v-front-porch = <6>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-pixel-packing = "tight";
+		qcom,mdss-dsi-pixel-alignment = <0>;
+		qcom,mdss-dsi-on-command = [
+			15 01 00 00 00 00 02 FE 00
+			15 01 00 00 00 00 02 35 00
+			15 01 00 00 00 00 02 51 80
+			39 01 00 00 00 00 05 2A 00 10 01 7F
+			39 01 00 00 00 00 05 2B 00 00 01 BF
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 40 00 02 29 00
+			];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 28 00 02 28 00
+			05 01 00 00 78 00 02 10 00
+			15 01 00 00 00 00 02 4F 01
+			];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-idle-on-command = [
+			05 01 00 00 00 00 01 39   /* Idle-Mode On */
+			];
+		qcom,mdss-dsi-idle-off-command = [
+			05 01 00 00 00 00 01 38   /* Idle-Mode Off */
+			];
+		qcom,mdss-dsi-idle-on-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-idle-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
+			22 27 1e 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x09>;
+		qcom,mdss-dsi-t-clk-pre = <0x2c>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+		qcom,mdss-dsi-reset-sequence = <1 1>, <0 12>, <1 12>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
index 6d384fc..010694d 100644
--- a/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
@@ -19,9 +19,9 @@
 		qcom,hpm-min-load = <100000>;
 		status = "disabled";
 
-		regulator-s2 {
+		regulator-s1 {
 			compatible = "qcom,rpm-smd-regulator";
-			regulator-name = "pm660_s2";
+			regulator-name = "pm660_s1";
 			qcom,set = <3>;
 			status = "disabled";
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt-overlay.dts
deleted file mode 100644
index a90c4ba..0000000
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt-overlay.dts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/dts-v1/;
-/plugin/;
-
-#include "sdm429-qrd-spyro-evt.dtsi"
-
-/ {
-	model = "Qualcomm Technologies, Inc. SDM429 QRD Spyro Overlay";
-	qcom,board-id = <0xb 6>;
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dts
deleted file mode 100644
index c9d952d..0000000
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/dts-v1/;
-
-#include "sdm429.dtsi"
-#include "sdm429-qrd-spyro-evt.dtsi"
-
-/ {
-	model = "Qualcomm Technologies, Inc. SDM429 QRD Spyro";
-	compatible = "qcom,sdm429-qrd", "qcom,sdm429", "qcom,qrd";
-	qcom,board-id = <0xb 6>;
-	qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>;
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dtsi
deleted file mode 100644
index eaa844b..0000000
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd-spyro-evt.dtsi
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Copyright (c) 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include "sdm439-qrd.dtsi"
-#include "sdm429w-pm660.dtsi"
-
-&gpio_key_active {
-	mux {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
-		function = "gpio";
-	};
-
-	config {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
-		drive-strength = <2>;
-		bias-pull-up;
-	};
-};
-
-&gpio_key_suspend {
-	mux {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
-		function = "gpio";
-	};
-
-	config {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
-		drive-strength = <2>;
-		bias-pull-up;
-	};
-};
-
-&cdc_pdm_lines_act {
-	mux {
-		pins = "gpio68", "gpio73", "gpio74";
-		function = "cdc_pdm0";
-	};
-
-	config {
-		pins = "gpio68", "gpio73", "gpio74";
-		drive-strength = <16>;
-	};
-};
-
-&cdc_pdm_lines_sus {
-	mux {
-		pins = "gpio68", "gpio73", "gpio74";
-		function = "cdc_pdm0";
-	};
-
-	config {
-		pins = "gpio68", "gpio73", "gpio74";
-		drive-strength = <2>;
-		bias-disable;
-	};
-};
-
-&cam_sensor_rear_standby {
-	/* STANDBY */
-	mux {
-		/delete-property/ pins;
-		pins = "gpio92";
-		function = "gpio";
-	};
-
-	config {
-		/delete-property/ pins;
-		pins = "gpio92";
-		bias-disable; /* No PULL */
-		drive-strength = <2>; /* 2 MA */
-	};
-};
-
-&cam_sensor_rear_standby_sleep {
-	/* STANDBY */
-	mux {
-		/delete-property/ pins;
-		pins = "gpio92";
-		function = "gpio";
-	};
-
-	config {
-		/delete-property/ pins;
-		pins = "gpio92";
-		bias-disable; /* No PULL */
-		drive-strength = <2>; /* 2 MA */
-	};
-};
-
-&cam_sensor_rear_vana {
-	/* VANA */
-	mux {
-		/delete-property/ pins;
-		pins = "gpio58";
-		function = "gpio";
-	};
-
-	config {
-		/delete-property/ pins;
-		pins = "gpio58";
-		bias-disable; /* No PULL */
-		drive-strength = <2>; /* 2 MA */
-	};
-};
-
-&cam_sensor_rear_vana_sleep {
-	/* VANA */
-	mux {
-		/delete-property/ pins;
-		pins = "gpio58";
-		function = "gpio";
-	};
-
-	config {
-		/delete-property/ pins;
-		pins = "gpio58";
-		bias-disable; /* No PULL */
-		drive-strength = <2>; /* 2 MA */
-	};
-};
-&mdss_dsi0 {
-	qcom,dsi-pref-prim-pan = <&dsi_edo_rm67162_qvga_cmd>;
-	pinctrl-names = "mdss_default", "mdss_sleep";
-	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
-	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
-	qcom,platform-te-gpio = <&tlmm 24 0>;
-	qcom,platform-reset-gpio = <&tlmm 60 0>;
-	qcom,platform-enable-gpio = <&tlmm 69 0>;
-};
-
-&dsi_edo_rm67162_qvga_cmd {
-	/delete-property/ qcom,mdss-dsi-panel-timings;
-	qcom,mdss-dsi-panel-timings-phy-12nm = [06 05 01 0A 00 03 01 0F];
-	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
-	qcom,panel-supply-entries = <&dsi_pm660_panel_pwr_supply>;
-};
-&soc {
-	/delete-node/ qcom,cci@1b0c000;
-	cci: qcom,cci@1b0c000 {
-		status = "ok";
-		cell-index = <0>;
-		compatible = "qcom,cci";
-		reg = <0x1b0c000 0x4000>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		reg-names = "cci";
-		interrupts = <0 50 0>;
-		interrupt-names = "cci";
-		clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
-			<&clock_gcc clk_cci_clk_src>,
-			<&clock_gcc clk_gcc_camss_cci_ahb_clk>,
-			<&clock_gcc clk_gcc_camss_cci_clk>,
-			<&clock_gcc clk_gcc_camss_ahb_clk>,
-			<&clock_gcc clk_gcc_camss_top_ahb_clk>;
-		clock-names = "ispif_ahb_clk", "cci_src_clk",
-			"cci_ahb_clk", "camss_cci_clk",
-			"camss_ahb_clk", "camss_top_ahb_clk";
-		qcom,clock-rates = <61540000 19200000 0 0 0 0>,
-				<61540000 37500000 0 0 0 0>;
-		pinctrl-names = "cci_default", "cci_suspend";
-			pinctrl-0 = <&cci0_active &cci1_active>;
-			pinctrl-1 = <&cci0_suspend &cci1_suspend>;
-		gpios = <&tlmm 29 0>,
-			<&tlmm 30 0>,
-			<&tlmm 31 0>,
-			<&tlmm 32 0>;
-		qcom,gpio-tbl-num = <0 1 2 3>;
-		qcom,gpio-tbl-flags = <1 1 1 1>;
-		qcom,gpio-tbl-label = "CCI_I2C_DATA0",
-						"CCI_I2C_CLK0",
-						"CCI_I2C_DATA1",
-						"CCI_I2C_CLK1";
-		i2c_freq_100Khz: qcom,i2c_standard_mode {
-			status = "disabled";
-		};
-		i2c_freq_400Khz: qcom,i2c_fast_mode {
-			status = "disabled";
-		};
-		i2c_freq_custom: qcom,i2c_custom_mode {
-			status = "disabled";
-		};
-
-		i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
-			status = "disabled";
-		};
-	};
-};
-
-#include "sdm429w-camera-sensor-spyro.dtsi"
-
-&i2c_5 {
-	status = "disabled";
-};
-
-&vol_up {
-	gpios = <&tlmm 35 0x1>;
-};
-
-&gpio_keys {
-	function_1: function_1 {
-		label = "function_1";
-		gpios = <&tlmm 127 0x1>;
-		linux,input-type = <1>;
-		linux,code = <116>;
-		debounce-interval = <15>;
-		linux,can-disable;
-		gpio-key,wakeup;
-	};
-
-	function_2: function_2 {
-		label = "function_2";
-		gpios = <&tlmm 126 0x1>;
-		linux,input-type = <1>;
-		linux,code = <117>;
-		debounce-interval = <15>;
-		linux,can-disable;
-		gpio-key,wakeup;
-	};
-};
-
-&soc {
-	/delete-node/ qcom,spm@b1d2000;
-	qcom,spm@b1d2000 {
-		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		reg = <0xb1d2000 0x1000>;
-		qcom,name = "system-cci";
-		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x14>;
-		qcom,saw2-spm-dly= <0x3C102800>;
-		qcom,saw2-spm-ctl = <0xe>;
-		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
-		qcom,vctl-timeout-us = <500>;
-		qcom,vctl-port = <0x0>;
-		qcom,vctl-port-ub = <0x1>;
-		qcom,pfm-port = <0x2>;
-	};
-
-};
-
-
-&dsi_hx8399c_hd_vid {
-		qcom,mdss-dsi-on-command = [
-			39 01 00 00 00 00 04
-				b9 ff 83 99
-			39 01 00 00 00 00 02
-				d2 88
-			39 01 00 00 00 00 0c
-				b1 02 04 72 92 01
-				32 aa 11 11 52 57
-			39 01 00 00 00 00 10
-				b2 00 80 80 cc 05 07 5a
-				11 10 10 00 1e 70 03 d4
-			39 01 00 00 00 00 2d
-				b4 00 ff 59 59 01 ab 00
-				00 09 00 03 05 00 28 03
-				0b 0d 21 03 02 00 0c a3
-				80 59 59 02 ab 00 00 09
-				00 03 05 00 28 03 0b 0d
-				02 00 0c a3 01
-			39 01 00 00 05 00 22
-				d3 00 0c 03 03 00 00 10
-				10 00 00 03 00 03 00 08
-				78 08 78 00 00 00 00 00
-				24 02 05 05 03 00 00 00
-				05 40
-			39 01 00 00 05 00 21
-				d5 20 20 19 19 18 18 02
-				03 00 01 24 24 18 18 18
-				18 24 24 00 00 00 00 00
-				00 00 00 2f 2f 30 30 31
-				31
-			39 01 00 00 05 00 21
-				d6 24 24 18 18 19 19 01
-				00 03 02 24 24 18 18 18
-				18 20 20 40 40 40 40 40
-				40 40 40 2f 2f 30 30 31
-				31
-			39 01 00 00 00 00 02
-				bd 00
-			39 01 00 00 00 00 11
-				d8 aa aa aa aa aa aa aa
-				aa aa ba aa aa aa ba aa
-				aa
-			39 01 00 00 00 00 02
-				bd 01
-			39 01 00 00 00 00 11
-				d8 00 00 00 00 00 00 00
-				00 82 ea aa aa 82 ea aa
-				aa
-			39 01 00 00 00 00 02
-				bd 02
-			39 01 00 00 00 00 09
-				d8 ff ff c0 3f ff ff c0
-				3f
-			39 01 00 00 00 00 02
-				bd 00
-			39 01 00 00 05 00 37
-				e0 01 21 31 2d 66 6f 7b
-				75 7a 81 86 89 8c 90 95
-				97 9a a1 a2 aa 9e ad b0
-				5b 57 63 7a 01 21 31 2d
-				66 6f 7b 75 7a 81 86 89
-				8c 90 95 97 9a a1 a2 aa
-				9e ad b0 5b 57 63 7a
-			39 01 00 00 00 00 03
-				b6 7e 7e
-			39 01 00 00 00 00 02
-				cc 08
-			39 01 00 00 00 00 02
-				35 00
-			39 01 00 00 00 00 02
-				dd 03
-			05 01 00 00 78 00 02 11 00
-			05 01 00 00 05 00 02 29 00];
-		qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 10>;
-	};
-
-&firmware {
-	android {
-		compatible = "android,firmware";
-		vbmeta {
-			compatible = "android,vbmeta";
-			parts = "vbmeta,boot,system,vendor,dtbo,recovery";
-		};
-		fstab {
-			compatible = "android,fstab";
-			vendor {
-				compatible = "android,vendor";
-				dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
-				type = "ext4";
-				mnt_flags = "ro,barrier=1,discard";
-				fsmgr_flags = "wait,avb";
-				status = "ok";
-			};
-			system {
-				compatible = "android,system";
-				dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
-				type = "ext4";
-				mnt_flags = "ro,barrier=1,discard";
-				fsmgr_flags = "wait,avb";
-				status = "ok";
-			};
-		};
-	};
-};
-
-&i2c_4 {
-	status = "ok";
-
-	tsc@24 {
-		compatible = "cy,cyttsp5_i2c_adapter";
-		reg = <0x24>;
-
-		interrupt-parent = <&tlmm>;
-		interrupts = <65 0x2008>;
-		cy,adapter_id = "cyttsp5_i2c_adapter";
-		vcc_i2c-supply = <&L13A>;
-		vdd-supply = <&L15A>;
-		pinctrl-names = "pmx_ts_active", "pmx_ts_suspend",
-				"pmx_ts_release";
-		pinctrl-0 = <&ts_int_active &ts_reset_active>;
-		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
-		pinctrl-2 = <&ts_release>;
-
-		cy,core {
-			cy,name = "cyttsp5_core";
-			cy,irq_gpio = <65>;
-			cy,rst_gpio = <64>;
-			cy,hid_desc_register = <1>;
-			cy,flags = <4>;
-			cy,easy_wakeup_gesture = <1>;
-			cy,btn_keys = <172 139 158 217 114 115 212 116>;
-			cy,btn_keys-tag = <0>;
-
-			cy,mt {
-				cy,name = "cyttsp5_mt";
-
-				cy,inp_dev_name = "cyttsp5_mt";
-				cy,flags = <0x28>;
-				cy,abs =
-					<0x35 0 320 0 0
-					0x36 0 360 0 0
-					0x3a 0 255 0 0
-					0xffff 0 255 0 0
-					0x39 0 15 0 0
-					0x30 0 255 0 0
-					0x31 0 255 0 0
-					0x34 0xffffff81 127 0 0
-					0x37 0 1 0 0
-					0x3b 0 255 0 0>;
-
-				cy,vkeys_x = <320>;
-				cy,vkeys_y = <360>;
-
-				cy,virtual_keys =
-					<158 1360 90 160 180
-					139 1360 270 160 180
-					172 1360 450 160 180
-					217 1360 630 160 180>;
-			};
-
-			cy,btn {
-				cy,name = "cyttsp5_btn";
-
-				cy,inp_dev_name = "cyttsp5_btn";
-			};
-
-			cy,proximity {
-				cy,name = "cyttsp5_proximity";
-
-				cy,inp_dev_name = "cyttsp5_proximity";
-				cy,abs = <0x19 0 1 0 0>;
-			};
-		};
-	};
-
-};
-
-&tlmm {
-	pmx_ts_int_active {
-		ts_int_active: ts_int_active {
-			mux {
-				pins = "gpio65";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio65";
-				drive-strength = <8>;
-				bias-pull-up;
-			};
-		};
-	};
-
-	pmx_ts_int_suspend {
-		ts_int_suspend: ts_int_suspend {
-			mux {
-				pins = "gpio65";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio65";
-				drive-strength = <2>;
-				bias-pull-down;
-			};
-		};
-	};
-
-	pmx_ts_reset_active {
-		ts_reset_active: ts_reset_active {
-			mux {
-				pins = "gpio64";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio64";
-				drive-strength = <8>;
-				bias-pull-up;
-			};
-		};
-	};
-
-	pmx_ts_reset_suspend {
-		ts_reset_suspend: ts_reset_suspend {
-			mux {
-				pins = "gpio64";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio64";
-				drive-strength = <2>;
-				bias-pull-down;
-			};
-		};
-	};
-
-	pmx_ts_release {
-		ts_release: ts_release {
-			mux {
-				pins = "gpio65", "gpio64";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio65", "gpio64";
-				drive-strength = <2>;
-				bias-pull-down;
-			};
-		};
-	};
-
-	smart_pa_int {
-		pa_int_default: pa_int_default {
-			mux {
-				pins = "gpio73", "gpio73";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio73", "gpio73";
-				drive-strength = <4>;
-				bias-disable;
-			};
-		};
-	};
-
-	smart_pa_rst {
-		pa_rst_default: pa_rst_default {
-			mux {
-				pins = "gpio68", "gpio68";
-				function = "gpio";
-			};
-
-			config {
-				pins = "gpio68", "gpio68";
-				drive-strength = <4>;
-				bias-disable;
-			};
-		};
-	};
-
-};
-
-&modem_mem {
-	reg = <0x0 0x86800000 0x0 0x5000000>;
-};
-
-&adsp_fw_mem {
-	reg = <0x0 0x8b800000 0x0 0x1400000>;
-};
-
-&wcnss_fw_mem {
-	reg = <0x0 0x8cc00000 0x0 0x700000>;
-};
-
-
-&int_codec {
-	compatible = "qcom,msm8952-dig-asoc-snd";
-	status = "okay";
-	qcom,model = "sdm429-qrd-snd-card";
-	qcom,msm-ext-pa = "quaternary";
-	/delete-property/ qcom,split-a2dp;
-	asoc-wsa-codec-names;
-	asoc-wsa-codec-prefixes;
-	ext_pa_aw8896;
-	qcom,audio-routing =
-		"CDC_CONN", "MCLK",
-		"QUAT_MI2S_RX", "DIGITAL_REGULATOR",
-		"TX_I2S_CLK", "DIGITAL_REGULATOR",
-		"DMIC1", "Digital Mic1",
-		"DMIC2", "Digital Mic2";
-	qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
-	qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>;
-	qcom,msm-gpios =
-		"quat_i2s",
-		"dmic";
-	qcom,pinctrl-names =
-		"all_off",
-		"quat_i2s_act",
-		"dmic_act",
-		"quat_i2s_dmic_act";
-	pinctrl-names =
-		"all_off",
-		"quat_i2s_act",
-		"dmic_act",
-		"quat_i2s_dmic_act";
-	pinctrl-0 = <&quat_mi2s_sleep &quat_mi2s_din_sleep
-		&cdc_dmic0_clk_sus &cdc_dmic0_data_sus>;
-	pinctrl-1 = <&quat_mi2s_active &quat_mi2s_din_active
-		&cdc_dmic0_clk_sus &cdc_dmic0_data_sus>;
-	pinctrl-2 = <&quat_mi2s_sleep &quat_mi2s_din_sleep
-		&cdc_dmic0_clk_act &cdc_dmic0_data_act>;
-	pinctrl-3 = <&quat_mi2s_active &quat_mi2s_din_active
-		&cdc_dmic0_clk_act &cdc_dmic0_data_act>;
-	/delete-property/qcom,cdc-us-euro-gpios;
-	/delete-property/qcom,pri-mi2s-gpios;
-	/delete-property/qcom,cdc-us-eu-gpios;
-
-
-	asoc-codec = <&stub_codec>, <&msm_dig_codec>, <&ext_smart_pa>;
-	asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", "ext-smart-pa";
-};
-
-&soc {
-	msm_dig_codec: msm_dig_codec {
-		compatible = "qcom,msm-digital-codec";
-		reg = <0xc0f0000 0x0>;
-		qcom,no-analog-codec;
-		cdc-vdd-digital-supply = <&pm660_l9>;
-		qcom,cdc-vdd-digital-voltage = <1800000 1800000>;
-		qcom,cdc-vdd-digital-current = <10000>;
-		qcom,cdc-on-demand-supplies = "cdc-vdd-digital";
-	};
-
-	cdc_dmic_gpios: cdc_dmic_pinctrl {
-		compatible = "qcom,msm-cdc-pinctrl";
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&cdc_dmic0_clk_act &cdc_dmic0_data_act>;
-		pinctrl-1 = <&cdc_dmic0_clk_sus &cdc_dmic0_data_sus>;
-	};
-
-	cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat {
-		compatible = "qcom,msm-cdc-pinctrl";
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
-		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
-	};
-};
-
-&wsa881x_i2c_f {
-	status = "disabled";
-};
-
-&wsa881x_i2c_45 {
-	status = "disabled";
-};
-
-&wsa881x_analog_vi_gpio {
-	status = "disabled";
-};
-
-&wsa881x_analog_clk_gpio {
-	status = "disabled";
-};
-
-&wsa881x_analog_reset_gpio {
-	status = "disabled";
-};
-
-&cdc_us_euro_sw {
-	status = "disabled";
-};
-
-&cdc_pri_mi2s_gpios {
-	status = "disabled";
-};
-
-&cdc_quin_mi2s_gpios {
-	status = "disabled";
-};
-
-&i2c_2 {
-	ext_smart_pa: aw8896_smartpa@34 {
-		compatible = "awinic,aw8896_smartpa";
-		reg = <0x34>;
-		reset-gpio = <&tlmm 68 0>;
-		irq-gpio = <&tlmm 73 0>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pa_int_default &pa_rst_default>;
-		status = "okay";
-	};
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-camera.dtsi
index 5c15948..8d047ca 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-camera.dtsi
@@ -203,82 +203,40 @@
 	eeprom_spyro1: qcom,eeprom@1 {
 		cell-index = <1>;
 		reg = <0x1>;
-		qcom,eeprom-name = "sunny_8865";
 		compatible = "qcom,eeprom";
-		qcom,slave-addr = <0x6c>;
-		qcom,cci-master = <0>;
-		qcom,num-blocks = <8>;
-
-		qcom,page0 = <1 0x0100 2 0x01 1 1>;
-		qcom,poll0 = <0 0x0 2 0x0 1 0>;
-		qcom,mem0 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page1 = <1 0x5002 2 0x00 1 0>;
-		qcom,poll1 = <0 0x0 2 0x0 1 0>;
-		qcom,mem1 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
-		qcom,poll2 = <0 0x0 2 0x0 1 0>;
-		qcom,mem2 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
-		qcom,poll3 = <0 0x0 2 0x0 1 0>;
-		qcom,mem3 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
-		qcom,poll4 = <0 0x0 2 0x0 1 0>;
-		qcom,mem4 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
-		qcom,poll5 = <0 0x0 2 0x0 1 0>;
-		qcom,mem5 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
-		qcom,poll6 = <0 0x0 2 0x0 1 0>;
-		qcom,mem6 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
-		qcom,poll7 = <0 0x0 2 0x0 1 1>;
-		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+		qcom,cci-master = <1>;
 
 		cam_vdig-supply = <&pm660_l3>;
-		cam_vana-supply = <&pm660_l7>;
-		cam_vio-supply = <&pm660_l6>;
+		cam_vio-supply = <&pm660_l14>;
+		cam_vana-supply = <&pm660_s5>;
 		cam_vaf-supply = <&pm660_l17>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio",
-				"cam_vana", "cam_vaf";
-		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
-		qcom,cam-vreg-max-voltage = <1200000 0 2800000 3200000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-min-voltage = <1200000 1800000 1420000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000 1420000>;
+		qcom,cam-vreg-op-mode = <200000 80000 80000>;
 		pinctrl-names = "cam_default", "cam_suspend";
-		pinctrl-0 = <&cam_sensor_mclk2_default
-			&cam_sensor_front1_default>;
-		pinctrl-1 = <&cam_sensor_mclk2_sleep
-			&cam_sensor_front1_sleep>;
-		gpios = <&tlmm 28 0>,
-			<&tlmm 40 0>,
-			<&tlmm 39 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
-					  "CAM_RESET2",
-					  "CAM_STANDBY2";
-		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
-			"sensor_vreg",
-			"sensor_gpio", "sensor_gpio" , "sensor_clk";
-		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
-			"sensor_gpio_reset", "sensor_gpio_standby",
-			"sensor_cam_mclk";
-		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
-		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
-		status = "disabled";
-		clocks = <&clock_gcc clk_mclk2_clk_src>,
-			<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+			&cam_sensor_front_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 33 0>,
+			<&tlmm 66 0>,
+			<&tlmm 38 0>;
+		qcom,gpio-vana= <1>;
+		qcom,gpio-vdig= <2>;
+		qcom,gpio-reset = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+								"CAM_AVDD1",
+								"CAM_DVDD1",
+								"CAM_RESET1";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+					<&clock_gcc clk_gcc_camss_mclk1_clk>;
 		clock-names = "cam_src_clk", "cam_clk";
-		qcom,clock-rates = <19200000 0>;
+		qcom,clock-rates = <24000000 0>;
 	};
 
 	qcom,camera@0 {
@@ -337,6 +295,8 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom_spyro1>;
+
 		cam_vdig-supply = <&pm660_l3>;
 		cam_vio-supply = <&pm660_l14>;
 		cam_vana-supply = <&pm660_s5>;
@@ -378,7 +338,6 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <270>;
-		qcom,eeprom-src = <&eeprom_spyro1>;
 		qcom,actuator-src = <&actuator_spyro1>;
 		cam_vdig-supply = <&pm660_l3>;
 		cam_vana-supply = <&pm660_l7>;
diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt.dtsi b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt.dtsi
index 3207827..0f73bd9 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt.dtsi
@@ -14,15 +14,48 @@
 #include "sdm429-spyro-qrd-mdss-panels.dtsi"
 #include "sdm429-spyro-qrd-evt-camera.dtsi"
 #include "sdm429-spyro-qrd-evt-audio.dtsi"
+#include <dt-bindings/thermal/thermal.h>
+
+&tlmm {
+	sd_eldo_active {
+		sd_eldo_active: sd_eldo_active {
+			mux {
+				pins = "gpio91";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio91";
+				drive-strength = <2>;
+				bias-pull-up;
+			};
+		};
+	};
+
+	sd_eldo_suspend {
+		sd_eldo_suspend: sd_eldo_suspend {
+			mux {
+				pins = "gpio91";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio91";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+	};
+};
 
 &gpio_key_active {
 	mux {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
+		pins = "gpio127", "gpio128", "gpio35", "gpio126";
 		function = "gpio";
 	};
 
 	config {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
+		pins = "gpio127", "gpio128", "gpio35", "gpio126";
 		drive-strength = <2>;
 		bias-pull-up;
 	};
@@ -30,18 +63,36 @@
 
 &gpio_key_suspend {
 	mux {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
+		pins = "gpio127", "gpio128", "gpio35", "gpio126";
 		function = "gpio";
 	};
 
 	config {
-		pins = "gpio91", "gpio127", "gpio128", "gpio35", "gpio126";
+		pins = "gpio127", "gpio128", "gpio35", "gpio126";
 		drive-strength = <2>;
 		bias-pull-up;
 	};
 };
 
 &soc {
+	/delete-node/ qcom,spm@b1d2000;
+	qcom,spm@b1d2000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb1d2000 0x1000>;
+		qcom,name = "system-cci";
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,vctl-timeout-us = <500>;
+		qcom,vctl-port = <0x0>;
+		qcom,vctl-port-ub = <0x1>;
+		qcom,pfm-port = <0x2>;
+	};
+
 	gpio_keys: gpio_keys {
 		compatible = "gpio-keys";
 		label = "gpio-keys";
@@ -124,8 +175,10 @@
 	qcom,vdd-io-current-level = <200 22000>;
 
 	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
-	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on
+							&sd_eldo_active>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off
+							&sd_eldo_suspend>;
 
 	cd-gpios = <&tlmm 67 0x0>;
 
@@ -189,11 +242,11 @@
 };
 
 &adsp_fw_mem {
-	reg = <0x0 0x8b800000 0x0 0x1400000>;
+	reg = <0x0 0x8b800000 0x0 0x1500000>;
 };
 
 &wcnss_fw_mem {
-	reg = <0x0 0x8cc00000 0x0 0x700000>;
+	reg = <0x0 0x8cd00000 0x0 0x700000>;
 };
 
 &i2c_4 {
@@ -382,3 +435,661 @@
 	};
 
 };
+
+&pm660_vadc {
+	chan@50 {
+		label = "pmic_therm";
+		reg = <0x50>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm660_adc_tm {
+	chan@50 {
+		label = "pmic_therm";
+		reg = <0x50>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x48>;
+		qcom,thermal-node;
+	};
+};
+
+&thermal_zones {
+
+	emmc-therm-adc {
+		status = "disabled";
+	};
+
+	aoss0-lowf {
+		status = "disabled";
+	};
+
+	mdm-core-lowf {
+		status = "disabled";
+	};
+
+	lpass-lowf {
+		status = "disabled";
+	};
+
+	camera-lowf {
+		status = "disabled";
+	};
+
+	cpuss1-lowf {
+		status = "disabled";
+	};
+
+	apc1-cpu0-lowf {
+		status = "disabled";
+	};
+
+	apc1-cpu1-lowf {
+		status = "disabled";
+	};
+
+	apc1-cpu2-lowf {
+		status = "disabled";
+	};
+
+	apc1-cpu3-lowf {
+		status = "disabled";
+	};
+
+	cpuss0-lowf {
+		status = "disabled";
+	};
+
+	gpu-lowf {
+		status = "disabled";
+	};
+
+	aoss0-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 0>;
+		tracks-low;
+
+		trips {
+			aoss0_trip: aoss-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	mdm-core-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 1>;
+		tracks-low;
+
+		trips {
+			mdm_core_trip: mdm-core-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&mdm_core_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&mdm_core_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&mdm_core_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	lpass-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 2>;
+		tracks-low;
+
+		trips {
+			qdsp_trip: qdsp-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&qdsp_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&qdsp_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&qdsp_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	camera-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 3>;
+		tracks-low;
+
+		trips {
+			camera_trip: camera-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	cpuss1-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 4>;
+		tracks-low;
+
+		trips {
+			cpuss1_trip: cpuss1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpuss1_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+					(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpuss1_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpuss1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	apc1-cpu0-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 5>;
+		tracks-low;
+
+		trips {
+			cpu0_trip: apc1-cpu0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	apc1-cpu1-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 6>;
+		tracks-low;
+
+		trips {
+			cpu1_trip: apc1-cpu1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	apc1-cpu2-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 7>;
+		tracks-low;
+
+		trips {
+			cpu2_trip: apc1-cpu2-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	apc1-cpu3-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 8>;
+		tracks-low;
+
+		trips {
+			cpu3_trip: apc1-cpu3-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	cpuss0-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 9>;
+		tracks-low;
+
+		trips {
+			cpuss0_lowf_trip: cpuss0-lowf-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpuss0_lowf_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&cpuss0_lowf_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&cpuss0_lowf_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	gpu-lowfr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 10>;
+		tracks-low;
+
+		trips {
+			gpu_lowf_trip: gpu-lowf-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&gpu_lowf_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2)
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			cx_vdd_cdev {
+				trip = <&gpu_lowf_trip>;
+				cooling-device = <&pm660_cx_cdev 0 0>;
+			};
+
+			modem_vdd_cdev {
+				trip = <&gpu_lowf_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	camera-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm660_adc_tm 0x4e>;
+		wake-capable-sensor;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pmic-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm660_adc_tm 0x50>;
+		wake-capable-sensor;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	quiet-therm-step {
+		polling-delay-passive = <1000>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm660_adc_tm 0x51>;
+		thermal-governor = "step_wise";
+
+		trips {
+			quiet_batt_439_trip1: quiet-batt-trip1 {
+				temperature = <38000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_batt_439_trip2: quiet-batt-trip2 {
+				temperature = <40000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_batt_439_trip3: quiet-batt-trip3 {
+				temperature = <42000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_batt_439_trip4: quiet-batt-trip4 {
+				temperature = <44000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_modem_439_trip1: quiet-modem-trip0 {
+				temperature = <44000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+
+			quiet_modem_439_trip2: quiet-modem-trip1 {
+				temperature = <46000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+
+			quiet_batt_439_trip5: quiet-batt-trip5 {
+				temperature = <46000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_439_batt_trip6_mdm_trip3: quiet-bt-trp6-mdm-trp3 {
+				temperature = <48000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_cpus_439_trip: quiet-cpus-trip {
+				temperature = <48000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+
+			quiet_gpu_439_trip: quiet-gpu-trip {
+				temperature = <50000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+
+			quiet_batt_439_trip7: quiet-batt-trip7 {
+				temperature = <50000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+
+			quiet_modem_439_trip4: quiet-modem-trip3 {
+				temperature = <55000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			skin_cpu0 {
+				trip = <&quiet_cpus_439_trip>;
+				/* throttle from fmax to 1497600KHz */
+				cooling-device = <&CPU0 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-3)>;
+			};
+
+			skin_cpu1 {
+				trip = <&quiet_cpus_439_trip>;
+				cooling-device = <&CPU1 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-3)>;
+			};
+
+			skin_cpu2 {
+				trip = <&quiet_cpus_439_trip>;
+				cooling-device = <&CPU2 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-3)>;
+			};
+
+			skin_cpu3 {
+				trip = <&quiet_cpus_439_trip>;
+				cooling-device = <&CPU3 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-3)>;
+			};
+
+			skin_gpu {
+				trip = <&quiet_gpu_439_trip>;
+				/* throttle from fmax to 510000000Hz */
+				cooling-device = <&msm_gpu THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-2)>;
+			};
+
+			modem_proc_lvl1 {
+				trip = <&quiet_modem_439_trip1>;
+				cooling-device = <&modem_proc 1 1>;
+			};
+
+			modem_proc_lvl2 {
+				trip = <&quiet_modem_439_trip4>;
+				cooling-device = <&modem_proc 3 3>;
+			};
+
+			modem_lvl1 {
+				trip = <&quiet_modem_439_trip2>;
+				cooling-device = <&modem_pa 1 1>;
+			};
+
+			modem_lvl2 {
+				trip = <&quiet_439_batt_trip6_mdm_trip3>;
+				cooling-device = <&modem_pa 2 2>;
+			};
+
+			modem_lvl3 {
+				trip = <&quiet_modem_439_trip4>;
+				cooling-device = <&modem_pa 3 3>;
+			};
+
+			battery_lvl1 {
+				trip = <&quiet_batt_439_trip1>;
+				cooling-device = <&pm660_charger 1 1>;
+			};
+
+			battery_lvl2 {
+				trip = <&quiet_batt_439_trip2>;
+				cooling-device = <&pm660_charger 2 2>;
+			};
+
+			battery_lvl3 {
+				trip = <&quiet_batt_439_trip3>;
+				cooling-device = <&pm660_charger 3 3>;
+			};
+
+			battery_lvl4 {
+				trip = <&quiet_batt_439_trip4>;
+				cooling-device = <&pm660_charger 4 4>;
+			};
+
+			battery_lvl5 {
+				trip = <&quiet_batt_439_trip5>;
+				cooling-device = <&pm660_charger 5 5>;
+			};
+
+			battery_lvl6 {
+				trip = <&quiet_439_batt_trip6_mdm_trip3>;
+				cooling-device = <&pm660_charger 6 6>;
+			};
+
+			battery_lvl7 {
+				trip = <&quiet_batt_439_trip7>;
+				cooling-device = <&pm660_charger 7 7>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-mdss-panels.dtsi
index 247d312..3fecf16 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-mdss-panels.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "dsi-panel-edo-rm67162-qvga-cmd.dtsi"
+#include "dsi-panel-truly-rm69090-qvga-cmd.dtsi"
 
 &soc {
 	dsi_pm660_panel_pwr_supply: dsi_pm660_panel_pwr_supply {
@@ -83,3 +84,11 @@
 	qcom,partial-update-enabled;
 	qcom,panel-roi-alignment = <2 2 4 2 320 2>;
 };
+
+&dsi_truly_rm69090_qvga_cmd {
+	/delete-property/ qcom,mdss-dsi-panel-timings;
+	qcom,mdss-dsi-panel-timings-phy-12nm = [04 04 01 08 00 03 01 0D];
+	qcom,panel-supply-entries = <&dsi_pm660_panel_pwr_supply>;
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "te_signal_check";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-wdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-wdp-overlay.dts
index f70c458..26819ac 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-wdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-wdp-overlay.dts
@@ -20,7 +20,7 @@
 	model = "Qualcomm Technologies, Inc. SDM429 QRD Spyro WDP Overlay";
 	compatible = "qcom,sdm429w-qrd", "qcom,sdm429w", "qcom,qrd";
 	qcom,msm-id = <416 0x0>;
-	qcom,board-id = <0x01000b 6>;
+	qcom,board-id = <0x01000b 7>;
 	qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>;
 };
 
@@ -39,3 +39,64 @@
 &sdhc_2 {
 	cd-gpios = <&tlmm 67 0x1>;
 };
+
+&mdss_dsi {
+	vddio-supply = <&L12A>; /* 1.8v */
+};
+
+&mdss_dsi0_pll {
+	vddio-supply = <&L12A>; /* 1.8V */
+};
+
+&mdss_dsi1_pll {
+	vddio-supply = <&L12A>; /* 1.8V */
+};
+
+&mdss_dsi0 {
+	qcom,platform-enable-gpio = <&pm660_gpios 12 0>;
+	/delete-property/ vdd-supply;
+	qcom,dsi-pref-prim-pan = <&dsi_truly_rm69090_qvga_cmd>;
+};
+&dsi_pm660_panel_pwr_supply {
+	/delete-node/ qcom,panel-supply-entry@0;
+};
+
+&pm660_gpios {
+	gpio@cb00 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <0>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+};
+
+&i2c_4 {
+	status = "ok";
+
+	tsc@24 {
+		cy,core {
+			cy,mt {
+				cy,name = "cyttsp5_mt";
+
+				cy,inp_dev_name = "cyttsp5_mt";
+				cy,flags = <0x8>;
+				cy,abs =
+					<0x35 0 368 0 0
+					 0x36 0 448 0 0
+					 0x3a 0 255 0 0
+					 0xffff 0 255 0 0
+					 0x39 0 15 0 0
+					 0x30 0 255 0 0
+					 0x31 0 255 0 0
+					 0x34 0xffffff81 127 0 0
+					 0x37 0 1 0 0
+					 0x3b 0 255 0 0>;
+
+			};
+
+		};
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-wdp.dts b/arch/arm64/boot/dts/qcom/sdm429-spyro-wdp.dts
index dd12d18..b6eedaf 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-spyro-wdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-wdp.dts
@@ -19,6 +19,6 @@
 	model = "Qualcomm Technologies, Inc. SDM429 QRD Spyro WDP";
 	compatible = "qcom,sdm429w-qrd", "qcom,sdm429w", "qcom,qrd";
 	qcom,msm-id = <416 0x0>;
-	qcom,board-id = <0x01000b 6>;
+	qcom,board-id = <0x01000b 7>;
 	qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm429w-camera-sensor-spyro.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-camera-sensor-spyro.dtsi
index 45756f7..c032db5 100644
--- a/arch/arm64/boot/dts/qcom/sdm429w-camera-sensor-spyro.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429w-camera-sensor-spyro.dtsi
@@ -109,82 +109,40 @@
 	eeprom_spyro1: qcom,eeprom@1 {
 		cell-index = <1>;
 		reg = <0x1>;
-		qcom,eeprom-name = "sunny_8865";
 		compatible = "qcom,eeprom";
-		qcom,slave-addr = <0x6c>;
-		qcom,cci-master = <0>;
-		qcom,num-blocks = <8>;
-
-		qcom,page0 = <1 0x0100 2 0x01 1 1>;
-		qcom,poll0 = <0 0x0 2 0x0 1 0>;
-		qcom,mem0 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page1 = <1 0x5002 2 0x00 1 0>;
-		qcom,poll1 = <0 0x0 2 0x0 1 0>;
-		qcom,mem1 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
-		qcom,poll2 = <0 0x0 2 0x0 1 0>;
-		qcom,mem2 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
-		qcom,poll3 = <0 0x0 2 0x0 1 0>;
-		qcom,mem3 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
-		qcom,poll4 = <0 0x0 2 0x0 1 0>;
-		qcom,mem4 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
-		qcom,poll5 = <0 0x0 2 0x0 1 0>;
-		qcom,mem5 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
-		qcom,poll6 = <0 0x0 2 0x0 1 0>;
-		qcom,mem6 = <0 0x0 2 0x0 1 0>;
-
-		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
-		qcom,poll7 = <0 0x0 2 0x0 1 1>;
-		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+		qcom,cci-master = <1>;
 
 		cam_vdig-supply = <&pm660_l3>;
-		cam_vana-supply = <&pm660_l7>;
-		cam_vio-supply = <&pm660_l6>;
+		cam_vio-supply = <&pm660_l14>;
+		cam_vana-supply = <&pm660_s5>;
 		cam_vaf-supply = <&pm660_l17>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio",
-				"cam_vana", "cam_vaf";
-		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
-		qcom,cam-vreg-max-voltage = <1200000 0 2800000 3200000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-min-voltage = <1200000 1800000 1420000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000 1420000>;
+		qcom,cam-vreg-op-mode = <200000 80000 80000>;
 		pinctrl-names = "cam_default", "cam_suspend";
-		pinctrl-0 = <&cam_sensor_mclk2_default
-			&cam_sensor_front1_default>;
-		pinctrl-1 = <&cam_sensor_mclk2_sleep
-			&cam_sensor_front1_sleep>;
-		gpios = <&tlmm 28 0>,
-			<&tlmm 40 0>,
-			<&tlmm 39 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
-					  "CAM_RESET2",
-					  "CAM_STANDBY2";
-		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
-			"sensor_vreg",
-			"sensor_gpio", "sensor_gpio" , "sensor_clk";
-		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
-			"sensor_gpio_reset", "sensor_gpio_standby",
-			"sensor_cam_mclk";
-		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
-		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+			&cam_sensor_front_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 33 0>,
+			<&tlmm 66 0>,
+			<&tlmm 38 0>;
+		qcom,gpio-vana= <1>;
+		qcom,gpio-vdig= <2>;
+		qcom,gpio-reset = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+								"CAM_AVDD1",
+								"CAM_DVDD1",
+								"CAM_RESET1";
 		status = "ok";
-		clocks = <&clock_gcc clk_mclk2_clk_src>,
-			<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+					<&clock_gcc clk_gcc_camss_mclk1_clk>;
 		clock-names = "cam_src_clk", "cam_clk";
-		qcom,clock-rates = <19200000 0>;
+		qcom,clock-rates = <24000000 0>;
 	};
 
 	qcom,camera@0 {
@@ -244,6 +202,8 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom_spyro1>;
+
 		cam_vdig-supply = <&pm660_l3>;
 		cam_vio-supply = <&pm660_l14>;
 		cam_vaf-supply = <&pm660_l19>;
@@ -286,7 +246,6 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <270>;
-		qcom,eeprom-src = <&eeprom_spyro1>;
 		qcom,actuator-src = <&actuator_spyro1>;
 		cam_vdig-supply = <&pm660_l3>;
 		cam_vana-supply = <&pm660_l7>;
diff --git a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi
index b432ce4..f6d85f4 100644
--- a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi
@@ -370,9 +370,10 @@
 
 /* over-write the PM660 GPIO mappings for 429w */
 &pm660_gpios {
-	interrupts  = <0x0 0xc3 0 IRQ_TYPE_NONE>;
-	interrupt-names = "pm660_gpio4";
-	qcom,gpios-disallowed = <1 2 3 5 6 7 8 9 10 11 12 13>;
+	interrupts  = <0x0 0xc3 0 IRQ_TYPE_NONE>,
+		      <0x0 0xcb 0 IRQ_TYPE_NONE>;
+	interrupt-names = "pm660_gpio4", "pm660_gpio12";
+	qcom,gpios-disallowed = <1 2 3 5 6 7 8 9 10 11 13>;
 };
 
 &pm660_vadc {
@@ -403,6 +404,8 @@
 		qcom,use-extcon;
 		qcom,pd-not-supported;
 
+		dpdm-supply = <&usb_otg>;
+
 		qcom,chgr@1000 {
 			reg = <0x1000 0x100>;
 			interrupts =
diff --git a/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi
index 4b521b2..db76a24 100644
--- a/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi
@@ -55,6 +55,14 @@
 				<RPM_SMD_REGULATOR_LEVEL_BINNING>;
 			qcom,use-voltage-level;
 		};
+
+		pm660_cx_cdev: regulator-cx-cdev {
+			compatible = "qcom,regulator-cooling-device";
+			regulator-cdev-supply = <&pm660_s1_floor_level>;
+			regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS
+					RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			#cooling-cells = <2>;
+		};
 	};
 
 	/* PM660 S2 - VDD_MX supply */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rb3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rb3.dtsi
index 2955610..2db4b60 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rb3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rb3.dtsi
@@ -290,6 +290,11 @@
 
 &pmi8998_fg {
 	qcom,battery-data = <&mtp_batterydata>;
+	status = "disabled";
+};
+
+&bcl_sensor {
+	status = "disabled";
 };
 
 &smb1355_charger_0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-rb3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.1-rb3.dtsi
index cf84ecf..47638e3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.1-rb3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-rb3.dtsi
@@ -33,6 +33,33 @@
 	status = "ok";
 };
 
+&pcie1 {
+	status = "disable";
+};
+
+&soc {
+	clk40M: can_clock {
+	compatible = "fixed-clock";
+	#clock-cells = <0>;
+	clock-frequency = <40000000>;
+	};
+};
+
+&qupv3_se0_spi {
+	status = "ok";
+	can@0 {
+		compatible = "microchip,mcp2517fd";
+		reg = <0>;
+		clocks = <&clk40M>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <104 0>;
+		interrupt-names = "can_irq";
+		spi-max-frequency = <10000000>;
+		gpio-controller;
+		status = "okay";
+	};
+};
+
 &qupv3_se3_i2c {
 	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts
index 1f91311..e23d1a6 100644
--- a/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts
@@ -26,7 +26,8 @@
 	qcom,msm-id =   <265 0>,
 			<301 0>;
 	qcom,board-id = <8 0x10f>,
-			<8 0x117>;
+			<8 0x117>,
+			<8 0x17>;
 	qcom,pmic-id =  <0x0001001b 0x0 0x0 0x0>,
 			<0x0001011b 0x0 0x0 0x0>;
 };
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index d75479e..d233c67 100755
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -104,6 +104,7 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_SYN_COOKIES=y
 CONFIG_NET_IPVTI=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
@@ -125,7 +126,6 @@
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
 CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=y
 CONFIG_NF_CONNTRACK_FTP=y
@@ -172,6 +172,7 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -205,6 +206,7 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_IP_SCTP=y
 CONFIG_L2TP=y
 CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=y
@@ -249,6 +251,7 @@
 CONFIG_DMA_CMA=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 1eea891..25e3245 100755
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -109,6 +109,7 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_SYN_COOKIES=y
 CONFIG_NET_IPVTI=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
@@ -130,7 +131,6 @@
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
 CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=y
 CONFIG_NF_CONNTRACK_FTP=y
@@ -178,6 +178,7 @@
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -211,6 +212,7 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_IP_SCTP=y
 CONFIG_L2TP=y
 CONFIG_L2TP_DEBUGFS=y
 CONFIG_L2TP_V3=y
@@ -258,6 +260,7 @@
 CONFIG_DMA_CMA=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 1ec275b..230ad65 100755
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -235,6 +235,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_SOCKEV_NLMCAST=y
+CONFIG_CAN=y
+CONFIG_CAN_MCP25XXFD=y
 CONFIG_BT=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
@@ -250,6 +252,7 @@
 CONFIG_DMA_CMA=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 1a39bca..4225d8b 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -240,6 +240,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_SOCKEV_NLMCAST=y
+CONFIG_CAN=y
+CONFIG_CAN_MCP25XXFD=y
 CONFIG_BT=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
@@ -256,6 +258,7 @@
 CONFIG_DMA_CMA=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 3b79682..af0c14d 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -40,6 +40,7 @@
  */
 struct thread_info {
 	unsigned long		flags;		/* low level flags */
+	unsigned long		padding[7];
 	mm_segment_t		addr_limit;	/* address limit */
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	u64			ttbr0;		/* saved TTBR0_EL1 */
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index b90bbfe..650585c 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 2013-2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 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
@@ -613,6 +613,23 @@
 	return 0;
 }
 
+static int get_bt_reset_gpio_value(void)
+{
+	int rc = 0;
+	int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst;
+
+	rc = gpio_request(bt_reset_gpio, "bt_sys_rst_n");
+	if (rc) {
+		BT_PWR_ERR("unable to request gpio %d (%d)\n",
+					bt_reset_gpio, rc);
+		return rc;
+	}
+
+	rc = gpio_get_value(bt_reset_gpio);
+	gpio_free(bt_power_pdata->bt_gpio_sys_rst);
+	return rc;
+}
+
 static int bt_power_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -659,7 +676,8 @@
 	btpdev = pdev;
 
 	if (of_id) {
-		if (strcmp(of_id->compatible, "qca,qca6174") == 0) {
+		if ((get_bt_reset_gpio_value() == BT_RESET_GPIO_HIGH_VAL)
+			&& (strcmp(of_id->compatible, "qca,qca6174") == 0)) {
 			bluetooth_toggle_radio(pdev->dev.platform_data, 0);
 			bluetooth_toggle_radio(pdev->dev.platform_data, 1);
 		}
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 57d6544..12c8bd9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -726,29 +726,44 @@
 	return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0;
 }
 
-static int diag_dci_filter_commands(struct diag_pkt_header_t *header)
+static int diag_dci_filter_commands(struct diag_pkt_header_t *header,
+	int header_len)
 {
 	if (!header)
 		return -ENOMEM;
 
-	switch (header->cmd_code) {
-	case 0x7d: /* Msg Mask Configuration */
-	case 0x73: /* Log Mask Configuration */
-	case 0x81: /* Event Mask Configuration */
-	case 0x82: /* Event Mask Change */
-	case 0x60: /* Event Mask Toggle */
-		return 1;
+	if (header_len <= 0)
+		return -EIO;
+
+	if (header_len) {
+		switch (header->cmd_code) {
+		case 0x7d: /* Msg Mask Configuration */
+		case 0x73: /* Log Mask Configuration */
+		case 0x81: /* Event Mask Configuration */
+		case 0x82: /* Event Mask Change */
+		case 0x60: /* Event Mask Toggle */
+			DIAG_LOG(DIAG_DEBUG_DCI,
+				"diag: command not supported: %d\n",
+				header->cmd_code);
+			return 1;
+		}
 	}
 
-	if (header->cmd_code == 0x4b && header->subsys_id == 0x12) {
-		switch (header->subsys_cmd_code) {
-		case 0x60: /* Extended Event Mask Config */
-		case 0x61: /* Extended Msg Mask Config */
-		case 0x62: /* Extended Log Mask Config */
-		case 0x20C: /* Set current Preset ID */
-		case 0x20D: /* Get current Preset ID */
-		case 0x218: /* HDLC Disabled Command */
-			return 1;
+	if (header_len >= (3*sizeof(uint8_t))) {
+		if (header->cmd_code == 0x4b && header->subsys_id == 0x12) {
+			switch (header->subsys_cmd_code) {
+			case 0x60: /* Extended Event Mask Config */
+			case 0x61: /* Extended Msg Mask Config */
+			case 0x62: /* Extended Log Mask Config */
+			case 0x20C: /* Set current Preset ID */
+			case 0x20D: /* Get current Preset ID */
+			case 0x218: /* HDLC Disabled Command */
+				DIAG_LOG(DIAG_DEBUG_DCI,
+					"diag: command not supported %d %d %d\n",
+					header->cmd_code, header->subsys_id,
+					header->subsys_cmd_code);
+				return 1;
+			}
 		}
 	}
 
@@ -1800,22 +1815,26 @@
 
 static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
 				     unsigned char *req_buf, int req_len,
-				     int tag)
+				     int tag, int pkt_header_len)
 {
-	uint8_t cmd_code, subsys_id, i, goto_download = 0;
+	uint8_t cmd_code = 0, subsys_id = 0, i, goto_download = 0;
 	uint8_t header_len = sizeof(struct diag_dci_pkt_header_t);
-	uint16_t ss_cmd_code;
+	uint16_t ss_cmd_code = 0;
 	uint32_t write_len = 0;
 	unsigned char *dest_buf = driver->apps_dci_buf;
 	unsigned char *payload_ptr = driver->apps_dci_buf + header_len;
 	struct diag_dci_pkt_header_t dci_header;
 
-	if (!pkt_header || !req_buf || req_len <= 0 || tag < 0)
+	if (!pkt_header || !req_buf || req_len <= 0 || tag < 0 ||
+		pkt_header_len <= 0)
 		return -EIO;
 
-	cmd_code = pkt_header->cmd_code;
-	subsys_id = pkt_header->subsys_id;
-	ss_cmd_code = pkt_header->subsys_cmd_code;
+	if (pkt_header_len >= (sizeof(uint8_t)))
+		cmd_code = pkt_header->cmd_code;
+	if (pkt_header_len >= (2 * sizeof(uint8_t)))
+		subsys_id = pkt_header->subsys_id;
+	if (pkt_header_len >= (3 * sizeof(uint8_t)))
+		ss_cmd_code = pkt_header->subsys_cmd_code;
 
 	if (cmd_code == DIAG_CMD_DOWNLOAD) {
 		*payload_ptr = DIAG_CMD_DOWNLOAD;
@@ -1935,7 +1954,7 @@
 static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
 {
 	int ret = DIAG_DCI_TABLE_ERR;
-	int common_cmd = 0;
+	int common_cmd = 0, header_len = 0;
 	struct diag_pkt_header_t *header = NULL;
 	unsigned char *temp = buf;
 	unsigned char *req_buf = NULL;
@@ -1951,8 +1970,7 @@
 	if (!buf)
 		return -EIO;
 
-	if (len < (sizeof(struct dci_pkt_req_t) +
-		sizeof(struct diag_pkt_header_t)) ||
+	if (len < sizeof(struct dci_pkt_req_t) ||
 		len > DCI_REQ_BUF_SIZE) {
 		pr_err("diag: dci: Invalid length %d len in %s", len, __func__);
 		return -EIO;
@@ -1963,13 +1981,6 @@
 	read_len += sizeof(struct dci_pkt_req_t);
 	req_len -= sizeof(struct dci_pkt_req_t);
 	req_buf = temp; /* Start of the Request */
-	header = (struct diag_pkt_header_t *)temp;
-	read_len += sizeof(struct diag_pkt_header_t);
-	if (read_len >= DCI_REQ_BUF_SIZE) {
-		pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__,
-		       read_len);
-		return -EIO;
-	}
 
 	mutex_lock(&driver->dci_mutex);
 	dci_entry = diag_dci_get_client_entry(req_hdr.client_id);
@@ -1980,11 +1991,40 @@
 		return DIAG_DCI_NO_REG;
 	}
 
+	header = (void *)temp;
+	header_len = len - sizeof(struct dci_pkt_req_t);
+	if (header_len <= 0) {
+		mutex_unlock(&driver->dci_mutex);
+		return -EIO;
+	}
+	if (header_len >= sizeof(uint8_t)) {
+		header->cmd_code = (uint16_t)(*(uint8_t *)temp);
+		read_len += sizeof(uint8_t);
+	}
+	if (header_len >= (2 * sizeof(uint8_t))) {
+		temp += sizeof(uint8_t);
+		header->subsys_id = (uint16_t)(*(uint8_t *)temp);
+		read_len += sizeof(uint8_t);
+	}
+	if (header_len == (3 * sizeof(uint8_t))) {
+		temp += sizeof(uint8_t);
+		header->subsys_cmd_code = (uint16_t)(*(uint8_t *)temp);
+		read_len += sizeof(uint8_t);
+	} else if (header_len >=
+		(2 * sizeof(uint8_t)) + sizeof(uint16_t)) {
+		temp += sizeof(uint8_t);
+		header->subsys_cmd_code = (uint16_t)(*(uint16_t *)temp);
+		read_len += sizeof(uint16_t);
+	}
+	if (read_len > DCI_REQ_BUF_SIZE) {
+		pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__,
+		       read_len);
+		mutex_unlock(&driver->dci_mutex);
+		return -EIO;
+	}
+
 	/* Check if the command is allowed on DCI */
-	if (diag_dci_filter_commands(header)) {
-		pr_debug("diag: command not supported %d %d %d",
-			 header->cmd_code, header->subsys_id,
-			 header->subsys_cmd_code);
+	if (diag_dci_filter_commands(header, header_len)) {
 		mutex_unlock(&driver->dci_mutex);
 		return DIAG_DCI_SEND_DATA_FAIL;
 	}
@@ -2038,14 +2078,23 @@
 
 	/* Check if it is a dedicated Apps command */
 	ret = diag_dci_process_apps_pkt(header, req_buf, req_len,
-					req_entry->tag);
+					req_entry->tag, header_len);
 	if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0)
 		return ret;
 
-	reg_entry.cmd_code = header->cmd_code;
-	reg_entry.subsys_id = header->subsys_id;
-	reg_entry.cmd_code_hi = header->subsys_cmd_code;
-	reg_entry.cmd_code_lo = header->subsys_cmd_code;
+	reg_entry.cmd_code = 0;
+	reg_entry.subsys_id = 0;
+	reg_entry.cmd_code_hi = 0;
+	reg_entry.cmd_code_lo = 0;
+
+	if (header_len >= (sizeof(uint8_t)))
+		reg_entry.cmd_code = header->cmd_code;
+	if (header_len >= (2 * sizeof(uint8_t)))
+		reg_entry.subsys_id = header->subsys_id;
+	if (header_len >= (3 * sizeof(uint8_t))) {
+		reg_entry.cmd_code_hi = header->subsys_cmd_code;
+		reg_entry.cmd_code_lo = header->subsys_cmd_code;
+	}
 
 	mutex_lock(&driver->cmd_reg_mutex);
 	temp_entry = diag_cmd_search(&reg_entry, ALL_PROC);
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c6ec271..c67f073 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1195,7 +1195,7 @@
 	int rsp_header_len = sizeof(struct diag_log_config_rsp_t);
 	uint32_t mask_size = 0;
 	struct diag_log_mask_t *log_item = NULL;
-	struct diag_log_config_req_t *req;
+	struct diag_log_config_get_req_t *req;
 	struct diag_log_config_rsp_t rsp;
 	struct diag_mask_info *mask_info = NULL;
 	struct diag_md_session_t *info = NULL;
@@ -1205,7 +1205,7 @@
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
-		src_len < sizeof(struct diag_log_config_req_t)) {
+		src_len < sizeof(struct diag_log_config_get_req_t)) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
@@ -1224,7 +1224,7 @@
 		return 0;
 	}
 
-	req = (struct diag_log_config_req_t *)src_buf;
+	req = (struct diag_log_config_get_req_t *)src_buf;
 	read_len += req_header_len;
 
 	rsp.cmd_code = DIAG_CMD_LOG_CONFIG;
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index a736ff2..5c76825 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -40,6 +40,13 @@
 	uint32_t *ptr;
 };
 
+struct diag_log_config_get_req_t {
+	uint8_t cmd_code;
+	uint8_t padding[3];
+	uint32_t sub_cmd;
+	uint32_t equip_id;
+} __packed;
+
 struct diag_log_config_req_t {
 	uint8_t cmd_code;
 	uint8_t padding[3];
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 91cf857..863be43 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -334,7 +334,7 @@
 config MSM_TIMER_LEAP
 	bool "ARCH TIMER counter rollover"
 	default n
-	depends on ARM_ARCH_TIMER && ARM64
+	depends on ARM_ARCH_TIMER
 	help
 	  This option enables a check for least significant 32 bits of
 	  counter rollover. On every counter read if least significant
diff --git a/drivers/input/sensors/smi130/smi130_acc.c b/drivers/input/sensors/smi130/smi130_acc.c
index c36c31d..a63e08e 100644
--- a/drivers/input/sensors/smi130/smi130_acc.c
+++ b/drivers/input/sensors/smi130/smi130_acc.c
@@ -1604,6 +1604,7 @@
 	bool read_acc_boot_sample;
 	int acc_bufsample_cnt;
 	bool acc_buffer_smi130_samples;
+	bool acc_enable;
 	struct kmem_cache *smi_acc_cachepool;
 	struct smi_acc_sample *smi130_acc_samplist[SMI_ACC_MAXSAMPLE];
 	int max_buffer_time;
@@ -4073,12 +4074,25 @@
 	else
 		return 0;
 }
+static void smi130_check_acc_enable_flag(struct smi130_acc_data *client_data,
+		unsigned long data)
+{
+	if (data == SMI_ACC2X2_MODE_NORMAL)
+		client_data->acc_enable = true;
+	else
+		client_data->acc_enable = false;
+}
 #else
 static inline int smi130_check_acc_early_buff_enable_flag(
 		struct smi130_acc_data *client_data)
 {
 	return 0;
 }
+static void smi130_check_acc_enable_flag(struct smi130_acc_data *client_data,
+		unsigned long data)
+{
+
+}
 #endif
 
 static ssize_t smi130_acc_enable_int_store(struct device *dev,
@@ -5481,13 +5495,17 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);
 
-	error = smi130_check_acc_early_buff_enable_flag(smi130_acc);
-	if (error)
-		return count;
 
 	error = kstrtoul(buf, 10, &data);
 	if (error)
 		return error;
+
+	smi130_check_acc_enable_flag(smi130_acc, data);
+
+	error = smi130_check_acc_early_buff_enable_flag(smi130_acc);
+	if (error)
+		return count;
+
 	if (smi130_acc_set_mode(smi130_acc->smi130_acc_client,
 		(unsigned char) data, SMI_ACC_ENABLED_BSX) < 0)
 			return -EINVAL;
@@ -6915,6 +6933,9 @@
 		PINFO("End of ACC buffering %d\n",
 				client_data->acc_bufsample_cnt);
 		client_data->acc_buffer_smi130_samples = false;
+		if (client_data->acc_enable == false)
+			smi130_acc_set_mode(client_data->smi130_acc_client,
+					SMI_ACC2X2_MODE_SUSPEND, 1);
 	}
 }
 #else
@@ -6982,6 +7003,7 @@
 	}
 
 	client_data->acc_buffer_smi130_samples = true;
+	client_data->acc_enable = false;
 
 	smi130_acc_set_mode(client, SMI_ACC2X2_MODE_NORMAL, 1);
 	smi130_acc_set_bandwidth(client, SMI_ACC2X2_BW_62_50HZ);
diff --git a/drivers/input/sensors/smi130/smi130_gyro_driver.c b/drivers/input/sensors/smi130/smi130_gyro_driver.c
index 552d39c..fd9e87d 100644
--- a/drivers/input/sensors/smi130/smi130_gyro_driver.c
+++ b/drivers/input/sensors/smi130/smi130_gyro_driver.c
@@ -295,6 +295,7 @@
 	bool read_gyro_boot_sample;
 	int gyro_bufsample_cnt;
 	bool gyro_buffer_smi130_samples;
+	bool gyro_enable;
 	struct kmem_cache *smi_gyro_cachepool;
 	struct smi_gyro_sample *smi130_gyro_samplist[SMI_GYRO_MAXSAMPLE];
 	int max_buffer_time;
@@ -860,12 +861,24 @@
 	else
 		return 0;
 }
+static void smi130_check_gyro_enable_flag(
+		struct smi_gyro_client_data *client_data, unsigned long data)
+{
+	if (data == SMI130_GYRO_MODE_NORMAL)
+		client_data->gyro_enable = true;
+	else
+		client_data->gyro_enable = false;
+}
 #else
 static inline int smi130_check_gyro_early_buff_enable_flag(
 		struct smi_gyro_client_data *client_data)
 {
 	return 0;
 }
+static void smi130_check_gyro_enable_flag(
+		struct smi_gyro_client_data *client_data, unsigned long data)
+{
+}
 #endif
 
 static ssize_t smi_gyro_show_op_mode(struct device *dev,
@@ -895,13 +908,17 @@
 
 	long op_mode;
 
-	err = smi130_check_gyro_early_buff_enable_flag(client_data);
-	if (err)
-		return count;
 
 	err = kstrtoul(buf, 10, &op_mode);
 	if (err)
 		return err;
+
+	smi130_check_gyro_enable_flag(client_data, op_mode);
+
+	err = smi130_check_gyro_early_buff_enable_flag(client_data);
+	if (err)
+		return count;
+
 	mutex_lock(&client_data->mutex_op_mode);
 
 	err = SMI_GYRO_CALL_API(set_mode)(op_mode);
@@ -1742,6 +1759,10 @@
 		PINFO("End of GYRO buffering %d",
 				client_data->gyro_bufsample_cnt);
 		client_data->gyro_buffer_smi130_samples = false;
+		if (client_data->gyro_enable == false) {
+			smi130_gyro_set_mode(SMI130_GYRO_MODE_SUSPEND);
+			smi130_gyro_delay(5);
+		}
 	}
 }
 #else
@@ -1810,6 +1831,7 @@
 	}
 
 	client_data->gyro_buffer_smi130_samples = true;
+	client_data->gyro_enable = false;
 
 	smi130_gyro_set_mode(SMI130_GYRO_MODE_NORMAL);
 	smi130_gyro_delay(5);
diff --git a/drivers/input/touchscreen/cyttsp5/cyttsp5_core.c b/drivers/input/touchscreen/cyttsp5/cyttsp5_core.c
index 64cc510..44bb9ba 100644
--- a/drivers/input/touchscreen/cyttsp5/cyttsp5_core.c
+++ b/drivers/input/touchscreen/cyttsp5/cyttsp5_core.c
@@ -306,8 +306,12 @@
 
 	for (i = 0; i < cd->num_hid_reports; i++) {
 		report = cd->hid_reports[i];
-		for (j = 0; j < report->num_fields; j++)
+		if (!report)
+			continue;
+		for (j = 0; j < report->num_fields; j++) {
 			kfree(report->fields[j]);
+			report->fields[j] = NULL;
+		}
 		kfree(report);
 		cd->hid_reports[i] = NULL;
 	}
@@ -3698,7 +3702,7 @@
 	rc = cyttsp5_hid_output_exit_easywake_state_(cd,
 			cd->easy_wakeup_gesture, &status);
 	if (rc || status == 0) {
-		dev_err(cd->dev, "%s: failed, rc=%d, status=%d\n",
+		dev_dbg(cd->dev, "%s: failed, rc=%d, status=%d\n",
 			__func__, rc, status);
 		return -EBUSY;
 	}
@@ -4395,7 +4399,8 @@
 	if (!IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture)) {
 
 		#ifdef CY_GES_WAKEUP
-		return cyttsp5_core_wake_device_from_easy_wakeup_(cd);
+		if (!cyttsp5_core_wake_device_from_easy_wakeup_(cd))
+			return 0;
 		#endif
 	}
 
@@ -4633,7 +4638,7 @@
 
 	rc = cyttsp5_check_and_deassert_int(cd);
 
-	if (reset || retry != CY_CORE_STARTUP_RETRY_COUNT) {
+	if (rc || retry != CY_CORE_STARTUP_RETRY_COUNT) {
 		/* reset hardware */
 		rc = cyttsp5_reset_and_wait(cd);
 		if (rc < 0) {
@@ -4773,12 +4778,11 @@
 	/* attention startup */
 	call_atten_cb(cd, CY_ATTEN_STARTUP, 0);
 
+	cyttsp5_start_wd_timer(cd);
 exit:
 	if (!rc)
 		cd->startup_retry_count = 0;
 
-	cyttsp5_start_wd_timer(cd);
-
 	if (!detected)
 		rc = -ENODEV;
 
@@ -4806,6 +4810,10 @@
 
 	rc = cyttsp5_startup_(cd, reset);
 
+	/* Wake the waiters for end of startup */
+	if (!rc)
+		wake_up(&cd->wait_q);
+
 	if (release_exclusive(cd, cd->dev) < 0)
 		/* Don't return fail code, mode is already changed. */
 		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
@@ -4818,9 +4826,6 @@
 	cd->startup_state = STARTUP_NONE;
 	mutex_unlock(&cd->system_lock);
 
-	/* Wake the waiters for end of startup */
-	wake_up(&cd->wait_q);
-
 	return rc;
 }
 
@@ -5759,6 +5764,8 @@
 
 struct cyttsp5_core_commands *cyttsp5_get_commands(void)
 {
+	if (!is_cyttsp5_probe_success)
+		return NULL;
 	return &_cyttsp5_core_commands;
 }
 EXPORT_SYMBOL_GPL(cyttsp5_get_commands);
@@ -6436,12 +6443,12 @@
 	cyttsp5_btn_release(dev);
 error_startup_mt:
 	cyttsp5_mt_release(dev);
+	cyttsp5_free_si_ptrs(cd);
 error_startup:
 	pm_runtime_disable(dev);
 	device_init_wakeup(dev, 0);
 	cancel_work_sync(&cd->startup_work);
 	cyttsp5_stop_wd_timer(cd);
-	cyttsp5_free_si_ptrs(cd);
 	remove_sysfs_interfaces(dev);
 error_attr_create:
 	free_irq(cd->irq, cd);
@@ -6453,7 +6460,7 @@
 	cyttsp5_del_core(dev);
 	dev_set_drvdata(dev, NULL);
 error_power:
-	kfree(cd);
+	cyttsp5_power_init(cd, false);
 error_alloc_data:
 error_no_pdata:
 	dev_err(dev, "%s failed.\n", __func__);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 2695c54..8d454cb 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -2164,6 +2164,7 @@
 	}
 
 	CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", ctx->ctx_index);
+	ctx->dual_ife_irq_mismatch_cnt = 0;
 	/* Start IFE root node: do nothing */
 	CAM_DBG(CAM_ISP, "Exit...(success)");
 	return 0;
@@ -2419,6 +2420,7 @@
 	memset(ctx->base, 0, sizeof(ctx->base));
 
 	/* release cdm handle */
+	ctx->dual_ife_irq_mismatch_cnt = 0;
 	cam_cdm_release(ctx->cdm_handle);
 
 	/* clean context */
@@ -3004,6 +3006,36 @@
 	}
 }
 
+static void cam_ife_mgr_ctx_irq_dump(struct cam_ife_hw_mgr_ctx *ctx)
+{
+	struct cam_ife_hw_mgr_res        *hw_mgr_res;
+	struct cam_hw_intf               *hw_intf;
+	struct cam_isp_hw_get_cmd_update  cmd_update;
+	int i = 0;
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT)
+			continue;
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+			switch (hw_mgr_res->hw_res[i]->res_id) {
+			case CAM_ISP_HW_VFE_IN_CAMIF:
+				hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+				cmd_update.res = hw_mgr_res->hw_res[i];
+				cmd_update.cmd_type =
+					CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP;
+				hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
+					&cmd_update, sizeof(cmd_update));
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
 static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 {
 	int rc = 0;
@@ -3654,11 +3686,26 @@
 		(event_cnt[core_idx1] &&
 		(event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) {
 
+		if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt > 10) {
+			rc = -1;
+			return rc;
+		}
+
 		CAM_ERR_RATE_LIMIT(CAM_ISP,
-			"One of the VFE cound not generate hw event %d",
+			"One of the VFE could not generate hw event %d",
 			hw_event_type);
-		rc = -1;
-		return rc;
+		if (event_cnt[core_idx0] >= 2) {
+			event_cnt[core_idx0]--;
+			ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++;
+		}
+		if (event_cnt[core_idx1] >= 2) {
+			event_cnt[core_idx1]--;
+			ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++;
+		}
+
+		if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt == 1)
+			cam_ife_mgr_ctx_irq_dump(ife_hw_mgr_ctx);
+		rc = 0;
 	}
 
 	CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d",
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index 9bfa34f..3a910b4 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -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
@@ -97,35 +97,38 @@
 /**
  * struct cam_vfe_hw_mgr_ctx - IFE HW manager Context object
  *
- * @list:                   used by the ctx list.
- * @common:                 common acquired context data
- * @ctx_index:              acquired context id.
- * @hw_mgr:                 IFE hw mgr which owns this context
- * @ctx_in_use:             flag to tell whether context is active
- * @res_list_ife_in:        Starting resource(TPG,PHY0, PHY1...) Can only be
- *                          one.
- * @res_list_csid:          CSID resource list
- * @res_list_ife_src:       IFE input resource list
- * @res_list_ife_out:       IFE output resoruces array
- * @free_res_list:          Free resources list for the branch node
- * @res_pool:               memory storage for the free resource list
- * @irq_status0_mask:       irq_status0_mask for the context
- * @irq_status1_mask:       irq_status1_mask for the context
- * @base                    device base index array contain the all IFE HW
- *                          instance associated with this context.
- * @num_base                number of valid base data in the base array
- * @cdm_handle              cdm hw acquire handle
- * @cdm_ops                 cdm util operation pointer for building
- *                          cdm commands
- * @cdm_cmd                 cdm base and length request pointer
- * @sof_cnt                 sof count value per core, used for dual VFE
- * @epoch_cnt               epoch count value per core, used for dual VFE
- * @eof_cnt                 eof count value per core, used for dual VFE
- * @overflow_pending        flat to specify the overflow is pending for the
- *                          context
- * @is_rdi_only_context     flag to specify the context has only rdi resource
- * @config_done_complete    indicator for configuration complete
- * @init_done               indicate whether init hw is done
+ * @list:                       used by the ctx list.
+ * @common:                     common acquired context data
+ * @ctx_index:                  acquired context id.
+ * @hw_mgr:                     IFE hw mgr which owns this context
+ * @ctx_in_use:                 flag to tell whether context is active
+ * @res_list_ife_in:            Starting resource(TPG,PHY0, PHY1...) Can only be
+ *                              one.
+ * @res_list_csid:              CSID resource list
+ * @res_list_ife_src:           IFE input resource list
+ * @res_list_ife_out:           IFE output resoruces array
+ * @free_res_list:              Free resources list for the branch node
+ * @res_pool:                   memory storage for the free resource list
+ * @irq_status0_mask:           irq_status0_mask for the context
+ * @irq_status1_mask:           irq_status1_mask for the context
+ * @base                        device base index array contain the all IFE HW
+ *                              instance associated with this context.
+ * @num_base                    number of valid base data in the base array
+ * @cdm_handle                  cdm hw acquire handle
+ * @cdm_ops                     cdm util operation pointer for building
+ *                              cdm commands
+ * @cdm_cmd                     cdm base and length request pointer
+ * @sof_cnt                     sof count value per core, used for dual VFE
+ * @epoch_cnt                   epoch count value per core, used for dual VFE
+ * @eof_cnt                     eof count value per core, used for dual VFE
+ * @overflow_pending            flag to specify the overflow is pending for the
+ *                              context
+ * @is_rdi_only_context         flag to specify the context has only rdi
+ *                              resource
+ * @config_done_complete        indicator for configuration complete
+ * @init_done                   indicate whether init hw is done
+ * @dual_ife_irq_mismatch_cnt   irq mismatch count value per core, used for
+ *                              dual VFE
  */
 struct cam_ife_hw_mgr_ctx {
 	struct list_head                list;
@@ -160,6 +163,7 @@
 	uint32_t                        is_rdi_only_context;
 	struct completion               config_done_complete;
 	bool                            init_done;
+	uint32_t                        dual_ife_irq_mismatch_cnt;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index 54aa4c2..2b814ac 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -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
@@ -97,6 +97,7 @@
 	CAM_ISP_HW_CMD_GET_REG_DUMP,
 	CAM_ISP_HW_CMD_SOF_IRQ_DEBUG,
 	CAM_ISP_HW_CMD_SET_CAMIF_DEBUG,
+	CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
 	CAM_ISP_HW_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index f6becfb..d8af627 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.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
@@ -696,6 +696,7 @@
 	case CAM_ISP_HW_CMD_CLOCK_UPDATE:
 	case CAM_ISP_HW_CMD_BW_UPDATE:
 	case CAM_ISP_HW_CMD_BW_CONTROL:
+	case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index fc257ec..528eb6d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.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
@@ -378,6 +378,40 @@
 	return rc;
 }
 
+static int cam_vfe_camif_irq_reg_dump(
+	struct cam_isp_resource_node *camif_res)
+{
+	struct cam_vfe_mux_camif_data *camif_priv;
+	struct cam_vfe_soc_private *soc_private;
+	int rc = 0;
+
+	if (!camif_res) {
+		CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) ||
+		(camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
+		CAM_ERR(CAM_ISP, "Error! Invalid state\n");
+		return 0;
+	}
+
+	camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
+	soc_private = camif_priv->soc_info->soc_private;
+
+	CAM_INFO(CAM_ISP,
+		"Core Id =%d Mask reg: offset 0x%x val 0x%x offset 0x%x val 0x%x",
+		camif_priv->hw_intf->hw_idx,
+		0x5c, cam_io_r_mb(camif_priv->mem_base + 0x5c),
+		0x60, cam_io_r_mb(camif_priv->mem_base + 0x60));
+	CAM_INFO(CAM_ISP,
+		"Core Id =%d Status reg: offset 0x%x val 0x%x offset 0x%x val 0x%x",
+		camif_priv->hw_intf->hw_idx,
+		0x6c, cam_io_r_mb(camif_priv->mem_base + 0x6c),
+		0x70, cam_io_r_mb(camif_priv->mem_base + 0x70));
+	return rc;
+}
+
 static int cam_vfe_camif_resource_stop(
 	struct cam_isp_resource_node        *camif_res)
 {
@@ -465,6 +499,9 @@
 			(struct cam_vfe_mux_camif_data *)rsrc_node->res_priv;
 		camif_priv->camif_debug = *((uint32_t *)cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP:
+		rc = cam_vfe_camif_irq_reg_dump(rsrc_node);
+		break;
 	default:
 		CAM_ERR(CAM_ISP,
 			"unsupported process command:%d", cmd_type);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index 47a0438..7ec11e8 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.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
@@ -379,6 +379,19 @@
 	return -EINVAL;
 }
 
+static int cam_vfe_get_irq_register_dump(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_isp_hw_get_cmd_update  *cmd_update = cmd_args;
+
+	if (cmd_update->res->process_cmd)
+		cmd_update->res->process_cmd(cmd_update->res,
+		CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, cmd_args, arg_size);
+
+	return 0;
+}
+
 int cam_vfe_top_get_hw_caps(void *device_priv,
 	void *get_hw_cap_args, uint32_t arg_size)
 {
@@ -657,6 +670,10 @@
 	case CAM_ISP_HW_CMD_BW_CONTROL:
 		rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP:
+		rc = cam_vfe_get_irq_register_dump(top_priv,
+				cmd_args, arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index 9628c81..dce58f3 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -899,7 +899,7 @@
 		lrme_core->state = CAM_LRME_CORE_STATE_INIT;
 	} else {
 		CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state);
-		return -EINVAL;
+		rc = -EINVAL;
 	}
 
 unlock:
@@ -951,7 +951,8 @@
 
 	if (lrme_core->req_submit != NULL) {
 		CAM_ERR(CAM_LRME, "req_submit is not NULL");
-		return -EBUSY;
+		rc = -EBUSY;
+		goto error;
 	}
 
 	rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
index 8c2853b..927e00b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.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
@@ -51,6 +51,10 @@
 		CAM_DBG(CAM_CCI, "master %d", master);
 		if (master < MASTER_MAX && master >= 0) {
 			mutex_lock(&cci_dev->cci_master_info[master].mutex);
+			mutex_lock(&cci_dev->
+				cci_master_info[master].mutex_q[QUEUE_0]);
+			mutex_lock(&cci_dev->
+				cci_master_info[master].mutex_q[QUEUE_1]);
 			flush_workqueue(cci_dev->write_wq[master]);
 			/* Re-initialize the completion */
 			reinit_completion(
@@ -73,6 +77,10 @@
 				CCI_TIMEOUT);
 			if (rc <= 0)
 				CAM_ERR(CAM_CCI, "wait failed %d", rc);
+			mutex_unlock(&cci_dev->
+				cci_master_info[master].mutex_q[QUEUE_1]);
+			mutex_unlock(&cci_dev->
+				cci_master_info[master].mutex_q[QUEUE_0]);
 			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
 		}
 		return 0;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 6797ba4..20976af 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -974,7 +974,7 @@
 			&eeprom_cap,
 			sizeof(struct cam_eeprom_query_cap_t))) {
 			CAM_ERR(CAM_EEPROM, "Failed Copy to User");
-			return -EFAULT;
+			rc = -EFAULT;
 			goto release_mutex;
 		}
 		CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info);
diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
index 7600cbb..11bad5d 100644
--- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
@@ -462,6 +462,17 @@
 				ctx->dev_name, ctx->ctx_id, req->request_id);
 
 		for (j = 0; j < req->num_in_map_entries; j++) {
+			rc = cam_sync_check_valid(
+				req->in_map_entries[j].sync_id);
+			if (rc) {
+				CAM_ERR(CAM_CTXT,
+					"invalid in map sync object %d",
+					req->in_map_entries[j].sync_id);
+				goto put_ref;
+			}
+		}
+
+		for (j = 0; j < req->num_in_map_entries; j++) {
 			cam_context_getref(ctx);
 			rc = cam_sync_register_callback(
 					cam_context_sync_callback,
@@ -482,7 +493,9 @@
 						ctx->dev_name, ctx->ctx_id,
 						req->request_id);
 
-				goto put_ctx_ref;
+				cam_context_putref(ctx);
+				goto put_ref;
+
 			}
 			CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d",
 				req->in_map_entries[j].sync_id, rc);
@@ -491,9 +504,6 @@
 	}
 
 	return rc;
-put_ctx_ref:
-	for (--j; j >= 0; j--)
-		cam_context_putref(ctx);
 put_ref:
 	for (--i; i >= 0; i--) {
 		rc = cam_sync_put_obj_ref(req->out_map_entries[i].sync_id);
diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
index 4276b35..a68e207 100644
--- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
@@ -980,8 +980,10 @@
 		return -EINVAL;
 	}
 
-	if (!CAM_CPAS_CLIENT_VALID(client_indx))
+	if (!CAM_CPAS_CLIENT_VALID(client_indx)) {
+		CAM_ERR(CAM_CPAS, "Client index invalid %d", client_indx);
 		return -EINVAL;
+	}
 
 	mutex_lock(&cpas_hw->hw_mutex);
 	mutex_lock(&cpas_core->client_mutex[client_indx]);
@@ -1099,8 +1101,10 @@
 	cmd_hw_stop = (struct cam_cpas_hw_cmd_stop *)stop_args;
 	client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_stop->client_handle);
 
-	if (!CAM_CPAS_CLIENT_VALID(client_indx))
+	if (!CAM_CPAS_CLIENT_VALID(client_indx)) {
+		CAM_ERR(CAM_CPAS, "Client index invalid %d", client_indx);
 		return -EINVAL;
+	}
 
 	mutex_lock(&cpas_hw->hw_mutex);
 	mutex_lock(&cpas_core->client_mutex[client_indx]);
@@ -1162,14 +1166,20 @@
 	ahb_vote.vote.level = CAM_SUSPEND_VOTE;
 	rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client,
 		&ahb_vote, NULL);
-	if (rc)
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "ahb vote failed for %s rc %d",
+			cpas_client->data.identifier, rc);
 		goto done;
+	}
 
 	axi_vote.uncompressed_bw = 0;
 	axi_vote.compressed_bw = 0;
 	axi_vote.compressed_bw_ab = 0;
 	rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
 		cpas_client, &axi_vote);
+	if (rc)
+		CAM_ERR(CAM_CPAS, "axi vote failed for %s rc %d",
+			cpas_client->data.identifier, rc);
 
 done:
 	mutex_unlock(&cpas_core->client_mutex[client_indx]);
@@ -1234,6 +1244,13 @@
 	rc = cam_common_util_get_string_index(soc_private->client_name,
 		soc_private->num_clients, client_name, &client_indx);
 
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "No match found for client %s",
+			client_name);
+		mutex_unlock(&cpas_hw->hw_mutex);
+		return rc;
+	}
+
 	mutex_lock(&cpas_core->client_mutex[client_indx]);
 
 	if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) ||
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c
index e13d7f2..4dbc8f1 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c
@@ -464,7 +464,11 @@
 
 	case CAM_ICP_A5_CMD_CPAS_STOP:
 		if (core_info->cpas_start) {
-			cam_cpas_stop(core_info->cpas_handle);
+			rc = cam_cpas_stop(core_info->cpas_handle);
+			if (rc) {
+				CAM_ERR(CAM_ICP, "cpas stop failed %d", rc);
+				return rc;
+			}
 			core_info->cpas_start = false;
 		}
 		break;
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
index c94276c..f522f71 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -347,7 +347,11 @@
 
 	case CAM_ICP_BPS_CMD_CPAS_STOP:
 		if (core_info->cpas_start) {
-			cam_cpas_stop(core_info->cpas_handle);
+			rc = cam_cpas_stop(core_info->cpas_handle);
+			if (rc) {
+				CAM_ERR(CAM_ICP, "cpas stop failed %d", rc);
+				return rc;
+			}
 			core_info->cpas_start = false;
 		}
 		break;
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index cfc474a..03b93ac 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -4077,8 +4077,13 @@
 
 	for (i = 0; i < packet->num_io_configs; i++) {
 		for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) {
-			if (!io_cfg[i].mem_handle[j])
+			if (!io_cfg[i].mem_handle[j]) {
+				CAM_ERR(CAM_ICP,
+					"Mem Handle %d is NULL for %d io config",
+					j, i);
 				break;
+			}
+
 
 			if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) ==
 				GET_FD_FROM_HANDLE(pf_buf_info)) {
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
index ae3d134..ae58b34 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -342,7 +342,11 @@
 
 	case CAM_ICP_IPE_CMD_CPAS_STOP:
 		if (core_info->cpas_start) {
-			cam_cpas_stop(core_info->cpas_handle);
+			rc = cam_cpas_stop(core_info->cpas_handle);
+			if (rc) {
+				CAM_ERR(CAM_ICP, "CPAS stop failed %d", rc);
+				return rc;
+			}
 			core_info->cpas_start = false;
 		}
 		break;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
index 57375c4..94d531d 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
@@ -38,18 +38,26 @@
 
 static void __cam_isp_ctx_update_state_monitor_array(
 	struct cam_isp_context *ctx_isp,
-	enum cam_isp_state_change_trigger trigger_type,
-	uint32_t req_id)
+	enum cam_isp_hw_event_type    hw_event,
+	enum cam_isp_ctx_activated_substate  curr_state,
+	enum cam_isp_ctx_activated_substate  next_state)
 {
 	int iterator = 0;
 
 	iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head);
 	ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state =
-		ctx_isp->substate_activated;
-	ctx_isp->cam_isp_ctx_state_monitor[iterator].trigger =
-		trigger_type;
-	ctx_isp->cam_isp_ctx_state_monitor[iterator].req_id =
-		req_id;
+		curr_state;
+	ctx_isp->cam_isp_ctx_state_monitor[iterator].next_state =
+		next_state;
+	ctx_isp->cam_isp_ctx_state_monitor[iterator].hw_event =
+		hw_event;
+	ctx_isp->cam_isp_ctx_state_monitor[iterator].last_reported_id =
+		ctx_isp->req_info.reported_req_id;
+	ctx_isp->cam_isp_ctx_state_monitor[iterator].last_applied_req_id =
+		ctx_isp->req_info.last_applied_req_id;
+	ctx_isp->cam_isp_ctx_state_monitor[iterator].frame_id =
+		ctx_isp->frame_id;
+
 	ctx_isp->cam_isp_ctx_state_monitor[iterator].evt_time_stamp =
 		jiffies_to_msecs(jiffies);
 }
@@ -79,17 +87,17 @@
 	uint32_t evt_id)
 {
 	switch (evt_id) {
-	case CAM_ISP_STATE_CHANGE_TRIGGER_ERROR:
+	case CAM_ISP_HW_EVENT_ERROR:
 		return "ERROR";
-	case CAM_ISP_STATE_CHANGE_TRIGGER_SOF:
+	case CAM_ISP_HW_EVENT_SOF:
 		return "SOF";
-	case CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE:
+	case CAM_ISP_HW_EVENT_REG_UPDATE:
 		return "REG_UPDATE";
-	case CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH:
+	case CAM_ISP_HW_EVENT_EPOCH:
 		return "EPOCH";
-	case CAM_ISP_STATE_CHANGE_TRIGGER_EOF:
+	case CAM_ISP_HW_EVENT_EOF:
 		return "EOF";
-	case CAM_ISP_STATE_CHANGE_TRIGGER_DONE:
+	case CAM_ISP_HW_EVENT_DONE:
 		return "DONE";
 	default:
 		return "CAM_ISP_EVENT_INVALID";
@@ -97,29 +105,58 @@
 }
 
 static void __cam_isp_ctx_dump_state_monitor_array(
-	struct cam_isp_context *ctx_isp)
+	struct cam_isp_context *ctx_isp, bool log_rate_limit)
 {
 	int i = 0;
 	uint64_t state_head = 0;
 	uint64_t index;
+	struct cam_isp_context_state_monitor   *ctx_monitor;
 
 	state_head = atomic64_read(&ctx_isp->state_monitor_head);
-	CAM_ERR_RATE_LIMIT(CAM_ISP,
-		"Dumping state information for preceding requests");
+
+	ctx_monitor = ctx_isp->cam_isp_ctx_state_monitor;
+
+	if (log_rate_limit)
+		CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20,
+			"Dumping state information for preceding requests");
+	else
+		CAM_INFO(CAM_ISP,
+			"Dumping state information for preceding requests");
 
 	for (i = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES - 1; i >= 0;
 		i--) {
 		index = (((state_head - i) +
 			CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) %
 			CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES);
-		CAM_ERR_RATE_LIMIT(CAM_ISP,
-		"time[0x%llx] req_id[%u] state[%s] evt_type[%s]",
-		ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp,
-		ctx_isp->cam_isp_ctx_state_monitor[index].req_id,
-		__cam_isp_ctx_substate_val_to_type(
-		ctx_isp->cam_isp_ctx_state_monitor[index].curr_state),
-		__cam_isp_hw_evt_val_to_type(
-		ctx_isp->cam_isp_ctx_state_monitor[index].trigger));
+
+		if (log_rate_limit) {
+			CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20,
+			"time[%lld] last reported req_id[%lld] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]",
+			ctx_monitor[index].evt_time_stamp,
+			ctx_monitor[index].last_reported_id,
+			ctx_monitor[index].frame_id,
+			ctx_monitor[index].last_applied_req_id,
+			__cam_isp_ctx_substate_val_to_type(
+			ctx_monitor[index].curr_state),
+			__cam_isp_ctx_substate_val_to_type(
+			ctx_monitor[index].next_state),
+			__cam_isp_hw_evt_val_to_type(
+			ctx_monitor[index].hw_event));
+
+		} else {
+			CAM_INFO(CAM_ISP,
+			"time[%lld] last reported req_id[%lld] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]",
+			ctx_monitor[index].evt_time_stamp,
+			ctx_monitor[index].last_reported_id,
+			ctx_monitor[index].frame_id,
+			ctx_monitor[index].last_applied_req_id,
+			__cam_isp_ctx_substate_val_to_type(
+			ctx_monitor[index].curr_state),
+			__cam_isp_ctx_substate_val_to_type(
+			ctx_monitor[index].next_state),
+			__cam_isp_hw_evt_val_to_type(
+			ctx_monitor[index].hw_event));
+		}
 	}
 }
 
@@ -403,7 +440,7 @@
 	struct cam_context *ctx = ctx_isp->base;
 
 	if (list_empty(&ctx->active_req_list)) {
-		CAM_DBG(CAM_ISP, "Buf done with no active request!");
+		CAM_WARN(CAM_ISP, "Buf done with no active request!");
 		goto end;
 	}
 
@@ -508,6 +545,10 @@
 		CAM_DBG(CAM_REQ,
 			"Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u",
 			 req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
+		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
+			CAM_ISP_HW_EVENT_DONE,
+			ctx_isp->substate_activated,
+			ctx_isp->substate_activated);
 	} else {
 		list_del_init(&req->list);
 		list_add_tail(&req->list, &ctx->free_req_list);
@@ -515,32 +556,39 @@
 		CAM_DBG(CAM_REQ,
 			"Move active request %lld to free list(cnt = %d) [all fences done], ctx %u",
 			 req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
+		ctx_isp->req_info.last_bufdone_req_id = req->request_id;
+		ctx_isp->req_info.last_bufdone_time_stamp =
+			jiffies_to_msecs(jiffies);
+		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
+			CAM_ISP_HW_EVENT_DONE,
+			ctx_isp->substate_activated,
+			ctx_isp->substate_activated);
 	}
 
 end:
-	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-		CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
-		ctx_isp->base->req_list->request_id);
 	return rc;
 }
 
 static void __cam_isp_ctx_send_sof_boot_timestamp(
 	struct cam_isp_context *ctx_isp, uint64_t request_id,
-	uint32_t sof_event_status)
+	uint32_t sof_event_status, uint64_t delta_ts)
 {
 	struct cam_req_mgr_message   req_msg;
 
 	req_msg.session_hdl = ctx_isp->base->session_hdl;
 	req_msg.u.frame_msg.frame_id = ctx_isp->frame_id;
 	req_msg.u.frame_msg.request_id = request_id;
-	req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp;
 	req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl;
 	req_msg.u.frame_msg.sof_status = sof_event_status;
 
+	req_msg.u.frame_msg.timestamp = ctx_isp->prev_boot_timestamp + delta_ts;
+
 	CAM_DBG(CAM_ISP,
-		"request id:%lld frame number:%lld boot time stamp:0x%llx",
-		 request_id, ctx_isp->frame_id,
-		 ctx_isp->boot_timestamp);
+		"req id:%lld frame num:%lld bt_ts:0x%llx pre_bt_ts:0x%llx diff:0x%llx",
+		request_id, ctx_isp->frame_id,
+		ctx_isp->boot_timestamp, ctx_isp->prev_boot_timestamp,
+		delta_ts);
+
 
 	if (cam_req_mgr_notify_message(&req_msg,
 		V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS,
@@ -548,6 +596,8 @@
 		CAM_ERR(CAM_ISP,
 			"Error in notifying the boot time for req id:%lld",
 			request_id);
+
+	ctx_isp->prev_boot_timestamp = req_msg.u.frame_msg.timestamp;
 }
 
 
@@ -556,6 +606,7 @@
 	uint32_t sof_event_status)
 {
 	struct cam_req_mgr_message   req_msg;
+	uint64_t delta_ts;
 
 	req_msg.session_hdl = ctx_isp->base->session_hdl;
 	req_msg.u.frame_msg.frame_id = ctx_isp->frame_id;
@@ -565,9 +616,9 @@
 	req_msg.u.frame_msg.sof_status = sof_event_status;
 
 	CAM_DBG(CAM_ISP,
-		"request id:%lld frame number:%lld SOF time stamp:0x%llx",
+		"request id:%lld frame number:%lld SOF time stamp:0x%llx, Prev SOF time:0x%llx",
 		 request_id, ctx_isp->frame_id,
-		ctx_isp->sof_timestamp_val);
+		ctx_isp->sof_timestamp_val, ctx_isp->prev_sof_timestamp_val);
 	CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status);
 
 	if (cam_req_mgr_notify_message(&req_msg,
@@ -575,9 +626,17 @@
 		CAM_ERR(CAM_ISP,
 			"Error in notifying the sof time for req id:%lld",
 			request_id);
+	delta_ts = ctx_isp->sof_timestamp_val -
+			ctx_isp->prev_sof_timestamp_val;
 
 	__cam_isp_ctx_send_sof_boot_timestamp(ctx_isp,
-		request_id, sof_event_status);
+		request_id, sof_event_status,
+		(ctx_isp->prev_sof_timestamp_val == 0) ?
+			ctx_isp->boot_timestamp :
+			delta_ts);
+
+	ctx_isp->prev_sof_timestamp_val =
+			ctx_isp->sof_timestamp_val;
 
 }
 
@@ -658,6 +717,7 @@
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
 			CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld ctx %u",
@@ -665,9 +725,12 @@
 		}
 
 		list_for_each_entry(req, &ctx->active_req_list, list) {
-			if (req->request_id > ctx_isp->reported_req_id) {
+			if (req->request_id >
+				ctx_isp->req_info.reported_req_id) {
 				request_id = req->request_id;
-				ctx_isp->reported_req_id = request_id;
+				ctx_isp->req_info.reported_req_id = request_id;
+				ctx_isp->req_info.last_reported_id_time_stamp =
+					jiffies_to_msecs(jiffies);
 				break;
 			}
 		}
@@ -675,6 +738,17 @@
 		if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE)
 			request_id = 0;
 
+		if (request_id && ctx_isp->req_info.reported_req_id &&
+			((request_id - ctx_isp->req_info.reported_req_id) >
+			1)){
+			CAM_INFO(CAM_ISP,
+				"ctx:%d curr req id: %lld last reported id:%lld",
+				ctx->ctx_id, request_id,
+				ctx_isp->req_info.reported_req_id);
+
+			__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
+		}
+
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 	} else {
@@ -742,8 +816,7 @@
 	ctx_isp->frame_id++;
 	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
 	ctx_isp->boot_timestamp = sof_event_data->boot_time;
-	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-		CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id);
+
 	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u",
 		ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id);
 
@@ -778,11 +851,7 @@
 			CAM_ERR(CAM_ISP,
 				"receive rup in unexpected state");
 	}
-	if (req != NULL) {
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
-			req->request_id);
-	}
+
 end:
 	return rc;
 }
@@ -800,7 +869,8 @@
 		 * If no wait req in epoch, this is an error case.
 		 * The recovery is to go back to sof state
 		 */
-		CAM_ERR(CAM_ISP, "No wait request");
+		CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id);
+		__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
 
 		/* Send SOF event as empty frame*/
@@ -815,7 +885,9 @@
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	req_isp->bubble_detected = true;
 
-	CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report);
+	CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
+	__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
 		ctx->ctx_crm_intf->notify_err) {
 		struct cam_req_mgr_error_notify notify;
@@ -842,9 +914,11 @@
 	list_del_init(&req->list);
 	list_add_tail(&req->list, &ctx->active_req_list);
 
-	if (req->request_id > ctx_isp->reported_req_id) {
+	if (req->request_id > ctx_isp->req_info.reported_req_id) {
 		request_id = req->request_id;
-		ctx_isp->reported_req_id = request_id;
+		ctx_isp->req_info.reported_req_id = request_id;
+		ctx_isp->req_info.last_reported_id_time_stamp =
+			jiffies_to_msecs(jiffies);
 	}
 	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 		CAM_REQ_MGR_SOF_EVENT_ERROR);
@@ -853,15 +927,7 @@
 	CAM_DBG(CAM_ISP, "next substate %d",
 		ctx_isp->substate_activated);
 end:
-	if (request_id == 0) {
-		req = list_last_entry(&ctx->active_req_list,
-			struct cam_ctx_request, list);
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id);
-	} else {
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, request_id);
-	}
+
 	return 0;
 }
 
@@ -884,7 +950,6 @@
 	int rc = 0;
 	struct cam_context                    *ctx = ctx_isp->base;
 	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
-	struct cam_ctx_request *req;
 
 	if (!evt_data) {
 		CAM_ERR(CAM_ISP, "in valid sof event data");
@@ -900,12 +965,6 @@
 	else
 		CAM_DBG(CAM_ISP, "Still need to wait for the buf done");
 
-	req = list_last_entry(&ctx->active_req_list,
-		struct cam_ctx_request, list);
-	if (req)
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_SOF,
-			ctx->req_list->request_id);
 	CAM_DBG(CAM_ISP, "next substate %d",
 		ctx_isp->substate_activated);
 
@@ -952,7 +1011,8 @@
 		 * If no pending req in epoch, this is an error case.
 		 * Just go back to the bubble state.
 		 */
-		CAM_ERR(CAM_ISP, "No pending request.");
+		CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id);
+		__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 
@@ -964,6 +1024,9 @@
 		list);
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	req_isp->bubble_detected = true;
+	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
+	__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
 		ctx->ctx_crm_intf->notify_err) {
@@ -992,9 +1055,11 @@
 	list_add_tail(&req->list, &ctx->active_req_list);
 
 	if (!req_isp->bubble_report) {
-		if (req->request_id > ctx_isp->reported_req_id) {
+		if (req->request_id > ctx_isp->req_info.reported_req_id) {
 			request_id = req->request_id;
-			ctx_isp->reported_req_id = request_id;
+			ctx_isp->req_info.reported_req_id = request_id;
+			ctx_isp->req_info.last_reported_id_time_stamp =
+			jiffies_to_msecs(jiffies);
 			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_ERROR);
 		} else
@@ -1007,11 +1072,7 @@
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
 	CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
 end:
-	req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request,
-		list);
-	if (req)
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id);
+
 	return 0;
 }
 
@@ -1023,9 +1084,7 @@
 		(struct cam_isp_hw_done_event_data *) evt_data;
 
 	rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1);
-	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-		CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
-		ctx_isp->base->req_list->request_id);
+
 	return rc;
 }
 
@@ -1083,9 +1142,6 @@
 	if (error_event_data->enable_reg_dump)
 		cam_isp_ctx_dump_req(req_isp);
 
-	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-		CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id);
-
 	list_for_each_entry_safe(req, req_temp,
 		&ctx->active_req_list, list) {
 		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
@@ -1176,14 +1232,15 @@
 end:
 	do {
 		if (list_empty(&ctx->pending_req_list)) {
-			error_request_id = ctx_isp->last_applied_req_id + 1;
+			error_request_id =
+				ctx_isp->req_info.last_applied_req_id + 1;
 			req_isp = NULL;
 			break;
 		}
 		req = list_first_entry(&ctx->pending_req_list,
 			struct cam_ctx_request, list);
 		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
-		error_request_id = ctx_isp->last_applied_req_id;
+		error_request_id = ctx_isp->req_info.last_applied_req_id;
 
 		if (req_isp->bubble_report) {
 			req_to_report = req;
@@ -1201,7 +1258,8 @@
 		list_del_init(&req->list);
 		list_add_tail(&req->list, &ctx->free_req_list);
 
-	} while (req->request_id < ctx_isp->last_applied_req_id);
+	} while (req->request_id <
+		ctx_isp->req_info.last_applied_req_id);
 
 	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) {
 		notify.link_hdl = ctx->link_hdl;
@@ -1240,8 +1298,8 @@
 					V4L_EVENT_CAM_REQ_MGR_EVENT))
 				CAM_ERR(CAM_ISP,
 					"Error in notifying the error time for req id:%lld ctx %u",
-						ctx_isp->last_applied_req_id,
-						ctx->ctx_id);
+					ctx_isp->req_info.last_applied_req_id,
+					ctx->ctx_id);
 		}
 		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR;
 	} else {
@@ -1278,8 +1336,7 @@
 	ctx_isp->frame_id++;
 	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
 	ctx_isp->boot_timestamp = sof_event_data->boot_time;
-	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-		CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id);
+
 	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
 		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
 
@@ -1293,6 +1350,7 @@
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
 			CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld",
@@ -1300,9 +1358,12 @@
 		}
 
 		list_for_each_entry(req, &ctx->active_req_list, list) {
-			if (req->request_id > ctx_isp->reported_req_id) {
+			if (req->request_id >
+				ctx_isp->req_info.reported_req_id) {
 				request_id = req->request_id;
-				ctx_isp->reported_req_id = request_id;
+				ctx_isp->req_info.reported_req_id = request_id;
+				ctx_isp->req_info.last_reported_id_time_stamp =
+					jiffies_to_msecs(jiffies);
 				break;
 			}
 		}
@@ -1343,8 +1404,10 @@
 			CAM_DBG(CAM_ISP, "No request, move to SOF");
 			ctx_isp->substate_activated =
 				CAM_ISP_CTX_ACTIVATED_SOF;
-			if (ctx_isp->reported_req_id < curr_req_id) {
-				ctx_isp->reported_req_id = curr_req_id;
+			if (ctx_isp->req_info.reported_req_id < curr_req_id) {
+				ctx_isp->req_info.reported_req_id = curr_req_id;
+				ctx_isp->req_info.last_reported_id_time_stamp =
+					jiffies_to_msecs(jiffies);
 				__cam_isp_ctx_send_sof_timestamp(ctx_isp,
 					curr_req_id,
 					CAM_REQ_MGR_SOF_EVENT_SUCCESS);
@@ -1402,11 +1465,7 @@
 			CAM_ERR(CAM_ISP,
 				"receive rup in unexpected state");
 	}
-	if (req != NULL) {
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
-			req->request_id);
-	}
+
 end:
 	return rc;
 }
@@ -1451,9 +1510,12 @@
 	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger &&
 		ctx_isp->active_req_cnt <= 2) {
 		list_for_each_entry(req, &ctx->active_req_list, list) {
-			if (req->request_id > ctx_isp->reported_req_id) {
+			if (req->request_id >
+				ctx_isp->req_info.reported_req_id) {
 				request_id = req->request_id;
-				ctx_isp->reported_req_id = request_id;
+				ctx_isp->req_info.reported_req_id = request_id;
+				ctx_isp->req_info.last_reported_id_time_stamp =
+					jiffies_to_msecs(jiffies);
 				break;
 			}
 		}
@@ -1466,6 +1528,7 @@
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
 			CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld",
@@ -1478,11 +1541,7 @@
 
 	CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
 end:
-	if (req != NULL && !rc) {
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH,
-			req->request_id);
-	}
+
 	return rc;
 }
 
@@ -1729,19 +1788,19 @@
 	} else {
 		spin_lock_bh(&ctx->lock);
 		ctx_isp->substate_activated = next_state;
-		ctx_isp->last_applied_req_id = apply->request_id;
+		ctx_isp->req_info.last_applied_req_id =
+			apply->request_id;
+		ctx_isp->req_info.last_applied_time_stamp =
+			jiffies_to_msecs(jiffies);
 		list_del_init(&req->list);
 		list_add_tail(&req->list, &ctx->wait_req_list);
 		CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld",
-			next_state, ctx_isp->last_applied_req_id);
+			next_state,
+			ctx_isp->req_info.last_applied_req_id);
 		spin_unlock_bh(&ctx->lock);
 	}
 end:
-	if (ctx_isp != NULL) {
-		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
-			CAM_ISP_STATE_CHANGE_TRIGGER_SOF,
-			ctx->req_list->request_id);
-	}
+
 	return rc;
 }
 
@@ -1875,6 +1934,23 @@
 	CAM_DBG(CAM_ISP, "try to flush pending list");
 	spin_lock_bh(&ctx->lock);
 	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
+
+	if (!list_empty(&ctx->active_req_list)) {
+		CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20,
+			"ctx:%d last applied id:%lld, reported req id:%lld, buf done id:%lld",
+			ctx->ctx_id,
+			ctx_isp->req_info.last_applied_req_id,
+			ctx_isp->req_info.reported_req_id,
+			ctx_isp->req_info.last_bufdone_req_id);
+		CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20,
+			"current time:%u last apply time:%lld, reported req time:%lld, buf done time:%lld",
+			jiffies_to_msecs(jiffies),
+			ctx_isp->req_info.last_applied_time_stamp,
+			ctx_isp->req_info.last_reported_id_time_stamp,
+			ctx_isp->req_info.last_bufdone_time_stamp);
+
+		__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
+	}
 	spin_unlock_bh(&ctx->lock);
 
 	atomic_set(&ctx_isp->process_bubble, 0);
@@ -2041,6 +2117,7 @@
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
 		CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld",
@@ -2133,8 +2210,10 @@
 		list);
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	req_isp->bubble_detected = true;
+	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
+	__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 
-	CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report);
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
 		ctx->ctx_crm_intf->notify_err) {
 		struct cam_req_mgr_error_notify notify;
@@ -2161,9 +2240,11 @@
 			req->request_id, ctx_isp->active_req_cnt);
 
 	if (!req_isp->bubble_report) {
-		if (req->request_id > ctx_isp->reported_req_id) {
+		if (req->request_id > ctx_isp->req_info.reported_req_id) {
 			request_id = req->request_id;
-			ctx_isp->reported_req_id = request_id;
+			ctx_isp->req_info.reported_req_id = request_id;
+			ctx_isp->req_info.last_reported_id_time_stamp =
+				jiffies_to_msecs(jiffies);
 			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_ERROR);
 		} else
@@ -2228,6 +2309,7 @@
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
 		CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld",
@@ -2298,6 +2380,7 @@
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
 		CAM_DBG(CAM_ISP, "Notify CRM  SOF frame %lld",
@@ -2305,8 +2388,11 @@
 	} else {
 		CAM_ERR(CAM_ISP, "Can not notify SOF to CRM");
 	}
-	if (request_id)
-		ctx_isp->reported_req_id = request_id;
+	if (request_id) {
+		ctx_isp->req_info.reported_req_id = request_id;
+		ctx_isp->req_info.last_reported_id_time_stamp =
+			jiffies_to_msecs(jiffies);
+	}
 
 	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 		CAM_REQ_MGR_SOF_EVENT_SUCCESS);
@@ -2481,9 +2567,14 @@
 	ctx->last_flush_req = 0;
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
-	ctx_isp->reported_req_id = 0;
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
+	ctx_isp->req_info.reported_req_id = 0;
+	ctx_isp->req_info.last_applied_req_id = 0;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
+	ctx_isp->req_info.last_applied_time_stamp = 0;
+	ctx_isp->req_info.last_bufdone_time_stamp = 0;
+	ctx_isp->req_info.last_reported_id_time_stamp = 0;
 
 	/*
 	 * Ideally, we should never have any active request here.
@@ -2538,11 +2629,16 @@
 	ctx->last_flush_req = 0;
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
-	ctx_isp->reported_req_id = 0;
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
 	ctx_isp->rdi_only_context = false;
 	ctx_isp->split_acquire = false;
+	ctx_isp->req_info.reported_req_id = 0;
+	ctx_isp->req_info.last_applied_req_id = 0;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
+	ctx_isp->req_info.last_applied_time_stamp = 0;
+	ctx_isp->req_info.last_bufdone_time_stamp = 0;
+	ctx_isp->req_info.last_reported_id_time_stamp = 0;
 
 	/*
 	 * Ideally, we should never have any active request here.
@@ -3169,7 +3265,7 @@
 	atomic_set(&ctx_isp->process_bubble, 0);
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
-	ctx_isp->reported_req_id = 0;
+	ctx_isp->req_info.reported_req_id = 0;
 	ctx_isp->substate_activated = ctx_isp->rdi_only_context ?
 		CAM_ISP_CTX_ACTIVATED_APPLIED :
 		(req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH :
@@ -3301,7 +3397,15 @@
 	}
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
-	ctx_isp->reported_req_id = 0;
+	ctx_isp->req_info.reported_req_id = 0;
+	ctx_isp->req_info.last_applied_req_id = 0;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
+	ctx_isp->req_info.last_applied_time_stamp = 0;
+	ctx_isp->req_info.last_bufdone_time_stamp = 0;
+	ctx_isp->req_info.last_reported_id_time_stamp = 0;
+	ctx_isp->prev_sof_timestamp_val = 0;
+	ctx_isp->prev_boot_timestamp = 0;
+
 	atomic_set(&ctx_isp->process_bubble, 0);
 
 	CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u",
@@ -3478,8 +3582,9 @@
 		rc = ctx_ops->crm_ops.apply_req(ctx, apply);
 	} else {
 		CAM_ERR_RATE_LIMIT(CAM_ISP,
-			"No handle function in activated substate %d",
-			ctx_isp->substate_activated);
+			"Ctx:%d No handle function in activated substate %d",
+			ctx->ctx_id, ctx_isp->substate_activated);
+		__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 		rc = -EFAULT;
 	}
 
@@ -3500,22 +3605,27 @@
 	struct cam_context *ctx = (struct cam_context *)context;
 	struct cam_isp_context *ctx_isp =
 		(struct cam_isp_context *)ctx->ctx_priv;
+	enum cam_isp_ctx_activated_substate  curr_state;
 
 	spin_lock(&ctx->lock);
 
 	trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id,
 		__cam_isp_ctx_get_event_ts(evt_id, evt_data));
 
+	curr_state = ctx_isp->substate_activated;
 	CAM_DBG(CAM_ISP, "Enter: State %d, Substate %d, evt id %d",
 		 ctx->state, ctx_isp->substate_activated, evt_id);
 	irq_ops = &ctx_isp->substate_machine_irq[ctx_isp->substate_activated];
 	if (irq_ops->irq_ops[evt_id]) {
 		rc = irq_ops->irq_ops[evt_id](ctx_isp, evt_data);
 	} else {
-		CAM_DBG(CAM_ISP, "No handle function for substate %d",
-			ctx_isp->substate_activated);
-		__cam_isp_ctx_dump_state_monitor_array(ctx_isp);
+		CAM_INFO(CAM_ISP, "Ctx:%d No handle function for substate %d",
+			ctx->ctx_id, ctx_isp->substate_activated);
+		__cam_isp_ctx_dump_state_monitor_array(ctx_isp, true);
 	}
+	if (evt_id != CAM_ISP_HW_EVENT_DONE)
+		__cam_isp_ctx_update_state_monitor_array(ctx_isp, evt_id,
+			curr_state, ctx_isp->substate_activated);
 
 	CAM_DBG(CAM_ISP, "Exit: State %d Substate %d",
 		 ctx->state, ctx_isp->substate_activated);
@@ -3677,7 +3787,13 @@
 	ctx->base = ctx_base;
 	ctx->frame_id = 0;
 	ctx->active_req_cnt = 0;
-	ctx->reported_req_id = 0;
+	ctx->req_info.reported_req_id = 0;
+	ctx->req_info.last_applied_req_id = 0;
+	ctx->req_info.last_bufdone_req_id = 0;
+	ctx->req_info.last_applied_time_stamp = 0;
+	ctx->req_info.last_bufdone_time_stamp = 0;
+	ctx->req_info.last_reported_id_time_stamp = 0;
+
 	ctx->hw_ctx = NULL;
 	ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
 	ctx->substate_machine = cam_isp_ctx_activated_state_machine;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h
index 4954f20..a4f4e5a 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h
@@ -62,20 +62,6 @@
 };
 
 /**
- * enum cam_isp_state_change_trigger - Different types of ISP events
- *
- */
-enum cam_isp_state_change_trigger {
-	CAM_ISP_STATE_CHANGE_TRIGGER_ERROR,
-	CAM_ISP_STATE_CHANGE_TRIGGER_SOF,
-	CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
-	CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH,
-	CAM_ISP_STATE_CHANGE_TRIGGER_EOF,
-	CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
-	CAM_ISP_STATE_CHANGE_TRIGGER_MAX
-};
-
-/**
  * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks
  *
  * @irq_ops:               Array of handle function pointers.
@@ -125,20 +111,47 @@
  *                                        debug purposes
  *
  *@curr_state:          Current sub state that received req
- *@req_type:            Event type of incoming req
- *@req_id:              Request id
- *@evt_time_stamp       Current time stamp
+ *@next_state:          Next sub state that received req
+ *@hw_event:            Hw Event type of incoming req
+ *@last_reported_id:    Last_reported_id to userspace
+ *@last_applied_req_id  Last applied request id to hardware
+ *@frame_id:            Current Frame id
+ *@evt_time_stamp       Current time stamp of this event logged
  *
  */
 struct cam_isp_context_state_monitor {
 	enum cam_isp_ctx_activated_substate  curr_state;
-	enum cam_isp_state_change_trigger    trigger;
-	uint32_t                             req_id;
+	enum cam_isp_ctx_activated_substate  next_state;
+	enum cam_isp_hw_event_type           hw_event;
+	int64_t                              last_reported_id;
+	int64_t                              last_applied_req_id;
 	int64_t                              frame_id;
 	uint64_t                             evt_time_stamp;
 };
 
 /**
+ * struct cam_isp_context_req_id_info - ISP context request id
+ *                     information for last applied, reported and bufdone.
+ *
+ *@last_applied_req_id:   Last applied request id
+ *@last_bufdone_req_id:   Last bufdone request id
+ *@reported_req_id:       Last reported request id to userspace
+ *@last_applied_time_stamp: Last applied request time stamp information
+ *@last_bufdone_time_stamp  Last bufdone request time stamp information
+ *@last_reported_id_time_stamp: Last reported request time stamp information
+ *
+ */
+
+struct cam_isp_context_req_id_info {
+	int64_t                          last_applied_req_id;
+	int64_t                          last_bufdone_req_id;
+	int64_t                          reported_req_id;
+	int64_t                          last_applied_time_stamp;
+	int64_t                          last_bufdone_time_stamp;
+	int64_t                          last_reported_id_time_stamp;
+
+};
+/**
  * struct cam_isp_context   -  ISP context object
  *
  * @base:                      Common context object pointer
@@ -152,13 +165,15 @@
  * @req_isp:                   ISP private request object storage
  * @hw_ctx:                    HW object returned by the acquire device command
  * @sof_timestamp_val:         Captured time stamp value at sof hw event
+ * @prev_sof_timestamp_val     Holds last notified sof time stamp
  * @boot_timestamp:            Boot time stamp for a given req_id
+ * @prev_boot_timestamp        Holds last notified boot time stamp
  * @active_req_cnt:            Counter for the active request
- * @reported_req_id:           Last reported request id
  * @subscribe_event:           The irq event mask that CRM subscribes to, IFE
  *                             will invoke CRM cb at those event.
- * @last_applied_req_id:       Last applied request id
  * @state_monitor_head:        Write index to the state monitoring array
+ * @req_info                   Request id information about last applied,
+ *                             reported and buf done
  * @cam_isp_ctx_state_monitor: State monitoring array
  * @rdi_only_context:          Get context type information.
  *                             true, if context is rdi only context
@@ -181,14 +196,15 @@
 
 	void                            *hw_ctx;
 	uint64_t                         sof_timestamp_val;
+	uint64_t                         prev_sof_timestamp_val;
 	uint64_t                         boot_timestamp;
+	uint64_t                         prev_boot_timestamp;
 	int32_t                          active_req_cnt;
-	int64_t                          reported_req_id;
 	uint32_t                         subscribe_event;
-	int64_t                          last_applied_req_id;
 	atomic64_t                       state_monitor_head;
 	struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[
 		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES];
+	struct cam_isp_context_req_id_info   req_info;
 	bool                             rdi_only_context;
 	bool                             hw_acquired;
 	bool                             init_received;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index fe3d2f1..cfc902a 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -2637,7 +2637,7 @@
 
 	/* Stop the master CSID path first */
 	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-		master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+		master_base_idx, csid_halt_type);
 
 	/* stop rest of the CSID paths  */
 	for (i = 0; i < ctx->num_base; i++) {
@@ -2647,7 +2647,7 @@
 			ctx->base[i].idx, i, master_base_idx);
 
 		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+			ctx->base[i].idx, csid_halt_type);
 	}
 
 	CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx);
@@ -4097,8 +4097,12 @@
 
 	for (i = 0; i < packet->num_io_configs; i++) {
 		for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) {
-			if (!io_cfg[i].mem_handle[j])
+			if (!io_cfg[i].mem_handle[j]) {
+				CAM_ERR(CAM_ISP,
+					"Mem Handle %d is NULL for %d io config",
+					j, i);
 				break;
+			}
 
 			if (pf_buf_info &&
 				GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) ==
@@ -4261,45 +4265,44 @@
 	struct cam_hw_intf                   *hw_intf;
 	struct cam_csid_get_time_stamp_args   csid_get_time;
 
-	list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
+	hw_mgr_res = list_first_entry(&ife_ctx->res_list_ife_csid,
+		struct cam_ife_hw_mgr_res, list);
+	for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+		if (!hw_mgr_res->hw_res[i])
+			continue;
 
+		/*
+		 * Get the SOF time stamp from left resource only.
+		 * Left resource is master for dual vfe case and
+		 * Rdi only context case left resource only hold
+		 * the RDI resource
+		 */
+
+		hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+		if (hw_intf->hw_ops.process_cmd) {
 			/*
-			 * Get the SOF time stamp from left resource only.
-			 * Left resource is master for dual vfe case and
-			 * Rdi only context case left resource only hold
-			 * the RDI resource
+			 * Single VFE case, Get the time stamp from
+			 * available one csid hw in the context
+			 * Dual VFE case, get the time stamp from
+			 * master(left) would be sufficient
 			 */
 
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			if (hw_intf->hw_ops.process_cmd) {
-				/*
-				 * Single VFE case, Get the time stamp from
-				 * available one csid hw in the context
-				 * Dual VFE case, get the time stamp from
-				 * master(left) would be sufficient
-				 */
-
-				csid_get_time.node_res =
-					hw_mgr_res->hw_res[i];
-				rc = hw_intf->hw_ops.process_cmd(
-					hw_intf->hw_priv,
-					CAM_IFE_CSID_CMD_GET_TIME_STAMP,
-					&csid_get_time,
-					sizeof(
-					struct cam_csid_get_time_stamp_args));
-				if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) {
-					*time_stamp =
-						csid_get_time.time_stamp_val;
-					*boot_time_stamp =
-						csid_get_time.boot_timestamp;
-				}
+			csid_get_time.node_res =
+				hw_mgr_res->hw_res[i];
+			rc = hw_intf->hw_ops.process_cmd(
+				hw_intf->hw_priv,
+				CAM_IFE_CSID_CMD_GET_TIME_STAMP,
+				&csid_get_time,
+				sizeof(
+				struct cam_csid_get_time_stamp_args));
+			if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) {
+				*time_stamp =
+					csid_get_time.time_stamp_val;
+				*boot_time_stamp =
+					csid_get_time.boot_timestamp;
 			}
 		}
 	}
-
 	if (rc)
 		CAM_ERR(CAM_ISP, "Getting sof time stamp failed");
 
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index 0b3c387..21f67ba 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -467,6 +467,7 @@
 	int32_t                             hdl;
 	int                                 mmu_hdl;
 	bool                                mode, is_buf_secure;
+	uint64_t                            req_id;
 
 	io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *)
 			&prepare->packet->payload +
@@ -475,6 +476,7 @@
 	num_in_buf  = 0;
 	io_cfg_used_bytes = 0;
 	prepare->pf_data->packet = prepare->packet;
+	req_id = prepare->packet->header.request_id;
 
 	/* Max one hw entries required for each base */
 	if (prepare->num_hw_update_entries + 1 >=
@@ -489,7 +491,7 @@
 		CAM_DBG(CAM_ISP, "======= io config idx %d ============", i);
 		CAM_DBG(CAM_REQ,
 			"i %d req_id %llu resource_type:%d fence:%d direction %d",
-			i, prepare->packet->header.request_id,
+			i, req_id,
 			io_cfg[i].resource_type, io_cfg[i].fence,
 			io_cfg[i].direction);
 		CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format);
@@ -616,12 +618,37 @@
 					mmu_hdl, &io_addr[plane_id], &size);
 				if (rc) {
 					CAM_ERR(CAM_ISP,
-						"no io addr for plane%d",
-						plane_id);
+						"no io addr for plane%d Bufhdl:%d, Size =%d",
+						plane_id,
+						io_cfg[i].mem_handle[plane_id],
+						(int)size);
+					CAM_ERR(CAM_ISP,
+						"Port i %d Reqid %llu res_type:%d fence:%d dir %d",
+						i, req_id,
+						io_cfg[i].resource_type,
+						io_cfg[i].fence,
+						io_cfg[i].direction);
 					rc = -ENOMEM;
 					return rc;
 				}
 
+				if (j == 0) {
+					rc = cam_packet_validate_plane_size(
+							&io_cfg[i],
+							plane_id,
+							size);
+					if (rc) {
+						CAM_ERR(CAM_ISP,
+						"Invalid buffer size, port 0x%x plane %d req_id %llu format %d memh 0x%x",
+						io_cfg[i].resource_type,
+						plane_id,
+						req_id,
+						io_cfg[i].format,
+						io_cfg[i].mem_handle[plane_id]);
+						return -EINVAL;
+					}
+				}
+
 				/* need to update with offset */
 				io_addr[plane_id] +=
 						io_cfg[i].offsets[plane_id];
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 5610f6d..3431a64 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -467,6 +467,7 @@
 		CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d",
 			csid_hw->hw_intf->hw_idx, val);
 	csid_hw->error_irq_count = 0;
+	csid_hw->first_sof_ts = 0;
 
 	for (i = 0 ; i < CAM_IFE_PIX_PATH_RES_MAX; i++)
 		csid_hw->res_sof_cnt[i] = 0;
@@ -1167,6 +1168,7 @@
 
 	csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN;
 	csid_hw->error_irq_count = 0;
+	csid_hw->first_sof_ts = 0;
 
 	return rc;
 }
@@ -2454,9 +2456,16 @@
 		CAM_IFE_CSID_QTIMER_MUL_FACTOR,
 		CAM_IFE_CSID_QTIMER_DIV_FACTOR);
 
-	get_monotonic_boottime64(&ts);
-	time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) +
-		ts.tv_nsec);
+	if (!csid_hw->first_sof_ts) {
+		get_monotonic_boottime64(&ts);
+		time_stamp->boot_timestamp =
+			(uint64_t)((ts.tv_sec * 1000000000) +
+			ts.tv_nsec);
+		CAM_DBG(CAM_ISP, "timestamp:%lld",
+			time_stamp->boot_timestamp);
+		csid_hw->first_sof_ts = 1;
+	} else
+		time_stamp->boot_timestamp = 0;
 
 	return 0;
 }
@@ -3737,6 +3746,7 @@
 
 	ife_csid_hw->csid_debug = 0;
 	ife_csid_hw->error_irq_count = 0;
+	ife_csid_hw->first_sof_ts = 0;
 
 	return 0;
 err:
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index 600deb2..9b4d5c3 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -480,6 +480,7 @@
  * @init_frame_drop           Initial frame drop number
  * @res_sof_cnt               path resource sof count value. it used for initial
  *                            frame drop
+ * @first_sof_ts              flag to mark the first sof has been registered
  *
  */
 struct cam_ife_csid_hw {
@@ -511,6 +512,7 @@
 	uint32_t                         dual_usage;
 	uint32_t                         init_frame_drop;
 	uint32_t                         res_sof_cnt[CAM_IFE_PIX_PATH_RES_MAX];
+	uint32_t                         first_sof_ts;
 };
 
 int cam_ife_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index f7b42d5..1a3a7cb 100644
--- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -634,8 +634,13 @@
 
 	for (i = 0; i < packet->num_io_configs; i++) {
 		for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) {
-			if (!io_cfg[i].mem_handle[j])
+			if (!io_cfg[i].mem_handle[j]) {
+				CAM_ERR(CAM_JPEG,
+					"Mem Handle %d is NULL for %d io config",
+					j, i);
 				break;
+			}
+
 
 			if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) ==
 				GET_FD_FROM_HANDLE(pf_buf_info)) {
diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
index 52907cd..225f859 100644
--- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
@@ -91,6 +91,9 @@
 		CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc);
 		goto soc_failed;
 	}
+	spin_lock(&jpeg_enc_dev->hw_lock);
+	jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_UP;
+	spin_unlock(&jpeg_enc_dev->hw_lock);
 
 	mutex_unlock(&core_info->core_mutex);
 
@@ -140,6 +143,9 @@
 		return -EFAULT;
 	}
 
+	spin_lock(&jpeg_enc_dev->hw_lock);
+	jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	spin_unlock(&jpeg_enc_dev->hw_lock);
 	rc = cam_jpeg_enc_disable_soc_resources(soc_info);
 	if (rc)
 		CAM_ERR(CAM_JPEG, "soc disable failed %d", rc);
@@ -173,12 +179,19 @@
 	hw_info = core_info->jpeg_enc_hw_info;
 	mem_base = soc_info->reg_map[0].mem_base;
 
+	spin_lock(&jpeg_enc_dev->hw_lock);
+	if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_ERR(CAM_JPEG, "JPEG HW is in off state");
+		spin_unlock(&jpeg_enc_dev->hw_lock);
+		return -EINVAL;
+	}
 	irq_status = cam_io_r_mb(mem_base +
 		core_info->jpeg_enc_hw_info->reg_offset.int_status);
 
 	cam_io_w_mb(irq_status,
 		soc_info->reg_map[0].mem_base +
 		core_info->jpeg_enc_hw_info->reg_offset.int_clr);
+	spin_unlock(&jpeg_enc_dev->hw_lock);
 
 	CAM_DBG(CAM_JPEG, "irq_num %d  irq_status = %x , core_state %d",
 		irq_num, irq_status, core_info->core_state);
@@ -268,6 +281,12 @@
 
 	mutex_lock(&core_info->core_mutex);
 	spin_lock(&jpeg_enc_dev->hw_lock);
+	if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_ERR(CAM_JPEG, "JPEG HW is in off state");
+		spin_unlock(&jpeg_enc_dev->hw_lock);
+		mutex_unlock(&core_info->core_mutex);
+		return -EINVAL;
+	}
 	if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) {
 		CAM_ERR(CAM_JPEG, "alrady resetting");
 		spin_unlock(&jpeg_enc_dev->hw_lock);
@@ -319,10 +338,18 @@
 	hw_info = core_info->jpeg_enc_hw_info;
 	mem_base = soc_info->reg_map[0].mem_base;
 
-	if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) {
-		CAM_ERR(CAM_JPEG, "Error not ready");
+	spin_lock(&jpeg_enc_dev->hw_lock);
+	if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_ERR(CAM_JPEG, "JPEG HW is in off state");
+		spin_unlock(&jpeg_enc_dev->hw_lock);
 		return -EINVAL;
 	}
+	if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) {
+		CAM_ERR(CAM_JPEG, "Error not ready");
+		spin_unlock(&jpeg_enc_dev->hw_lock);
+		return -EINVAL;
+	}
+	spin_unlock(&jpeg_enc_dev->hw_lock);
 
 	cam_io_w_mb(hw_info->reg_val.hw_cmd_start,
 		mem_base + hw_info->reg_offset.hw_cmd);
@@ -352,6 +379,12 @@
 
 	mutex_lock(&core_info->core_mutex);
 	spin_lock(&jpeg_enc_dev->hw_lock);
+	if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_ERR(CAM_JPEG, "JPEG HW is in off state");
+		spin_unlock(&jpeg_enc_dev->hw_lock);
+		mutex_unlock(&core_info->core_mutex);
+		return -EINVAL;
+	}
 	if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) {
 		CAM_ERR(CAM_JPEG, "alrady stopping");
 		spin_unlock(&jpeg_enc_dev->hw_lock);
diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c
index c8e2a02..b2994d5 100644
--- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c
@@ -48,6 +48,9 @@
 	link->last_flush_id = 0;
 	link->initial_sync_req = -1;
 	link->in_msync_mode = false;
+	link->initial_skip = true;
+	link->sof_timestamp = 0;
+	link->prev_sof_timestamp = 0;
 }
 
 void cam_req_mgr_handle_core_shutdown(void)
@@ -610,6 +613,19 @@
 	traverse_data.open_req_cnt = link->open_req_cnt;
 
 	/*
+	 *  Some no-sync mode requests are processed after link config,
+	 *  then process the sync mode requests after no-sync mode requests
+	 *  are handled, the initial_skip should be false when processing
+	 *  the sync mode requests.
+	 */
+	if (link->initial_skip) {
+		CAM_DBG(CAM_CRM,
+			"Set initial_skip to false for link %x",
+			link->link_hdl);
+		link->initial_skip = false;
+	}
+
+	/*
 	 *  Traverse through all pd tables, if result is success,
 	 *  apply the settings
 	 */
@@ -894,9 +910,11 @@
 	struct cam_req_mgr_slot *slot)
 {
 	struct cam_req_mgr_core_link *sync_link = NULL;
-	int64_t req_id = 0;
+	struct cam_req_mgr_slot *sync_rd_slot = NULL;
+	int64_t req_id = 0, sync_req_id = 0;
 	int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0;
 	int32_t sync_num_slots = 0;
+	uint64_t sync_frame_duration = 0;
 	bool ready = true, sync_ready = true;
 
 	if (!link->sync_link) {
@@ -907,11 +925,65 @@
 	sync_link = link->sync_link;
 	req_id = slot->req_id;
 	sync_num_slots = sync_link->req.in_q->num_slots;
+	sync_rd_idx = sync_link->req.in_q->rd_idx;
+	sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx];
+	sync_req_id = sync_rd_slot->req_id;
 
 	CAM_DBG(CAM_REQ,
 		"link_hdl %x req %lld frame_skip_flag %d ",
 		link->link_hdl, req_id, link->sync_link_sof_skip);
 
+	if (sync_link->initial_skip) {
+		link->initial_skip = false;
+		__cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx);
+		CAM_DBG(CAM_CRM,
+			"sync link %x not streamed on",
+			sync_link->link_hdl);
+		return -EAGAIN;
+	}
+
+	if (sync_link->prev_sof_timestamp)
+		sync_frame_duration = sync_link->sof_timestamp
+			- sync_link->prev_sof_timestamp;
+	else
+		sync_frame_duration = DEFAULT_FRAME_DURATION;
+
+	CAM_DBG(CAM_CRM,
+		"sync link %x last frame duration is %d ns",
+		sync_link->link_hdl, sync_frame_duration);
+
+	if (link->initial_skip) {
+		link->initial_skip = false;
+
+		if (link->sof_timestamp > sync_link->sof_timestamp &&
+			sync_link->sof_timestamp > 0 &&
+			link->sof_timestamp - sync_link->sof_timestamp <
+			sync_frame_duration / 2) {
+			/*
+			 * If this frame sync with the previous frame of sync
+			 * link, then we need to skip this frame, since the
+			 * previous frame of sync link is also skipped.
+			 */
+			__cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx);
+			CAM_DBG(CAM_CRM,
+				"This frame sync with previous sync_link %x frame",
+				sync_link->link_hdl);
+			return -EAGAIN;
+		} else if (link->sof_timestamp <= sync_link->sof_timestamp) {
+			/*
+			 * Sometimes, link receives the SOF event is eariler
+			 * than sync link in IFE CSID side, but link's SOF
+			 * event is processed later than sync link's, then
+			 * we need to skip this SOF event since the sync
+			 * link's SOF event is also skipped.
+			 */
+			__cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx);
+			CAM_DBG(CAM_CRM,
+				"The previous frame of sync link is skipped");
+			return -EAGAIN;
+		}
+	}
+
 	if (sync_link->sync_link_sof_skip) {
 		CAM_DBG(CAM_REQ,
 			"No req applied on corresponding SOF on sync link: %x",
@@ -937,12 +1009,11 @@
 		sync_ready = false;
 	}
 
-	sync_rd_idx = sync_link->req.in_q->rd_idx;
 	if ((sync_link->req.in_q->slot[sync_slot_idx].status !=
 		CRM_SLOT_STATUS_REQ_APPLIED) &&
 		(((sync_slot_idx - sync_rd_idx + sync_num_slots) %
 		sync_num_slots) >= 1) &&
-		(sync_link->req.in_q->slot[sync_rd_idx].status !=
+		(sync_rd_slot->status !=
 		CRM_SLOT_STATUS_REQ_APPLIED)) {
 		CAM_DBG(CAM_CRM,
 			"Req: %lld [other link] not next req to be applied on link: %x",
@@ -975,7 +1046,15 @@
 		CAM_DBG(CAM_CRM,
 			"Req: %lld ready %d sync_ready %d, ignore sync link next SOF",
 			req_id, ready, sync_ready);
-		link->sync_link_sof_skip = true;
+
+		/*
+		 * Only skip the frames if current frame sync with
+		 * next frame of sync link.
+		 */
+		if (link->sof_timestamp - sync_link->sof_timestamp >
+			sync_frame_duration / 2)
+			link->sync_link_sof_skip = true;
+
 		return -EINVAL;
 	} else if (ready == false) {
 		CAM_DBG(CAM_CRM,
@@ -984,6 +1063,61 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * Do the self-correction when the frames are sync,
+	 * we consider that the frames are synced if the
+	 * difference of two SOF timestamp less than
+	 * (sync_frame_duration / 5).
+	 */
+	if ((link->sof_timestamp > sync_link->sof_timestamp) &&
+		(sync_link->sof_timestamp > 0) &&
+		(link->sof_timestamp - sync_link->sof_timestamp <
+		sync_frame_duration / 5) &&
+		(sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) {
+
+		/*
+		 * This means current frame should sync with next
+		 * frame of sync link, then the request id of in
+		 * rd slot of two links should be same.
+		 */
+		CAM_DBG(CAM_CRM,
+			"link %x req_id %lld, sync_link %x req_id %lld",
+			link->link_hdl, req_id,
+			sync_link->link_hdl, sync_req_id);
+
+		if (req_id > sync_req_id) {
+			CAM_DBG(CAM_CRM,
+				"link %x too quickly, skip this frame",
+				link->link_hdl);
+			return -EAGAIN;
+		} else if (req_id < sync_req_id) {
+			CAM_DBG(CAM_CRM,
+				"sync link %x too quickly, skip next frame of sync link",
+				sync_link->link_hdl);
+			link->sync_link_sof_skip = true;
+		}
+	} else if ((sync_link->sof_timestamp > 0) &&
+		(link->sof_timestamp < sync_link->sof_timestamp) &&
+		(sync_link->sof_timestamp - link->sof_timestamp <
+		sync_frame_duration / 5) &&
+		(sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) {
+
+		/*
+		 * There is a timing issue once enter this condition,
+		 * it means link receives the SOF event earlier than
+		 * sync link in IFE CSID side, but the process in CRM
+		 * is sync_link earlier than link, then previous SOF
+		 * event of sync link is skipped, so we also need to
+		 * skip this SOF event.
+		 */
+		if (req_id >= sync_req_id) {
+			CAM_DBG(CAM_CRM,
+				"Timing issue, the sof event of link %x is delayed",
+				link->link_hdl);
+			return -EAGAIN;
+		}
+	}
+
 	CAM_DBG(CAM_REQ,
 		"Req: %lld ready to apply on link: %x [validation successful]",
 		req_id, link->link_hdl);
@@ -1011,10 +1145,11 @@
  *
  */
 static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
-	uint32_t trigger)
+	struct cam_req_mgr_trigger_notify *trigger_data)
 {
 	int                                  rc = 0, idx, last_app_idx;
 	int                                  reset_step = 0;
+	uint32_t                             trigger = trigger_data->trigger;
 	struct cam_req_mgr_slot             *slot = NULL;
 	struct cam_req_mgr_req_queue        *in_q;
 	struct cam_req_mgr_core_session     *session;
@@ -1052,6 +1187,13 @@
 	}
 
 	if (trigger == CAM_TRIGGER_POINT_SOF) {
+		/*
+		 * Update the timestamp in session lock protection
+		 * to avoid timing issue.
+		 */
+		link->prev_sof_timestamp = link->sof_timestamp;
+		link->sof_timestamp = trigger_data->sof_timestamp_val;
+
 		if (link->trigger_mask) {
 			CAM_ERR_RATE_LIMIT(CAM_CRM,
 				"Applying for last EOF fails");
@@ -2141,7 +2283,7 @@
 		__cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots);
 	}
 
-	rc = __cam_req_mgr_process_req(link, trigger_data->trigger);
+	rc = __cam_req_mgr_process_req(link, trigger_data);
 
 release_lock:
 	mutex_unlock(&link->req.lock);
@@ -2372,6 +2514,7 @@
 	notify_trigger->link_hdl = trigger_data->link_hdl;
 	notify_trigger->dev_hdl = trigger_data->dev_hdl;
 	notify_trigger->trigger = trigger_data->trigger;
+	notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val;
 	task->process_cb = &cam_req_mgr_process_trigger;
 	rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0);
 
@@ -3125,8 +3268,6 @@
 
 	link1->is_master = false;
 	link2->is_master = false;
-	link1->initial_skip = false;
-	link2->initial_skip = false;
 
 	link1->in_msync_mode = false;
 	link2->in_msync_mode = false;
@@ -3137,6 +3278,16 @@
 		link1->sync_link = link2;
 		link2->sync_link = link1;
 		__cam_req_mgr_set_master_link(link1, link2);
+	} else {
+		/*
+		 * Reset below info after the mode is configured
+		 * to NO-SYNC mode since they may be overridden
+		 * if the sync config is invoked after SOF comes.
+		 */
+		link1->initial_skip = true;
+		link2->initial_skip = true;
+		link1->sof_timestamp = 0;
+		link2->sof_timestamp = 0;
 	}
 
 	cam_session->sync_mode = sync_info->sync_mode;
diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
index 05fe086..94f26de 100644
--- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
@@ -32,6 +32,9 @@
 
 #define MAX_SYNC_COUNT 65535
 
+/* Default frame rate is 30 */
+#define DEFAULT_FRAME_DURATION 33333333
+
 #define SYNC_LINK_SOF_CNT_MAX_LMT 1
 
 #define MAXIMUM_LINKS_PER_SESSION  4
@@ -321,7 +324,10 @@
  *                         master-slave sync
  * @in_msync_mode        : Flag to determine if a link is in master-slave mode
  * @initial_sync_req     : The initial req which is required to sync with the
- *                         other link
+ *                         other link, it means current hasn't receive any
+ *                         stream after streamon if it is true
+ * @sof_timestamp_value  : SOF timestamp value
+ * @prev_sof_timestamp   : Previous SOF timestamp value
  *
  */
 struct cam_req_mgr_core_link {
@@ -349,6 +355,8 @@
 	bool                                 initial_skip;
 	bool                                 in_msync_mode;
 	int64_t                              initial_sync_req;
+	uint64_t                             sof_timestamp;
+	uint64_t                             prev_sof_timestamp;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h
index 1d1df45..934bc76 100644
--- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h
+++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h
@@ -201,12 +201,14 @@
  * @frame_id : frame id for internal tracking
  * @trigger  : trigger point of this notification, CRM will send apply
  * only to the devices which subscribe to this point.
+ * @sof_timestamp_val: Captured time stamp value at sof hw event
  */
 struct cam_req_mgr_trigger_notify {
 	int32_t  link_hdl;
 	int32_t  dev_hdl;
 	int64_t  frame_id;
 	uint32_t trigger;
+	uint64_t sof_timestamp_val;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c
index 0181a4d..f66d86c 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c
@@ -410,7 +410,9 @@
 	cci_dev->cci_state = CCI_STATE_DISABLED;
 	cci_dev->cycles_per_us = 0;
 
-	cam_cpas_stop(cci_dev->cpas_handle);
+	rc = cam_cpas_stop(cci_dev->cpas_handle);
+	if (rc)
+		CAM_ERR(CAM_CCI, "cpas stop failed %d", rc);
 
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 8074ecd..b860559 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -551,7 +551,7 @@
 void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev)
 {
 	struct cam_hw_soc_info *soc_info;
-	int32_t i = 0;
+	int32_t i = 0, rc = 0;
 
 	if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT)
 		return;
@@ -574,7 +574,10 @@
 		cam_csiphy_reset(csiphy_dev);
 		cam_soc_util_disable_platform_resource(soc_info, true, true);
 
-		cam_cpas_stop(csiphy_dev->cpas_handle);
+		rc = cam_cpas_stop(csiphy_dev->cpas_handle);
+		if (rc)
+			CAM_ERR(CAM_CSIPHY, "cpas stop failed %d", rc);
+
 		csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE;
 	}
 
@@ -934,7 +937,10 @@
 			if (rc < 0) {
 				csiphy_dev->csiphy_info.secure_mode[offset] =
 					CAM_SECURE_MODE_NON_SECURE;
-				cam_cpas_stop(csiphy_dev->cpas_handle);
+				rc = cam_cpas_stop(csiphy_dev->cpas_handle);
+				if (rc < 0)
+					CAM_ERR(CAM_CSIPHY,
+						"de-voting CPAS: %d", rc);
 				goto release_mutex;
 			}
 		}
@@ -942,7 +948,9 @@
 		rc = cam_csiphy_enable_hw(csiphy_dev);
 		if (rc != 0) {
 			CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed");
-			cam_cpas_stop(csiphy_dev->cpas_handle);
+			rc = cam_cpas_stop(csiphy_dev->cpas_handle);
+			if (rc < 0)
+				CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc);
 			goto release_mutex;
 		}
 		rc = cam_csiphy_config_dev(csiphy_dev);
@@ -952,7 +960,9 @@
 		if (rc < 0) {
 			CAM_ERR(CAM_CSIPHY, "cam_csiphy_config_dev failed");
 			cam_csiphy_disable_hw(csiphy_dev);
-			cam_cpas_stop(csiphy_dev->cpas_handle);
+			rc = cam_cpas_stop(csiphy_dev->cpas_handle);
+			if (rc < 0)
+				CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc);
 			goto release_mutex;
 		}
 		csiphy_dev->start_dev_count++;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 06d6bd4..bcd3823 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -1016,7 +1016,7 @@
 			&eeprom_cap,
 			sizeof(struct cam_eeprom_query_cap_t))) {
 			CAM_ERR(CAM_EEPROM, "Failed Copy to User");
-			return -EFAULT;
+			rc = -EFAULT;
 			goto release_mutex;
 		}
 		CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info);
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
index a2a738d..94bc611 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -927,6 +927,16 @@
 	}
 		break;
 	case CAM_CONFIG_DEV: {
+		if (s_ctrl->sensor_state < CAM_SENSOR_ACQUIRE) {
+			rc = -EINVAL;
+			CAM_ERR(CAM_SENSOR,
+				"sensor_id:[0x%x] not acquired to configure [%d] ",
+				s_ctrl->sensordata->slave_info.sensor_id,
+				s_ctrl->sensor_state
+			);
+			goto release_mutex;
+		}
+
 		rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg);
 		if (rc < 0) {
 			CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc);
diff --git a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c
index 626473f..77a7204 100644
--- a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c
@@ -191,7 +191,7 @@
 
 static struct dentry *smmu_dentry;
 
-static bool smmu_fatal_flag;
+static bool smmu_fatal_flag = true;
 
 static enum dma_data_direction cam_smmu_translate_dir(
 	enum cam_smmu_map_dir dir);
diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c
index d4487ef..93d39e3 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c
@@ -288,6 +288,7 @@
 	int rc;
 	long idx = 0;
 	bool bit;
+	int i = 0;
 
 	if (!sync_obj || !merged_obj) {
 		CAM_ERR(CAM_SYNC, "Invalid pointer(s)");
@@ -305,6 +306,14 @@
 		return -EINVAL;
 	}
 
+	for (i = 0; i < num_objs; i++) {
+		rc = cam_sync_check_valid(sync_obj[i]);
+		if (rc) {
+			CAM_ERR(CAM_SYNC, "Sync_obj[%d] %d valid check fail",
+				i, sync_obj[i]);
+			return rc;
+		}
+	}
 	do {
 		idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
 		if (idx >= CAM_SYNC_MAX_OBJS)
@@ -376,6 +385,29 @@
 	return cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
 }
 
+int cam_sync_check_valid(int32_t sync_obj)
+{
+	struct sync_table_row *row = NULL;
+
+	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+		return -EINVAL;
+
+	row = sync_dev->sync_table + sync_obj;
+
+	if (!test_bit(sync_obj, sync_dev->bitmap)) {
+		CAM_ERR(CAM_SYNC, "Error: Released sync obj received %d",
+			sync_obj);
+		return -EINVAL;
+	}
+
+	if (row->state == CAM_SYNC_STATE_INVALID) {
+		CAM_ERR(CAM_SYNC,
+			"Error: accessing an uninitialized sync obj = %d",
+			sync_obj);
+		return -EINVAL;
+	}
+	return 0;
+}
 int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms)
 {
 	unsigned long timeleft;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_api.h
index c735d51..f2f67cb 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_api.h
+++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_api.h
@@ -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
@@ -147,5 +147,14 @@
  */
 int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms);
 
+/**
+ * @brief: Check if sync object is valid
+ *
+ * @param sync_obj: int referencing the sync object to be checked
+ *
+ * @return 0 upon success, -EINVAL if sync object is in bad state or arguments
+ * are invalid
+ */
+int cam_sync_check_valid(int32_t sync_obj);
 
 #endif /* __CAM_SYNC_API_H__ */
diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
index 0f910c9..185e060 100644
--- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
@@ -182,11 +182,15 @@
 	int        i;
 	int        rc = 0;
 	int32_t    hdl;
+	uint64_t   requestId;
+	uint32_t   num_patches;
 
 	/* process patch descriptor */
 	patch_desc = (struct cam_patch_desc *)
 			((uint32_t *) &packet->payload +
 			packet->patch_offset/4);
+	requestId = packet->header.request_id;
+	num_patches = packet->num_patches;
 	CAM_DBG(CAM_UTIL, "packet = %pK patch_desc = %pK size = %lu",
 			(void *)packet, (void *)patch_desc,
 			sizeof(struct cam_patch_desc));
@@ -197,7 +201,16 @@
 		rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl,
 			hdl, &iova_addr, &src_buf_size);
 		if (rc < 0) {
-			CAM_ERR(CAM_UTIL, "unable to get src buf address");
+			CAM_ERR(CAM_UTIL,
+				"unable to get src buf address ReqId: %llu, num_patches = %d",
+				requestId, num_patches);
+			CAM_ERR(CAM_UTIL,
+				"i = %d patch info = %x %x %x %x src_bfsz:0x%x",
+				i, patch_desc[i].dst_buf_hdl,
+				patch_desc[i].dst_offset,
+				patch_desc[i].src_buf_hdl,
+				patch_desc[i].src_offset,
+				(uint32_t)src_buf_size);
 			return rc;
 		}
 		src_buf_iova_addr = (uint32_t *)iova_addr;
@@ -206,18 +219,37 @@
 		rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl,
 			&cpu_addr, &dst_buf_len);
 		if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) {
-			CAM_ERR(CAM_UTIL, "unable to get dst buf address");
+			CAM_ERR(CAM_UTIL,
+				"unable to get dst buf address ReqId: %llu, num_patches = %d",
+				requestId, num_patches);
+			CAM_ERR(CAM_UTIL,
+				"i = %d patch info = %x %x %x %x dst_bfsz:0x%x",
+				i, patch_desc[i].dst_buf_hdl,
+				patch_desc[i].dst_offset,
+				patch_desc[i].src_buf_hdl,
+				patch_desc[i].src_offset,
+				(uint32_t)dst_buf_len);
 			return rc;
 		}
 		dst_cpu_addr = (uint32_t *)cpu_addr;
 
-		CAM_DBG(CAM_UTIL, "i = %d patch info = %x %x %x %x", i,
-			patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
+		CAM_DBG(CAM_UTIL,
+			"ReqId: %llu, i = %d patch info = %x %x %x %x",
+			requestId, i, patch_desc[i].dst_buf_hdl,
+			patch_desc[i].dst_offset,
 			patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
 
 		if ((size_t)patch_desc[i].src_offset >= src_buf_size) {
 			CAM_ERR(CAM_UTIL,
-				"Invalid src buf patch offset");
+				"Invalid src buf patch offset ReqId: %llu, num_patches = %d",
+				requestId, num_patches);
+			CAM_ERR(CAM_UTIL,
+				"i = %d patch info = %x %x %x %x src_bfsz:0x%x",
+				i, patch_desc[i].dst_buf_hdl,
+				patch_desc[i].dst_offset,
+				patch_desc[i].src_buf_hdl,
+				patch_desc[i].src_offset,
+				(uint32_t)src_buf_size);
 			return -EINVAL;
 		}
 
@@ -225,7 +257,15 @@
 			((dst_buf_len - sizeof(void *)) <
 			(size_t)patch_desc[i].dst_offset)) {
 			CAM_ERR(CAM_UTIL,
-				"Invalid dst buf patch offset");
+				"Invalid dst buf patch offset ReqId: %llu, num_patches = %d",
+				requestId, num_patches);
+			CAM_ERR(CAM_UTIL,
+				"i = %d patch info = %x %x %x %x dst_bfsz:0x%x",
+				i, patch_desc[i].dst_buf_hdl,
+				patch_desc[i].dst_offset,
+				patch_desc[i].src_buf_hdl,
+				patch_desc[i].src_offset,
+				(uint32_t)dst_buf_len);
 			return -EINVAL;
 		}
 
@@ -353,3 +393,115 @@
 
 	return rc;
 }
+
+int32_t cam_packet_validate_plane_size(
+	struct cam_buf_io_cfg *io_cfg,
+	int plane_index,
+	size_t size)
+{
+	int rc = 0;
+	uint32_t kmd_plane_size = 0;
+	uint32_t plane_stride = 0;
+	uint32_t slice_height = 0;
+	uint32_t metadata_size = 0;
+	uint32_t format = io_cfg->format;
+	uint32_t plane_pixel_size = 0;
+
+	if (plane_index < CAM_PACKET_MAX_PLANES) {
+		plane_stride = io_cfg->planes[plane_index].plane_stride;
+		slice_height = io_cfg->planes[plane_index].slice_height;
+	}
+
+	if (!(plane_stride && slice_height)) {
+		CAM_ERR(CAM_ISP,
+			"Invalid values from UMD stride %d, slice height %d",
+			plane_stride,
+			slice_height);
+		return -EINVAL;
+	}
+
+	switch (format) {
+	case CAM_FORMAT_MIPI_RAW_6:
+	case CAM_FORMAT_MIPI_RAW_8:
+		kmd_plane_size = ((plane_stride * slice_height) + 16 - 1)
+			/ 16 * 16;
+		break;
+	case CAM_FORMAT_MIPI_RAW_10:
+		if (plane_stride % 4 == 0)
+			kmd_plane_size = ((plane_stride * slice_height)
+				+ 16 - 1) / 16 * 16;
+		break;
+	case CAM_FORMAT_MIPI_RAW_12:
+		if (plane_stride % 2 == 0)
+			kmd_plane_size = ((plane_stride * slice_height)
+				+ 16 - 1) / 16 * 16;
+		break;
+	case CAM_FORMAT_MIPI_RAW_14:
+		if (plane_stride % 4 == 0)
+			kmd_plane_size = plane_stride * slice_height * 7 / 4;
+		break;
+	case CAM_FORMAT_PLAIN16_8:
+	case CAM_FORMAT_PLAIN16_10:
+	case CAM_FORMAT_PLAIN16_12:
+	case CAM_FORMAT_PLAIN16_14:
+	case CAM_FORMAT_PLAIN16_16:
+	case CAM_FORMAT_PLAIN64:
+			kmd_plane_size = plane_stride * slice_height;
+		break;
+	case CAM_FORMAT_NV21:
+	case CAM_FORMAT_NV12:
+	if (plane_index < CAM_PACKET_MAX_PLANES)
+		kmd_plane_size = plane_stride * slice_height;
+		break;
+	case CAM_FORMAT_PD10:
+	if (plane_index < CAM_PACKET_MAX_PLANES)
+		kmd_plane_size = plane_stride * slice_height;
+	break;
+	case CAM_FORMAT_UBWC_NV12:
+	case CAM_FORMAT_UBWC_NV12_4R:
+	case CAM_FORMAT_UBWC_TP10:
+		metadata_size = io_cfg->planes[plane_index].meta_size;
+		plane_pixel_size = ((plane_stride * slice_height) +
+	       (4096 - 1)) & ~((uint32_t) 4096 - 1);
+		kmd_plane_size = metadata_size + plane_pixel_size;
+		break;
+	case CAM_FORMAT_UBWC_P010:
+	case CAM_FORMAT_PLAIN32_20:
+	case CAM_FORMAT_TP10:
+	case CAM_FORMAT_YUV422:
+	case CAM_FORMAT_PD8:
+	case CAM_FORMAT_PLAIN128:
+	case CAM_FORMAT_ARGB:
+	case CAM_FORMAT_ARGB_10:
+	case CAM_FORMAT_ARGB_12:
+	case CAM_FORMAT_ARGB_14:
+	case CAM_FORMAT_MIPI_RAW_16:
+	case CAM_FORMAT_MIPI_RAW_20:
+	case CAM_FORMAT_QTI_RAW_8:
+	case CAM_FORMAT_QTI_RAW_10:
+	case CAM_FORMAT_QTI_RAW_12:
+	case CAM_FORMAT_QTI_RAW_14:
+	case CAM_FORMAT_PLAIN8:
+	case CAM_FORMAT_PLAIN8_SWAP:
+	case CAM_FORMAT_PLAIN8_10:
+	case CAM_FORMAT_PLAIN8_10_SWAP:
+		kmd_plane_size = plane_stride * slice_height;
+		break;
+	default:
+		kmd_plane_size = plane_stride * slice_height;
+		break;
+	}
+	if (!kmd_plane_size ||
+		kmd_plane_size > (size - io_cfg->offsets[plane_index])) {
+		CAM_ERR(CAM_ISP,
+			"kmd size: %d umd size: %zu width: %d height: %d stride: %d sliceheight: %d ",
+			kmd_plane_size,
+			size,
+			io_cfg->planes[plane_index].width,
+			io_cfg->planes[plane_index].height,
+			plane_stride,
+			slice_height);
+		return -EINVAL;
+	}
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
index 33c07ad..e49968e 100644
--- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
+++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
@@ -135,4 +135,20 @@
 	struct cam_cmd_buf_desc *cmd_buf,
 	cam_packet_generic_blob_handler blob_handler_cb, void *user_data);
 
+/**
+ * cam_packet_validate_plane_size()
+ *
+ * @brief:             Utility function to calculate and validate size of buffer
+ *                     required for a format.
+ * @io_cfg:            Contains IO config info
+ * @plane_index        Plane index for which size is to be calculated
+ *
+ * @return:            Size of buffer
+ *
+ */
+int32_t cam_packet_validate_plane_size(
+	struct cam_buf_io_cfg *io_cfg,
+	int plane_index,
+	size_t size);
+
 #endif /* _CAM_PACKET_UTIL_H_ */
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index bde3110..6c2eebef 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -370,6 +370,12 @@
 				"hal_process_session_init_done: bad_pkt_size\n");
 		return -E2BIG;
 	}
+	if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32)
+		+ sizeof(struct hfi_msg_release_buffer_ref_event_packet)) {
+		dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n",
+			__func__, pkt->size);
+		return -E2BIG;
+	}
 
 	data = (struct hfi_msg_release_buffer_ref_event_packet *)
 				pkt->rg_ext_event_data;
@@ -1558,15 +1564,13 @@
 	struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt;
 	struct msm_vidc_cb_data_done data_done = {0};
 	struct hfi_picture_type *hfi_picture_type = NULL;
+	u32 is_sync_frame;
 
 	dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id);
 
 	if (!pkt || pkt->size <
-		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
-		dprintk(VIDC_ERR,
-				"hal_process_session_etb_done: bad_pkt_size\n");
-		return -E2BIG;
-	}
+		sizeof(struct hfi_msg_session_empty_buffer_done_packet))
+		goto bad_packet_size;
 
 	data_done.device_id = device_id;
 	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
@@ -1586,8 +1590,13 @@
 	data_done.input_done.extra_data_buffer = pkt->extra_data_buffer;
 	data_done.input_done.status =
 		hfi_map_err_status(pkt->error_type);
-	hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0];
-	if (hfi_picture_type->is_sync_frame) {
+	is_sync_frame = pkt->rgData[0];
+	if (is_sync_frame == 1) {
+		if (pkt->size <
+			sizeof(struct hfi_msg_session_empty_buffer_done_packet)
+			+ sizeof(struct hfi_picture_type))
+			goto bad_packet_size;
+		hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1];
 		if (hfi_picture_type->picture_type)
 			data_done.input_done.flags =
 				hfi_picture_type->picture_type;
@@ -1604,6 +1613,10 @@
 	info->response.data = data_done;
 
 	return 0;
+bad_packet_size:
+	dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n",
+		__func__, pkt ? pkt->size : 0);
+	return -E2BIG;
 }
 
 static int hfi_process_session_ftb_done(
@@ -1838,8 +1851,7 @@
 	cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
 	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
 	cmd_done.status = hfi_map_err_status(pkt->error_type);
-	cmd_done.data.buffer_info =
-			*(struct hal_buffer_info *)pkt->rg_buffer_info;
+	cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info;
 	cmd_done.size = sizeof(struct hal_buffer_info);
 
 	info->response_type = HAL_SESSION_RELEASE_BUFFER_DONE;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 0cfe693..949eb0d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -601,7 +601,7 @@
 	u32 extra_data_buffer;
 	u32 flags;
 	struct hfi_frame_cr_stats_type ubwc_cr_stats;
-	u32 rgData[0];
+	u32 rgData[1];
 };
 
 struct hfi_msg_session_fill_buffer_done_compressed_packet {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 733cbb9..f66d6c9 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -655,7 +655,6 @@
 };
 
 struct hfi_picture_type {
-	u32 is_sync_frame;
 	u32 picture_type;
 };
 
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
index abf2ef1..654d9fa 100644
--- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
@@ -287,6 +287,12 @@
 				"hal_process_session_init_done: bad_pkt_size\n");
 		return -E2BIG;
 	}
+	if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32)
+		+ sizeof(struct hfi_msg_release_buffer_ref_event_packet)) {
+		dprintk(VIDC_ERR,
+			"hfi_msg_release_buffer_ref_event: bad_pkt_size\n");
+		return -E2BIG;
+	}
 
 	data = (struct hfi_msg_release_buffer_ref_event_packet *)
 				pkt->rg_ext_event_data;
@@ -1540,15 +1546,13 @@
 	struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt;
 	struct msm_vidc_cb_data_done data_done = {0};
 	struct hfi_picture_type *hfi_picture_type = NULL;
+	u32 is_sync_frame;
 
 	dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id);
 
 	if (!pkt || pkt->size <
-		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
-		dprintk(VIDC_ERR,
-				"hal_process_session_etb_done: bad_pkt_size\n");
-		return -E2BIG;
-	}
+		sizeof(struct hfi_msg_session_empty_buffer_done_packet))
+		goto bad_packet_size;
 
 	data_done.device_id = device_id;
 	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
@@ -1563,8 +1567,13 @@
 		(ion_phys_addr_t)pkt->extra_data_buffer;
 	data_done.input_done.status =
 		hfi_map_err_status(pkt->error_type);
-	hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0];
-	if (hfi_picture_type->is_sync_frame) {
+	is_sync_frame = pkt->rgData[0];
+	if (is_sync_frame == 1) {
+		if (pkt->size <
+			sizeof(struct hfi_msg_session_empty_buffer_done_packet)
+			+ sizeof(struct hfi_picture_type))
+			goto bad_packet_size;
+		hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1];
 		if (hfi_picture_type->picture_type)
 			data_done.input_done.flags =
 				hfi_picture_type->picture_type;
@@ -1583,6 +1592,10 @@
 	};
 
 	return 0;
+bad_packet_size:
+	dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n",
+		__func__, pkt ? pkt->size : 0);
+	return -E2BIG;
 }
 
 static int hfi_process_session_ftb_done(
@@ -1823,8 +1836,7 @@
 	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
 	cmd_done.status = hfi_map_err_status(pkt->error_type);
 	if (pkt->rg_buffer_info) {
-		cmd_done.data.buffer_info =
-			*(struct hal_buffer_info *)pkt->rg_buffer_info;
+		cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info;
 		cmd_done.size = sizeof(struct hal_buffer_info);
 	} else {
 		dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
index be3b992..d7e2154 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -347,7 +347,7 @@
 	 * ----------------|----------------------|------------------------|
 	 */
 
-	if (is_realtime_session(inst) &&
+	if (!is_realtime_session(inst) &&
 		(quirks & LOAD_CALC_IGNORE_NON_REALTIME_LOAD)) {
 		if (!inst->prop.fps) {
 			dprintk(VIDC_INFO, "instance:%pK fps = 0\n", inst);
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
index d0fd493..903603b 100644
--- a/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -662,7 +662,7 @@
 	u32 input_tag;
 	u32 packet_buffer;
 	u32 extra_data_buffer;
-	u32 rgData[0];
+	u32 rgData[1];
 };
 
 struct hfi_msg_session_fill_buffer_done_compressed_packet {
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
index c09cf84c..16c390a 100644
--- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
@@ -701,7 +701,6 @@
 };
 
 struct hfi_picture_type {
-	u32 is_sync_frame;
 	u32 picture_type;
 };
 
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 3ec631fc..5cd8a56 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -14,4 +14,10 @@
 	depends on SPI
 	---help---
 	  Unified driver for QTI CAN controllers.
+
+config CAN_MCP25XXFD
+        tristate "Microchip MCP25xxFD SPI CAN controllers"
+        depends on HAS_DMA
+        ---help---
+          Driver for the Microchip MCP25XXFD SPI FD-CAN controller family.
 endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index 64ba861..bbb4343 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_QTI_CAN)		+= qti-can.o
+obj-$(CONFIG_CAN_MCP25XXFD)     += mcp25xxfd.o
diff --git a/drivers/net/can/spi/mcp25xxfd.c b/drivers/net/can/spi/mcp25xxfd.c
new file mode 100644
index 0000000..12cdf44
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd.c
@@ -0,0 +1,4513 @@
+/*
+ * CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2017 Martin Sperl <kernel@xxxxxxxxxxxxxxxx>
+ *
+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ *
+ * Based on Microchip MCP251x CAN controller driver written by
+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
+ *
+ */
+
+#include <linux/can/core.h>
+#include <linux/can/dev.h>
+#include <linux/can/led.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/spi/spi.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+
+#define DEVICE_NAME "mcp25xxfd"
+
+/* device description and rational:
+ *
+ * the mcp25xxfd is a CanFD controller that also supports can2.0 only
+ * modes.
+ * It is connected via spi to the host and requires at minimum a single
+ * irq line in addition to the SPI lines - it is not mentioned explicitly
+ * in the documentation but in principle SPI 3-wire should be possible.
+ *
+ * The clock connected is typically 4MHz, 20MHz or 40MHz.
+ * For the 4MHz clock the controller contains 10x PLL circuitry.
+ *
+ * The controller itself has 2KB or ECC-SRAM for data.
+ * It also has 32 FIFOs (of up to 32 CAN-frames).
+ * There are 4 Fifo types which can get configured:
+ * * TEF - Transmission Event Fifo - which consumes FIFO 0
+ *   even if it is not configured
+ * * Tansmission Queue - for up to 32 Frames.
+ *   this queue reorders CAN frames to get transmitted following the
+ *   typical CAN dominant/recessive rules on the can bus itself.
+ *   This FIFO is optional.
+ * * TX FIFO: generic TX fifos that can contain arbitrary data
+ *   and which come with a configurable priority for transmission
+ *   It is also possible to have the Controller automatically trigger
+ *   a transfer when a Filter Rule for a RTR frame matches.
+ *   Each of these fifos in principle can get configured for distinct
+ *   dlc sizes (8 thru 64 bytes)
+ * * RX FIFO: generic RX fifo which is filled via filter-rules.
+ *   Each of these fifos in principle can get configured for distinct
+ *   dlc sizes (8 thru 64 bytes)
+ *   Unfortunately there is no filter rule that would allow triggering
+ *   on different frame sizes, so for all practical purposes the
+ *   RX fifos have to be of the same size (unless one wants to experience
+ *   lost data).
+ * When a Can Frame is transmitted fromthe TX Queue or an individual
+ * TX FIFO then a small TEF Frame can get added to the TEF FIFO queue
+ * to log the Transmission of the frame - this includes ID, Flags
+ * (including a custom identifier/index) .
+ *
+ * The controller provides an optional free running counter with a divider
+ * for timestamping of RX frames as well as for TEF entries.
+ *
+ * Driver Implementation details and rational:
+ * * The whole driver has been designed to give best performance
+ *   and as little packet loss as possible with 1MHZ Can frames with DLC=0
+ *   on small/slow devices like the Raspberry Pi 1
+ * * This means that some optimizations for full duplex communication
+ *   have been implemented to avoid CPU introduced latencies
+ *   (especially for spi_write_then_read cases) - this only applies to
+ *   4 wire SPI busses.
+ * * Due to the fact that the TXQ does reorder Can-Frames we do not make
+ *   use of it to avoid unexpected behaviour (say when running a
+ *   firmware upgrade via Can)
+ * * this means we use individual TX-fifos with a given priority and
+ *   we have to wait until all the TX fifos have been transmitted before
+ *   we can restart the networking queue to avoid reordering the frames on
+ *   the Can bus itself.
+ *   Still we can transmit a transmit only Duty-cycle of 66% to 90% on the
+ *   Can bus (at 1MHz).
+ *   The scaling factors here are:
+ *   * Can bus speed - lower Speeds increase Duty-cycle
+ *   * SPI Clock Rate - higher speeds increase duty-cycle
+ *   * CPU speed + SPI implementation - reduces latencies between transfers
+ * * There is a module parameter that allows the modification of the
+ *   number of tx_fifos, which is by default 7.
+ * * The driver offers some module parameters that allow to control the use
+ *   of some optimizations (prefer reading more data than necessary instead
+ *   of multiple SPI transfers - the idea here is that this way we may
+ *   allow the SPI-controller to use DMA instead of programmed IO to
+ *   limit latencies/number of interrupts)
+ *   When we have to read multiple RX frames in CanFD mode:
+ *   * we allow reading all 64 bytes of payload even if DLC <=8
+ *     this mode is used in Can2.0 only mode by default and can not get
+ *     disabled (SRAM Reads have to be a multiple of 4 bytes anyway)
+ *   * Releasing/freeing the RX queue requires writing of 1 byte per fifo.
+ *     unfortunately these 32-bit registers are not ajacent to each other,
+ *     so that for 2 consecutive RX Frames instead of writing 1 byte per
+ *     fifo (with protocol overhead of 2 bytes - so a total of 6 bytes in
+ *     2 transfers) we transmit 13 bytes (with a protocol overhead of 2 -
+ *     so a total of 15 bytes)
+ *     This optimization is only enabled by a module parameter.
+ * * we use TEF + time stamping to record the transmitted frames
+ *   including their timestamp - we use this to order TX and RX frames
+ *   when submitting them to the network stack.
+ * * due to the inability to "filter" based on DLC sizes we have to use
+ *   a common FIFO size. This is 8 bytes for Can2.0 and 64 bytes for CanFD.
+ * * the driver tries to detect the Controller only by reading registers,
+ *   but there are circumstances (e.g. after a crashed driver) where we
+ *   have to "blindly" configure the clock rate to get the controller to
+ *   respond correctly.
+ * * There is one situation where the controller will require a full POR
+ *   (total power off) to recover from a bad Clock configuration.
+ *   This happens when the wrong clock is configured in the device tree
+ *   (say 4MHz are configured, while 20 or 40MHz are used)
+ *   in such a situation the driver tries to enable the PLL, which will
+ *   never synchronize and the controller becomes unresponsive to further
+ *   spi requests until a POR.
+ */
+
+#define MCP25XXFD_OST_DELAY_MS		3
+#define MCP25XXFD_MIN_CLOCK_FREQUENCY	1000000
+#define MCP25XXFD_MAX_CLOCK_FREQUENCY	40000000
+#define MCP25XXFD_PLL_MULTIPLIER	10
+#define MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY				\
+	(MCP25XXFD_MAX_CLOCK_FREQUENCY / MCP25XXFD_PLL_MULTIPLIER)
+#define MCP25XXFD_SCLK_DIVIDER		2
+
+#define MCP25XXFD_OSC_POLLING_JIFFIES	(HZ / 2)
+
+#define TX_ECHO_SKB_MAX	32
+
+#define INSTRUCTION_RESET		0x0000
+#define INSTRUCTION_READ		0x3000
+#define INSTRUCTION_WRITE		0x2000
+#define INSTRUCTION_READ_CRC		0xB000
+#define INSTRUCTION_WRITE_CRC		0xA000
+#define INSTRUCTION_WRITE_SAVE		0xC000
+
+#define ADDRESS_MASK			0x0fff
+
+#define MCP25XXFD_SFR_BASE(x)		(0xE00 + (x))
+#define MCP25XXFD_OSC			MCP25XXFD_SFR_BASE(0x00)
+#  define MCP25XXFD_OSC_PLLEN		BIT(0)
+#  define MCP25XXFD_OSC_OSCDIS		BIT(2)
+#  define MCP25XXFD_OSC_SCLKDIV		BIT(4)
+#  define MCP25XXFD_OSC_CLKODIV_BITS	2
+#  define MCP25XXFD_OSC_CLKODIV_SHIFT	5
+#  define MCP25XXFD_OSC_CLKODIV_MASK			\
+	GENMASK(MCP25XXFD_OSC_CLKODIV_SHIFT		\
+		+ MCP25XXFD_OSC_CLKODIV_BITS - 1,	\
+		MCP25XXFD_OSC_CLKODIV_SHIFT)
+#  define MCP25XXFD_OSC_CLKODIV_10	3
+#  define MCP25XXFD_OSC_CLKODIV_4	2
+#  define MCP25XXFD_OSC_CLKODIV_2	1
+#  define MCP25XXFD_OSC_CLKODIV_1	0
+#  define MCP25XXFD_OSC_PLLRDY		BIT(8)
+#  define MCP25XXFD_OSC_OSCRDY		BIT(10)
+#  define MCP25XXFD_OSC_SCLKRDY		BIT(12)
+#define MCP25XXFD_IOCON			MCP25XXFD_SFR_BASE(0x04)
+#  define MCP25XXFD_IOCON_TRIS0		BIT(0)
+#  define MCP25XXFD_IOCON_TRIS1		BIT(1)
+#  define MCP25XXFD_IOCON_XSTBYEN	BIT(6)
+#  define MCP25XXFD_IOCON_LAT0		BIT(8)
+#  define MCP25XXFD_IOCON_LAT1		BIT(9)
+#  define MCP25XXFD_IOCON_GPIO0		BIT(16)
+#  define MCP25XXFD_IOCON_GPIO1		BIT(17)
+#  define MCP25XXFD_IOCON_PM0		BIT(24)
+#  define MCP25XXFD_IOCON_PM1		BIT(25)
+#  define MCP25XXFD_IOCON_TXCANOD	BIT(28)
+#  define MCP25XXFD_IOCON_SOF		BIT(29)
+#  define MCP25XXFD_IOCON_INTOD		BIT(29)
+#define MCP25XXFD_CRC			MCP25XXFD_SFR_BASE(0x08)
+#  define MCP25XXFD_CRC_MASK		GENMASK(15, 0)
+#  define MCP25XXFD_CRC_CRCERRIE	BIT(16)
+#  define MCP25XXFD_CRC_FERRIE		BIT(17)
+#  define MCP25XXFD_CRC_CRCERRIF	BIT(24)
+#  define MCP25XXFD_CRC_FERRIF		BIT(25)
+#define MCP25XXFD_ECCCON		MCP25XXFD_SFR_BASE(0x0C)
+#  define MCP25XXFD_ECCCON_ECCEN	BIT(0)
+#  define MCP25XXFD_ECCCON_SECIE	BIT(1)
+#  define MCP25XXFD_ECCCON_DEDIE	BIT(2)
+#  define MCP25XXFD_ECCCON_PARITY_BITS 6
+#  define MCP25XXFD_ECCCON_PARITY_SHIFT 8
+#  define MCP25XXFD_ECCCON_PARITY_MASK			\
+	GENMASK(MCP25XXFD_ECCCON_PARITY_SHIFT		\
+		+ MCP25XXFD_ECCCON_PARITY_BITS - 1,	\
+		MCP25XXFD_ECCCON_PARITY_SHIFT)
+#define MCP25XXFD_ECCSTAT		MCP25XXFD_SFR_BASE(0x10)
+#  define MCP25XXFD_ECCSTAT_SECIF	BIT(1)
+#  define MCP25XXFD_ECCSTAT_DEDIF	BIT(2)
+#  define MCP25XXFD_ECCSTAT_ERRADDR_SHIFT 8
+#  define MCP25XXFD_ECCSTAT_ERRADDR_MASK	      \
+	GENMASK(MCP25XXFD_ECCSTAT_ERRADDR_SHIFT + 11, \
+		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT)
+
+#define CAN_SFR_BASE(x)			(0x000 + (x))
+#define CAN_CON				CAN_SFR_BASE(0x00)
+#  define CAN_CON_DNCNT_BITS		5
+#  define CAN_CON_DNCNT_SHIFT		0
+#  define CAN_CON_DNCNT_MASK					\
+	GENMASK(CAN_CON_DNCNT_SHIFT + CAN_CON_DNCNT_BITS - 1,	\
+		CAN_CON_DNCNT_SHIFT)
+#  define CAN_CON_ISOCRCEN		BIT(5)
+#  define CAN_CON_PXEDIS		BIT(6)
+#  define CAN_CON_WAKFIL		BIT(8)
+#  define CAN_CON_WFT_BITS		2
+#  define CAN_CON_WFT_SHIFT		9
+#  define CAN_CON_WFT_MASK					\
+	GENMASK(CAN_CON_WFT_SHIFT + CAN_CON_WFT_BITS - 1,	\
+		CAN_CON_WFT_SHIFT)
+#  define CAN_CON_BUSY			BIT(11)
+#  define CAN_CON_BRSDIS		BIT(12)
+#  define CAN_CON_RTXAT			BIT(16)
+#  define CAN_CON_ESIGM			BIT(17)
+#  define CAN_CON_SERR2LOM		BIT(18)
+#  define CAN_CON_STEF			BIT(19)
+#  define CAN_CON_TXQEN			BIT(20)
+#  define CAN_CON_OPMODE_BITS		3
+#  define CAN_CON_OPMOD_SHIFT		21
+#  define CAN_CON_OPMOD_MASK					\
+	GENMASK(CAN_CON_OPMOD_SHIFT + CAN_CON_OPMODE_BITS - 1,	\
+		CAN_CON_OPMOD_SHIFT)
+#  define CAN_CON_REQOP_BITS		3
+#  define CAN_CON_REQOP_SHIFT		24
+#  define CAN_CON_REQOP_MASK					\
+	GENMASK(CAN_CON_REQOP_SHIFT + CAN_CON_REQOP_BITS - 1,	\
+		CAN_CON_REQOP_SHIFT)
+#    define CAN_CON_MODE_MIXED			0
+#    define CAN_CON_MODE_SLEEP			1
+#    define CAN_CON_MODE_INTERNAL_LOOPBACK	2
+#    define CAN_CON_MODE_LISTENONLY		3
+#    define CAN_CON_MODE_CONFIG			4
+#    define CAN_CON_MODE_EXTERNAL_LOOPBACK	5
+#    define CAN_CON_MODE_CAN2_0			6
+#    define CAN_CON_MODE_RESTRICTED		7
+#  define CAN_CON_ABAT			BIT(27)
+#  define CAN_CON_TXBWS_BITS		3
+#  define CAN_CON_TXBWS_SHIFT		28
+#  define CAN_CON_TXBWS_MASK					\
+	GENMASK(CAN_CON_TXBWS_SHIFT + CAN_CON_TXBWS_BITS - 1,	\
+		CAN_CON_TXBWS_SHIFT)
+#  define CAN_CON_DEFAULT				\
+	(CAN_CON_ISOCRCEN |				\
+	 CAN_CON_PXEDIS |				\
+	 CAN_CON_WAKFIL |				\
+	 (3 << CAN_CON_WFT_SHIFT) |			\
+	 CAN_CON_STEF |					\
+	 CAN_CON_TXQEN |				\
+	 (CAN_CON_MODE_CONFIG << CAN_CON_OPMOD_SHIFT) |	\
+	 (CAN_CON_MODE_CONFIG << CAN_CON_REQOP_SHIFT))
+#  define CAN_CON_DEFAULT_MASK	\
+	(CAN_CON_DNCNT_MASK |	\
+	 CAN_CON_ISOCRCEN |	\
+	 CAN_CON_PXEDIS |	\
+	 CAN_CON_WAKFIL |	\
+	 CAN_CON_WFT_MASK |	\
+	 CAN_CON_BRSDIS |	\
+	 CAN_CON_RTXAT |	\
+	 CAN_CON_ESIGM |	\
+	 CAN_CON_SERR2LOM |	\
+	 CAN_CON_STEF |		\
+	 CAN_CON_TXQEN |	\
+	 CAN_CON_OPMOD_MASK |	\
+	 CAN_CON_REQOP_MASK |	\
+	 CAN_CON_ABAT |		\
+	 CAN_CON_TXBWS_MASK)
+#define CAN_NBTCFG			CAN_SFR_BASE(0x04)
+#  define CAN_NBTCFG_SJW_BITS		7
+#  define CAN_NBTCFG_SJW_SHIFT		0
+#  define CAN_NBTCFG_SJW_MASK					\
+	GENMASK(CAN_NBTCFG_SJW_SHIFT + CAN_NBTCFG_SJW_BITS - 1, \
+		CAN_NBTCFG_SJW_SHIFT)
+#  define CAN_NBTCFG_TSEG2_BITS		7
+#  define CAN_NBTCFG_TSEG2_SHIFT	8
+#  define CAN_NBTCFG_TSEG2_MASK					    \
+	GENMASK(CAN_NBTCFG_TSEG2_SHIFT + CAN_NBTCFG_TSEG2_BITS - 1, \
+		CAN_NBTCFG_TSEG2_SHIFT)
+#  define CAN_NBTCFG_TSEG1_BITS		8
+#  define CAN_NBTCFG_TSEG1_SHIFT	16
+#  define CAN_NBTCFG_TSEG1_MASK					    \
+	GENMASK(CAN_NBTCFG_TSEG1_SHIFT + CAN_NBTCFG_TSEG1_BITS - 1, \
+		CAN_NBTCFG_TSEG1_SHIFT)
+#  define CAN_NBTCFG_BRP_BITS		8
+#  define CAN_NBTCFG_BRP_SHIFT		24
+#  define CAN_NBTCFG_BRP_MASK					\
+	GENMASK(CAN_NBTCFG_BRP_SHIFT + CAN_NBTCFG_BRP_BITS - 1, \
+		CAN_NBTCFG_BRP_SHIFT)
+#define CAN_DBTCFG			CAN_SFR_BASE(0x08)
+#  define CAN_DBTCFG_SJW_BITS		4
+#  define CAN_DBTCFG_SJW_SHIFT		0
+#  define CAN_DBTCFG_SJW_MASK					\
+	GENMASK(CAN_DBTCFG_SJW_SHIFT + CAN_DBTCFG_SJW_BITS - 1, \
+		CAN_DBTCFG_SJW_SHIFT)
+#  define CAN_DBTCFG_TSEG2_BITS		4
+#  define CAN_DBTCFG_TSEG2_SHIFT	8
+#  define CAN_DBTCFG_TSEG2_MASK					    \
+	GENMASK(CAN_DBTCFG_TSEG2_SHIFT + CAN_DBTCFG_TSEG2_BITS - 1, \
+		CAN_DBTCFG_TSEG2_SHIFT)
+#  define CAN_DBTCFG_TSEG1_BITS		5
+#  define CAN_DBTCFG_TSEG1_SHIFT	16
+#  define CAN_DBTCFG_TSEG1_MASK					    \
+	GENMASK(CAN_DBTCFG_TSEG1_SHIFT + CAN_DBTCFG_TSEG1_BITS - 1, \
+		CAN_DBTCFG_TSEG1_SHIFT)
+#  define CAN_DBTCFG_BRP_BITS		8
+#  define CAN_DBTCFG_BRP_SHIFT		24
+#  define CAN_DBTCFG_BRP_MASK					\
+	GENMASK(CAN_DBTCFG_BRP_SHIFT + CAN_DBTCFG_BRP_BITS - 1, \
+		CAN_DBTCFG_BRP_SHIFT)
+#define CAN_TDC				CAN_SFR_BASE(0x0C)
+#  define CAN_TDC_TDCV_BITS		5
+#  define CAN_TDC_TDCV_SHIFT		0
+#  define CAN_TDC_TDCV_MASK					\
+	GENMASK(CAN_TDC_TDCV_SHIFT + CAN_TDC_TDCV_BITS - 1, \
+		CAN_TDC_TDCV_SHIFT)
+#  define CAN_TDC_TDCO_BITS		5
+#  define CAN_TDC_TDCO_SHIFT		8
+#  define CAN_TDC_TDCO_MASK					\
+	GENMASK(CAN_TDC_TDCO_SHIFT + CAN_TDC_TDCO_BITS - 1, \
+		CAN_TDC_TDCO_SHIFT)
+#  define CAN_TDC_TDCMOD_BITS		2
+#  define CAN_TDC_TDCMOD_SHIFT		16
+#  define CAN_TDC_TDCMOD_MASK					\
+	GENMASK(CAN_TDC_TDCMOD_SHIFT + CAN_TDC_TDCMOD_BITS - 1, \
+		CAN_TDC_TDCMOD_SHIFT)
+#  define CAN_TDC_TDCMOD_DISABLED	0
+#  define CAN_TDC_TDCMOD_MANUAL		1
+#  define CAN_TDC_TDCMOD_AUTO		2
+#  define CAN_TDC_SID11EN		BIT(24)
+#  define CAN_TDC_EDGFLTEN		BIT(25)
+#define CAN_TBC				CAN_SFR_BASE(0x10)
+#define CAN_TSCON			CAN_SFR_BASE(0x14)
+#  define CAN_TSCON_TBCPRE_BITS		10
+#  define CAN_TSCON_TBCPRE_SHIFT	0
+#  define CAN_TSCON_TBCPRE_MASK					    \
+	GENMASK(CAN_TSCON_TBCPRE_SHIFT + CAN_TSCON_TBCPRE_BITS - 1, \
+		CAN_TSCON_TBCPRE_SHIFT)
+#  define CAN_TSCON_TBCEN		BIT(16)
+#  define CAN_TSCON_TSEOF		BIT(17)
+#  define CAN_TSCON_TSRES		BIT(18)
+#define CAN_VEC				CAN_SFR_BASE(0x18)
+#  define CAN_VEC_ICODE_BITS		7
+#  define CAN_VEC_ICODE_SHIFT		0
+#  define CAN_VEC_ICODE_MASK					    \
+	GENMASK(CAN_VEC_ICODE_SHIFT + CAN_VEC_ICODE_BITS - 1,	    \
+		CAN_VEC_ICODE_SHIFT)
+#  define CAN_VEC_FILHIT_BITS		5
+#  define CAN_VEC_FILHIT_SHIFT		8
+#  define CAN_VEC_FILHIT_MASK					\
+	GENMASK(CAN_VEC_FILHIT_SHIFT + CAN_VEC_FILHIT_BITS - 1, \
+		CAN_VEC_FILHIT_SHIFT)
+#  define CAN_VEC_TXCODE_BITS		7
+#  define CAN_VEC_TXCODE_SHIFT		16
+#  define CAN_VEC_TXCODE_MASK					\
+	GENMASK(CAN_VEC_TXCODE_SHIFT + CAN_VEC_TXCODE_BITS - 1, \
+		CAN_VEC_TXCODE_SHIFT)
+#  define CAN_VEC_RXCODE_BITS		7
+#  define CAN_VEC_RXCODE_SHIFT		24
+#  define CAN_VEC_RXCODE_MASK					\
+	GENMASK(CAN_VEC_RXCODE_SHIFT + CAN_VEC_RXCODE_BITS - 1, \
+		CAN_VEC_RXCODE_SHIFT)
+#define CAN_INT				CAN_SFR_BASE(0x1C)
+#  define CAN_INT_IF_SHIFT		0
+#  define CAN_INT_TXIF			BIT(0)
+#  define CAN_INT_RXIF			BIT(1)
+#  define CAN_INT_TBCIF			BIT(2)
+#  define CAN_INT_MODIF			BIT(3)
+#  define CAN_INT_TEFIF			BIT(4)
+#  define CAN_INT_ECCIF			BIT(8)
+#  define CAN_INT_SPICRCIF		BIT(9)
+#  define CAN_INT_TXATIF		BIT(10)
+#  define CAN_INT_RXOVIF		BIT(11)
+#  define CAN_INT_SERRIF		BIT(12)
+#  define CAN_INT_CERRIF		BIT(13)
+#  define CAN_INT_WAKIF			BIT(14)
+#  define CAN_INT_IVMIF			BIT(15)
+#  define CAN_INT_IF_MASK		\
+	(CAN_INT_TXIF |			\
+	 CAN_INT_RXIF |			\
+	 CAN_INT_TBCIF	|		\
+	 CAN_INT_MODIF	|		\
+	 CAN_INT_TEFIF	|		\
+	 CAN_INT_ECCIF	|		\
+	 CAN_INT_SPICRCIF |		\
+	 CAN_INT_TXATIF |		\
+	 CAN_INT_RXOVIF |		\
+	 CAN_INT_CERRIF |		\
+	 CAN_INT_SERRIF |		\
+	 CAN_INT_WAKEIF |		\
+	 CAN_INT_IVMIF)
+#  define CAN_INT_IE_SHIFT		16
+#  define CAN_INT_TXIE			(CAN_INT_TXIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_RXIE			(CAN_INT_RXIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_TBCIE			(CAN_INT_TBCIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_MODIE			(CAN_INT_MODIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_TEFIE			(CAN_INT_TEFIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_ECCIE			(CAN_INT_ECCIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_SPICRCIE		\
+	(CAN_INT_SPICRCIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_TXATIE		(CAN_INT_TXATIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_RXOVIE		(CAN_INT_RXOVIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_CERRIE		(CAN_INT_CERRIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_SERRIE		(CAN_INT_SERRIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_WAKIE			(CAN_INT_WAKIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_IVMIE			(CAN_INT_IVMIF << CAN_INT_IE_SHIFT)
+#  define CAN_INT_IE_MASK		\
+	(CAN_INT_TXIE |			\
+	 CAN_INT_RXIE |			\
+	 CAN_INT_TBCIE	|		\
+	 CAN_INT_MODIE	|		\
+	 CAN_INT_TEFIE	|		\
+	 CAN_INT_ECCIE	|		\
+	 CAN_INT_SPICRCIE |		\
+	 CAN_INT_TXATIE |		\
+	 CAN_INT_RXOVIE |		\
+	 CAN_INT_CERRIE |		\
+	 CAN_INT_SERRIE |		\
+	 CAN_INT_WAKEIE |		\
+	 CAN_INT_IVMIE)
+#define CAN_RXIF			CAN_SFR_BASE(0x20)
+#define CAN_TXIF			CAN_SFR_BASE(0x24)
+#define CAN_RXOVIF			CAN_SFR_BASE(0x28)
+#define CAN_TXATIF			CAN_SFR_BASE(0x2C)
+#define CAN_TXREQ			CAN_SFR_BASE(0x30)
+#define CAN_TREC			CAN_SFR_BASE(0x34)
+#  define CAN_TREC_REC_BITS		8
+#  define CAN_TREC_REC_SHIFT		0
+#  define CAN_TREC_REC_MASK				    \
+	GENMASK(CAN_TREC_REC_SHIFT + CAN_TREC_REC_BITS - 1, \
+		CAN_TREC_REC_SHIFT)
+#  define CAN_TREC_TEC_BITS		8
+#  define CAN_TREC_TEC_SHIFT		8
+#  define CAN_TREC_TEC_MASK				    \
+	GENMASK(CAN_TREC_TEC_SHIFT + CAN_TREC_TEC_BITS - 1, \
+		CAN_TREC_TEC_SHIFT)
+#  define CAN_TREC_EWARN		BIT(16)
+#  define CAN_TREC_RXWARN		BIT(17)
+#  define CAN_TREC_TXWARN		BIT(18)
+#  define CAN_TREC_RXBP			BIT(19)
+#  define CAN_TREC_TXBP			BIT(20)
+#  define CAN_TREC_TXBO			BIT(21)
+#define CAN_BDIAG0			CAN_SFR_BASE(0x38)
+#  define CAN_BDIAG0_NRERRCNT_BITS	8
+#  define CAN_BDIAG0_NRERRCNT_SHIFT	0
+#  define CAN_BDIAG0_NRERRCNT_MASK				\
+	GENMASK(CAN_BDIAG0_NRERRCNT_SHIFT + CAN_BDIAG0_NRERRCNT_BITS - 1, \
+		CAN_BDIAG0_NRERRCNT_SHIFT)
+#  define CAN_BDIAG0_NTERRCNT_BITS	8
+#  define CAN_BDIAG0_NTERRCNT_SHIFT	8
+#  define CAN_BDIAG0_NTERRCNT_MASK					\
+	GENMASK(CAN_BDIAG0_NTERRCNT_SHIFT + CAN_BDIAG0_NTERRCNT_BITS - 1, \
+		CAN_BDIAG0_NTERRCNT_SHIFT)
+#  define CAN_BDIAG0_DRERRCNT_BITS	8
+#  define CAN_BDIAG0_DRERRCNT_SHIFT	16
+#  define CAN_BDIAG0_DRERRCNT_MASK					\
+	GENMASK(CAN_BDIAG0_DRERRCNT_SHIFT + CAN_BDIAG0_DRERRCNT_BITS - 1, \
+		CAN_BDIAG0_DRERRCNT_SHIFT)
+#  define CAN_BDIAG0_DTERRCNT_BITS	8
+#  define CAN_BDIAG0_DTERRCNT_SHIFT	24
+#  define CAN_BDIAG0_DTERRCNT_MASK					\
+	GENMASK(CAN_BDIAG0_DTERRCNT_SHIFT + CAN_BDIAG0_DTERRCNT_BITS - 1, \
+		CAN_BDIAG0_DTERRCNT_SHIFT)
+#define CAN_BDIAG1			CAN_SFR_BASE(0x3C)
+#  define CAN_BDIAG1_EFMSGCNT_BITS	16
+#  define CAN_BDIAG1_EFMSGCNT_SHIFT	0
+#  define CAN_BDIAG1_EFMSGCNT_MASK					\
+	GENMASK(CAN_BDIAG1_EFMSGCNT_SHIFT + CAN_BDIAG1_EFMSGCNT_BITS - 1, \
+		CAN_BDIAG1_EFMSGCNT_SHIFT)
+#  define CAN_BDIAG1_NBIT0ERR		BIT(16)
+#  define CAN_BDIAG1_NBIT1ERR		BIT(17)
+#  define CAN_BDIAG1_NACKERR		BIT(18)
+#  define CAN_BDIAG1_NSTUFERR		BIT(19)
+#  define CAN_BDIAG1_NFORMERR		BIT(20)
+#  define CAN_BDIAG1_NCRCERR		BIT(21)
+#  define CAN_BDIAG1_TXBOERR		BIT(23)
+#  define CAN_BDIAG1_DBIT0ERR		BIT(24)
+#  define CAN_BDIAG1_DBIT1ERR		BIT(25)
+#  define CAN_BDIAG1_DFORMERR		BIT(27)
+#  define CAN_BDIAG1_DSTUFERR		BIT(28)
+#  define CAN_BDIAG1_DCRCERR		BIT(29)
+#  define CAN_BDIAG1_ESI		BIT(30)
+#  define CAN_BDIAG1_DLCMM		BIT(31)
+#define CAN_TEFCON			CAN_SFR_BASE(0x40)
+#  define CAN_TEFCON_TEFNEIE		BIT(0)
+#  define CAN_TEFCON_TEFHIE		BIT(1)
+#  define CAN_TEFCON_TEFFIE		BIT(2)
+#  define CAN_TEFCON_TEFOVIE		BIT(3)
+#  define CAN_TEFCON_TEFTSEN		BIT(5)
+#  define CAN_TEFCON_UINC		BIT(8)
+#  define CAN_TEFCON_FRESET		BIT(10)
+#  define CAN_TEFCON_FSIZE_BITS		5
+#  define CAN_TEFCON_FSIZE_SHIFT	24
+#  define CAN_TEFCON_FSIZE_MASK					    \
+	GENMASK(CAN_TEFCON_FSIZE_SHIFT + CAN_TEFCON_FSIZE_BITS - 1, \
+		CAN_TEFCON_FSIZE_SHIFT)
+#define CAN_TEFSTA			CAN_SFR_BASE(0x44)
+#  define CAN_TEFSTA_TEFNEIF		BIT(0)
+#  define CAN_TEFSTA_TEFHIF		BIT(1)
+#  define CAN_TEFSTA_TEFFIF		BIT(2)
+#  define CAN_TEFSTA_TEVOVIF		BIT(3)
+#define CAN_TEFUA			CAN_SFR_BASE(0x48)
+#define CAN_RESERVED			CAN_SFR_BASE(0x4C)
+#define CAN_TXQCON			CAN_SFR_BASE(0x50)
+#  define CAN_TXQCON_TXQNIE		BIT(0)
+#  define CAN_TXQCON_TXQEIE		BIT(2)
+#  define CAN_TXQCON_TXATIE		BIT(4)
+#  define CAN_TXQCON_TXEN		BIT(7)
+#  define CAN_TXQCON_UINC		BIT(8)
+#  define CAN_TXQCON_TXREQ		BIT(9)
+#  define CAN_TXQCON_FRESET		BIT(10)
+#  define CAN_TXQCON_TXPRI_BITS		5
+#  define CAN_TXQCON_TXPRI_SHIFT	16
+#  define CAN_TXQCON_TXPRI_MASK					    \
+	GENMASK(CAN_TXQCON_TXPRI_SHIFT + CAN_TXQCON_TXPRI_BITS - 1, \
+		CAN_TXQCON_TXPRI_SHIFT)
+#  define CAN_TXQCON_TXAT_BITS		2
+#  define CAN_TXQCON_TXAT_SHIFT		21
+#  define CAN_TXQCON_TXAT_MASK					    \
+	GENMASK(CAN_TXQCON_TXAT_SHIFT + CAN_TXQCON_TXAT_BITS - 1, \
+		CAN_TXQCON_TXAT_SHIFT)
+#  define CAN_TXQCON_FSIZE_BITS		5
+#  define CAN_TXQCON_FSIZE_SHIFT	24
+#  define CAN_TXQCON_FSIZE_MASK					    \
+	GENMASK(CAN_TXQCON_FSIZE_SHIFT + CAN_TXQCON_FSIZE_BITS - 1, \
+		CAN_TXQCON_FSIZE_SHIFT)
+#  define CAN_TXQCON_PLSIZE_BITS	3
+#  define CAN_TXQCON_PLSIZE_SHIFT	29
+#  define CAN_TXQCON_PLSIZE_MASK				      \
+	GENMASK(CAN_TXQCON_PLSIZE_SHIFT + CAN_TXQCON_PLSIZE_BITS - 1, \
+		CAN_TXQCON_PLSIZE_SHIFT)
+#    define CAN_TXQCON_PLSIZE_8		0
+#    define CAN_TXQCON_PLSIZE_12	1
+#    define CAN_TXQCON_PLSIZE_16	2
+#    define CAN_TXQCON_PLSIZE_20	3
+#    define CAN_TXQCON_PLSIZE_24	4
+#    define CAN_TXQCON_PLSIZE_32	5
+#    define CAN_TXQCON_PLSIZE_48	6
+#    define CAN_TXQCON_PLSIZE_64	7
+
+#define CAN_TXQSTA			CAN_SFR_BASE(0x54)
+#  define CAN_TXQSTA_TXQNIF		BIT(0)
+#  define CAN_TXQSTA_TXQEIF		BIT(2)
+#  define CAN_TXQSTA_TXATIF		BIT(4)
+#  define CAN_TXQSTA_TXERR		BIT(5)
+#  define CAN_TXQSTA_TXLARB		BIT(6)
+#  define CAN_TXQSTA_TXABT		BIT(7)
+#  define CAN_TXQSTA_TXQCI_BITS		5
+#  define CAN_TXQSTA_TXQCI_SHIFT	8
+#  define CAN_TXQSTA_TXQCI_MASK					    \
+	GENMASK(CAN_TXQSTA_TXQCI_SHIFT + CAN_TXQSTA_TXQCI_BITS - 1, \
+		CAN_TXQSTA_TXQCI_SHIFT)
+
+#define CAN_TXQUA			CAN_SFR_BASE(0x58)
+#define CAN_FIFOCON(x)			CAN_SFR_BASE(0x5C + 12 * ((x) - 1))
+#define CAN_FIFOCON_TFNRFNIE		BIT(0)
+#define CAN_FIFOCON_TFHRFHIE		BIT(1)
+#define CAN_FIFOCON_TFERFFIE		BIT(2)
+#define CAN_FIFOCON_RXOVIE		BIT(3)
+#define CAN_FIFOCON_TXATIE		BIT(4)
+#define CAN_FIFOCON_RXTSEN		BIT(5)
+#define CAN_FIFOCON_RTREN		BIT(6)
+#define CAN_FIFOCON_TXEN		BIT(7)
+#define CAN_FIFOCON_UINC		BIT(8)
+#define CAN_FIFOCON_TXREQ		BIT(9)
+#define CAN_FIFOCON_FRESET		BIT(10)
+#  define CAN_FIFOCON_TXPRI_BITS	5
+#  define CAN_FIFOCON_TXPRI_SHIFT	16
+#  define CAN_FIFOCON_TXPRI_MASK					\
+	GENMASK(CAN_FIFOCON_TXPRI_SHIFT + CAN_FIFOCON_TXPRI_BITS - 1,	\
+		CAN_FIFOCON_TXPRI_SHIFT)
+#  define CAN_FIFOCON_TXAT_BITS		2
+#  define CAN_FIFOCON_TXAT_SHIFT	21
+#  define CAN_FIFOCON_TXAT_MASK					    \
+	GENMASK(CAN_FIFOCON_TXAT_SHIFT + CAN_FIFOCON_TXAT_BITS - 1, \
+		CAN_FIFOCON_TXAT_SHIFT)
+#  define CAN_FIFOCON_TXAT_ONE_SHOT	0
+#  define CAN_FIFOCON_TXAT_THREE_SHOT	1
+#  define CAN_FIFOCON_TXAT_UNLIMITED	2
+#  define CAN_FIFOCON_FSIZE_BITS	5
+#  define CAN_FIFOCON_FSIZE_SHIFT	24
+#  define CAN_FIFOCON_FSIZE_MASK					\
+	GENMASK(CAN_FIFOCON_FSIZE_SHIFT + CAN_FIFOCON_FSIZE_BITS - 1,	\
+		CAN_FIFOCON_FSIZE_SHIFT)
+#  define CAN_FIFOCON_PLSIZE_BITS	3
+#  define CAN_FIFOCON_PLSIZE_SHIFT	29
+#  define CAN_FIFOCON_PLSIZE_MASK					\
+	GENMASK(CAN_FIFOCON_PLSIZE_SHIFT + CAN_FIFOCON_PLSIZE_BITS - 1, \
+		CAN_FIFOCON_PLSIZE_SHIFT)
+#define CAN_FIFOSTA(x)			CAN_SFR_BASE(0x60 + 12 * ((x) - 1))
+#  define CAN_FIFOSTA_TFNRFNIF		BIT(0)
+#  define CAN_FIFOSTA_TFHRFHIF		BIT(1)
+#  define CAN_FIFOSTA_TFERFFIF		BIT(2)
+#  define CAN_FIFOSTA_RXOVIF		BIT(3)
+#  define CAN_FIFOSTA_TXATIF		BIT(4)
+#  define CAN_FIFOSTA_TXERR		BIT(5)
+#  define CAN_FIFOSTA_TXLARB		BIT(6)
+#  define CAN_FIFOSTA_TXABT		BIT(7)
+#  define CAN_FIFOSTA_FIFOCI_BITS	5
+#  define CAN_FIFOSTA_FIFOCI_SHIFT	8
+#  define CAN_FIFOSTA_FIFOCI_MASK					\
+	GENMASK(CAN_FIFOSTA_FIFOCI_SHIFT + CAN_FIFOSTA_FIFOCI_BITS - 1, \
+		CAN_FIFOSTA_FIFOCI_SHIFT)
+#define CAN_FIFOUA(x)			CAN_SFR_BASE(0x64 + 12 * ((x) - 1))
+#define CAN_FLTCON(x)			CAN_SFR_BASE(0x1D0 + ((x) & 0x1c))
+#  define CAN_FILCON_SHIFT(x)		(((x) & 3) * 8)
+#  define CAN_FILCON_BITS(x)		CAN_FILCON_BITS_
+#  define CAN_FILCON_BITS_		4
+	/* avoid macro reuse warning, so do not use GENMASK as above */
+#  define CAN_FILCON_MASK(x)					\
+	(GENMASK(CAN_FILCON_BITS_ - 1, 0) << CAN_FILCON_SHIFT(x))
+#  define CAN_FIFOCON_FLTEN(x)		BIT(7 + CAN_FILCON_SHIFT(x))
+#define CAN_FLTOBJ(x)			CAN_SFR_BASE(0x1F0 + 8 * (x))
+#  define CAN_FILOBJ_SID_BITS		11
+#  define CAN_FILOBJ_SID_SHIFT		0
+#  define CAN_FILOBJ_SID_MASK					\
+	GENMASK(CAN_FILOBJ_SID_SHIFT + CAN_FILOBJ_SID_BITS - 1, \
+		CAN_FILOBJ_SID_SHIFT)
+#  define CAN_FILOBJ_EID_BITS		18
+#  define CAN_FILOBJ_EID_SHIFT		12
+#  define CAN_FILOBJ_EID_MASK					\
+	GENMASK(CAN_FILOBJ_EID_SHIFT + CAN_FILOBJ_EID_BITS - 1, \
+		CAN_FILOBJ_EID_SHIFT)
+#  define CAN_FILOBJ_SID11		BIT(29)
+#  define CAN_FILOBJ_EXIDE		BIT(30)
+#define CAN_FLTMASK(x)			CAN_SFR_BASE(0x1F4 + 8 * (x))
+#  define CAN_FILMASK_MSID_BITS		11
+#  define CAN_FILMASK_MSID_SHIFT	0
+#  define CAN_FILMASK_MSID_MASK					\
+	GENMASK(CAN_FILMASK_MSID_SHIFT + CAN_FILMASK_MSID_BITS - 1, \
+		CAN_FILMASK_MSID_SHIFT)
+#  define CAN_FILMASK_MEID_BITS		18
+#  define CAN_FILMASK_MEID_SHIFT	12
+#  define CAN_FILMASK_MEID_MASK					\
+	GENMASK(CAN_FILMASK_MEID_SHIFT + CAN_FILMASK_MEID_BITS - 1, \
+		CAN_FILMASK_MEID_SHIFT)
+#  define CAN_FILMASK_MSID11		BIT(29)
+#  define CAN_FILMASK_MIDE		BIT(30)
+
+#define CAN_OBJ_ID_SID_BITS		11
+#define CAN_OBJ_ID_SID_SHIFT		0
+#define CAN_OBJ_ID_SID_MASK					\
+	GENMASK(CAN_OBJ_ID_SID_SHIFT + CAN_OBJ_ID_SID_BITS - 1, \
+		CAN_OBJ_ID_SID_SHIFT)
+#define CAN_OBJ_ID_EID_BITS		18
+#define CAN_OBJ_ID_EID_SHIFT		11
+#define CAN_OBJ_ID_EID_MASK					\
+	GENMASK(CAN_OBJ_ID_EID_SHIFT + CAN_OBJ_ID_EID_BITS - 1, \
+		CAN_OBJ_ID_EID_SHIFT)
+#define CAN_OBJ_ID_SID_BIT11		BIT(29)
+
+#define CAN_OBJ_FLAGS_DLC_BITS		4
+#define CAN_OBJ_FLAGS_DLC_SHIFT		0
+#define CAN_OBJ_FLAGS_DLC_MASK					      \
+	GENMASK(CAN_OBJ_FLAGS_DLC_SHIFT + CAN_OBJ_FLAGS_DLC_BITS - 1, \
+		CAN_OBJ_FLAGS_DLC_SHIFT)
+#define CAN_OBJ_FLAGS_IDE		BIT(4)
+#define CAN_OBJ_FLAGS_RTR		BIT(5)
+#define CAN_OBJ_FLAGS_BRS		BIT(6)
+#define CAN_OBJ_FLAGS_FDF		BIT(7)
+#define CAN_OBJ_FLAGS_ESI		BIT(8)
+#define CAN_OBJ_FLAGS_SEQ_BITS		7
+#define CAN_OBJ_FLAGS_SEQ_SHIFT		9
+#define CAN_OBJ_FLAGS_SEQ_MASK					      \
+	GENMASK(CAN_OBJ_FLAGS_SEQ_SHIFT + CAN_OBJ_FLAGS_SEQ_BITS - 1, \
+		CAN_OBJ_FLAGS_SEQ_SHIFT)
+#define CAN_OBJ_FLAGS_FILHIT_BITS	11
+#define CAN_OBJ_FLAGS_FILHIT_SHIFT	5
+#define CAN_OBJ_FLAGS_FILHIT_MASK				      \
+	GENMASK(CAN_FLAGS_FILHIT_SHIFT + CAN_FLAGS_FILHIT_BITS - 1, \
+		CAN_FLAGS_FILHIT_SHIFT)
+
+#define CAN_OBJ_FLAGS_CUSTOM_ISTEF	BIT(31)
+
+#define MCP25XXFD_BUFFER_TXRX_SIZE 2048
+
+static const char * const mcp25xxfd_mode_names[] = {
+	[CAN_CON_MODE_MIXED] = "can2.0+canfd",
+	[CAN_CON_MODE_SLEEP] = "sleep",
+	[CAN_CON_MODE_INTERNAL_LOOPBACK] = "internal loopback",
+	[CAN_CON_MODE_LISTENONLY] = "listen only",
+	[CAN_CON_MODE_CONFIG] = "config",
+	[CAN_CON_MODE_EXTERNAL_LOOPBACK] = "external loopback",
+	[CAN_CON_MODE_CAN2_0] = "can2.0",
+	[CAN_CON_MODE_RESTRICTED] = "restricted"
+};
+
+struct mcp25xxfd_obj {
+	u32 id;
+	u32 flags;
+};
+
+struct mcp25xxfd_obj_tx {
+	struct mcp25xxfd_obj header;
+	u32 data[];
+};
+
+static void mcp25xxfd_obj_to_le(struct mcp25xxfd_obj *obj)
+{
+	obj->id = cpu_to_le32(obj->id);
+	obj->flags = cpu_to_le32(obj->flags);
+}
+
+struct mcp25xxfd_obj_ts {
+	u32 id;
+	u32 flags;
+	u32 ts;
+};
+
+struct mcp25xxfd_obj_tef {
+	struct mcp25xxfd_obj_ts header;
+};
+
+struct mcp25xxfd_obj_rx {
+	struct mcp25xxfd_obj_ts header;
+	u8 data[];
+};
+
+static void mcp25xxfd_obj_ts_from_le(struct mcp25xxfd_obj_ts *obj)
+{
+	obj->id = le32_to_cpu(obj->id);
+	obj->flags = le32_to_cpu(obj->flags);
+	obj->ts = le32_to_cpu(obj->ts);
+}
+
+#define FIFO_DATA(x)			(0x400 + (x))
+#define FIFO_DATA_SIZE			0x800
+
+static const struct can_bittiming_const mcp25xxfd_nominal_bittiming_const = {
+	.name		= DEVICE_NAME,
+	.tseg1_min	= 2,
+	.tseg1_max	= BIT(CAN_NBTCFG_TSEG1_BITS),
+	.tseg2_min	= 1,
+	.tseg2_max	= BIT(CAN_NBTCFG_TSEG2_BITS),
+	.sjw_max	= BIT(CAN_NBTCFG_SJW_BITS),
+	.brp_min	= 1,
+	.brp_max	= BIT(CAN_NBTCFG_BRP_BITS),
+	.brp_inc	= 1,
+};
+
+static const struct can_bittiming_const mcp25xxfd_data_bittiming_const = {
+	.name		= DEVICE_NAME,
+	.tseg1_min	= 1,
+	.tseg1_max	= BIT(CAN_DBTCFG_TSEG1_BITS),
+	.tseg2_min	= 1,
+	.tseg2_max	= BIT(CAN_DBTCFG_TSEG2_BITS),
+	.sjw_max	= BIT(CAN_DBTCFG_SJW_BITS),
+	.brp_min	= 1,
+	.brp_max	= BIT(CAN_DBTCFG_BRP_BITS),
+	.brp_inc	= 1,
+};
+
+enum mcp25xxfd_model {
+	CAN_MCP2517FD	= 0x2517,
+};
+
+enum mcp25xxfd_gpio_mode {
+	gpio_mode_int		= 0,
+	gpio_mode_standby	= MCP25XXFD_IOCON_XSTBYEN,
+	gpio_mode_out_low	= MCP25XXFD_IOCON_PM0,
+	gpio_mode_out_high	= MCP25XXFD_IOCON_PM0 | MCP25XXFD_IOCON_LAT0,
+	gpio_mode_in		= MCP25XXFD_IOCON_PM0 | MCP25XXFD_IOCON_TRIS0
+};
+
+struct mcp25xxfd_trigger_tx_message {
+	struct spi_message msg;
+	struct spi_transfer fill_xfer;
+	struct spi_transfer trigger_xfer;
+	int fifo;
+	char fill_cmd[2];
+	char fill_obj[sizeof(struct mcp25xxfd_obj_tx)];
+	char fill_data[64];
+	char trigger_cmd[2];
+	char trigger_data;
+};
+
+struct mcp25xxfd_read_fifo_info {
+	struct mcp25xxfd_obj_ts *rxb[32];
+	int rx_count;
+};
+
+struct mcp25xxfd_priv {
+	struct can_priv	   can;
+	struct net_device *net;
+	struct spi_device *spi;
+	struct regulator *power;
+	struct regulator *transceiver;
+	struct clk *clk;
+
+	struct mutex clk_user_lock; /* lock for enabling/disabling the clock */
+	int clk_user_mask;
+#define MCP25XXFD_CLK_USER_CAN BIT(0)
+#define MCP25XXFD_CLK_USER_GPIO0 BIT(1)
+#define MCP25XXFD_CLK_USER_GPIO1 BIT(2)
+
+	struct dentry *debugfs_dir;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio;
+#endif
+
+	/* the actual model of the mcp25xxfd */
+	enum mcp25xxfd_model model;
+
+	struct {
+		/* clock configuration */
+		bool clock_pll;
+		bool clock_div2;
+		int  clock_odiv;
+
+		/* GPIO configuration */
+		bool gpio_opendrain;
+	} config;
+
+	/* the distinct spi_speeds to use for spi communication */
+	u32 spi_setup_speed_hz;
+	u32 spi_speed_hz;
+
+	/* fifo info */
+	struct {
+		/* define payload size and mode */
+		int payload_size;
+		u32 payload_mode;
+
+		/* TEF addresses - start, end and current */
+		u32 tef_fifos;
+		u32 tef_address_start;
+		u32 tef_address_end;
+		u32 tef_address;
+
+		/* address in mcp25xxfd-Fifo RAM of each fifo */
+		u32 fifo_address[32];
+
+		/* infos on tx-fifos */
+		u32 tx_fifos;
+		u32 tx_fifo_start;
+		u32 tx_fifo_mask; /* bitmask of which fifo is a tx fifo */
+		u32 tx_submitted_mask;
+		u32 tx_pending_mask;
+		u32 tx_pending_mask_in_irq;
+		u32 tx_processed_mask;
+
+		/* info on rx_fifos */
+		u32 rx_fifos;
+		u32 rx_fifo_depth;
+		u32 rx_fifo_start;
+		u32 rx_fifo_mask;  /* bitmask of which fifo is a rx fifo */
+
+		/* memory image of FIFO RAM on mcp25xxfd */
+		u8 fifo_data[MCP25XXFD_BUFFER_TXRX_SIZE];
+
+	} fifos;
+
+	/* structure with active fifos that need to get fed to the system */
+	struct mcp25xxfd_read_fifo_info queued_fifos;
+
+	/* statistics */
+	struct {
+		/* number of calls to the irq handler */
+		u64 irq_calls;
+		/* number of loops inside the irq handler */
+		u64 irq_loops;
+
+		/* interrupt handler state and statistics */
+		u32 irq_state;
+#define IRQ_STATE_NEVER_RUN 0
+#define IRQ_STATE_RUNNING 1
+#define IRQ_STATE_HANDLED 2
+		/* stats on number of rx overflows */
+		u64 rx_overflow;
+		/* statistics of FIFO usage */
+		u64 fifo_usage[32];
+
+		/* message abort counter */
+		u64 rx_mab;
+		u64 tx_mab;
+
+		/* message counter fd */
+		u64 rx_fd_count;
+		u64 tx_fd_count;
+
+		/* message counter fd bit rate switch */
+		u64 rx_brs_count;
+		u64 tx_brs_count;
+
+		/* interrupt counter */
+		u64 int_ivm_count;
+		u64 int_wake_count;
+		u64 int_cerr_count;
+		u64 int_serr_count;
+		u64 int_rxov_count;
+		u64 int_txat_count;
+		u64 int_spicrc_count;
+		u64 int_ecc_count;
+		u64 int_tef_count;
+		u64 int_mod_count;
+		u64 int_tbc_count;
+		u64 int_rx_count;
+		u64 int_tx_count;
+
+		/* dlc statistics */
+		u64 rx_dlc_usage[16];
+		u64 tx_dlc_usage[16];
+	} stats;
+
+	/* the current status of the mcp25xxfd */
+	struct {
+		u32 intf;
+		/* ASSERT(CAN_INT + 4 == CAN_RXIF) */
+		u32 rxif;
+		/* ASSERT(CAN_RXIF + 4 == CAN_TXIF) */
+		u32 txif;
+		/* ASSERT(CAN_TXIF + 4 == CAN_RXOVIF) */
+		u32 rxovif;
+		/* ASSERT(CAN_RXOVIF + 4 == CAN_TXATIF) */
+		u32 txatif;
+		/* ASSERT(CAN_TXATIF + 4 == CAN_TXREQ) */
+		u32 txreq;
+		/* ASSERT(CAN_TXREQ + 4 == CAN_TREC) */
+		u32 trec;
+		/* ASSERT(CAN_TREC + 4 == CAN_BDIAG0) */
+		u32 bdiag0;
+		/* ASSERT(CAN_BDIAG0 + 4 == CAN_BDIAG1) */
+		u32 bdiag1;
+	} status;
+
+	/* configuration registers */
+	struct {
+		u32 osc;
+		u32 ecccon;
+		u32 con;
+		u32 iocon;
+		u32 tdc;
+		u32 tscon;
+		u32 tefcon;
+		u32 nbtcfg;
+		u32 dbtcfg;
+	} regs;
+
+	/* interrupt handler signaling */
+	int force_quit;
+	int after_suspend;
+#define AFTER_SUSPEND_UP 1
+#define AFTER_SUSPEND_DOWN 2
+#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
+	int restart_tx;
+
+	/* interrupt flags during irq handling */
+	u32 bdiag1_clear_mask;
+	u32 bdiag1_clear_value;
+
+	/* composit error id and dataduring irq handling */
+	u32 can_err_id;
+	u32 can_err_data[8];
+
+	/* the current mode */
+	u32 active_can_mode;
+	u32 new_state;
+
+	/* status of the tx_queue enabled/disabled */
+	u32 tx_queue_status;
+#define TX_QUEUE_STATUS_INIT		0
+#define TX_QUEUE_STATUS_RUNNING		1
+#define TX_QUEUE_STATUS_NEEDS_START	2
+#define TX_QUEUE_STATUS_STOPPED		3
+
+	/* spi-tx/rx buffers for efficient transfers
+	 * used during setup and irq
+	 */
+	struct mutex spi_rxtx_lock;
+	u8 spi_tx[MCP25XXFD_BUFFER_TXRX_SIZE];
+	u8 spi_rx[MCP25XXFD_BUFFER_TXRX_SIZE];
+
+	/* structure for transmit fifo spi_messages */
+	struct mcp25xxfd_trigger_tx_message *spi_transmit_fifos;
+};
+
+/* module parameters */
+bool use_bulk_release_fifos;
+module_param(use_bulk_release_fifos, bool, 0664);
+MODULE_PARM_DESC(use_bulk_release_fifos,
+		 "Use code that favours longer spi transfers over multiple transfers");
+bool use_complete_fdfifo_read;
+module_param(use_complete_fdfifo_read, bool, 0664);
+MODULE_PARM_DESC(use_complete_fdfifo_read,
+		 "Use code that favours longer spi transfers over multiple transfers for fd can");
+unsigned int tx_fifos;
+module_param(tx_fifos, uint, 0664);
+MODULE_PARM_DESC(tx_fifos,
+		 "Number of tx-fifos to configure\n");
+unsigned int bw_sharing_log2bits;
+module_param(bw_sharing_log2bits, uint, 0664);
+MODULE_PARM_DESC(bw_sharing_log2bits,
+		 "Delay between 2 transmissions in number of arbitration bit times\n");
+bool three_shot;
+module_param(three_shot, bool, 0664);
+MODULE_PARM_DESC(three_shot,
+		 "Use 3 shots when one-shot is requested");
+
+/* spi sync helper */
+
+/* wrapper arround spi_sync, that sets speed_hz */
+static int mcp25xxfd_sync_transfer(struct spi_device *spi,
+				   struct spi_transfer *xfer,
+				   unsigned int xfers,
+				   int speed_hz)
+{
+	int i;
+
+	for (i = 0; i < xfers; i++)
+		xfer[i].speed_hz = speed_hz;
+
+	return spi_sync_transfer(spi, xfer, xfers);
+}
+
+/* an optimization of spi_write_then_read that merges the transfers */
+static int mcp25xxfd_write_then_read(struct spi_device *spi,
+				     const void *tx_buf,
+				     unsigned int tx_len,
+				     void *rx_buf,
+				     unsigned int rx_len,
+				     int speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct spi_transfer xfer[2];
+	u8 single_reg_data_tx[6];
+	u8 single_reg_data_rx[6];
+	int ret;
+
+	memset(xfer, 0, sizeof(xfer));
+
+	/* when using a halfduplex controller or to big for buffer */
+	if ((spi->master->flags & SPI_MASTER_HALF_DUPLEX) ||
+	    (tx_len + rx_len > sizeof(priv->spi_tx))) {
+		xfer[0].tx_buf = tx_buf;
+		xfer[0].len = tx_len;
+
+		xfer[1].rx_buf = rx_buf;
+		xfer[1].len = rx_len;
+
+		return mcp25xxfd_sync_transfer(spi, xfer, 2, speed_hz);
+	}
+
+	/* full duplex optimization */
+	xfer[0].len = tx_len + rx_len;
+	if (xfer[0].len > sizeof(single_reg_data_tx)) {
+		mutex_lock(&priv->spi_rxtx_lock);
+		xfer[0].tx_buf = priv->spi_tx;
+		xfer[0].rx_buf = priv->spi_rx;
+	} else {
+		xfer[0].tx_buf = single_reg_data_tx;
+		xfer[0].rx_buf = single_reg_data_rx;
+	}
+
+	/* copy and clean */
+	memcpy((u8 *)xfer[0].tx_buf, tx_buf, tx_len);
+	memset((u8 *)xfer[0].tx_buf + tx_len, 0, rx_len);
+
+	ret = mcp25xxfd_sync_transfer(spi, xfer, 1, speed_hz);
+	if (!ret)
+		memcpy(rx_buf, xfer[0].rx_buf + tx_len, rx_len);
+
+	if (xfer[0].len > sizeof(single_reg_data_tx))
+		mutex_unlock(&priv->spi_rxtx_lock);
+
+	return ret;
+}
+
+/* simple spi_write wrapper with speed_hz */
+static int mcp25xxfd_write(struct spi_device *spi,
+			   const void *tx_buf,
+			   unsigned int tx_len,
+			   int speed_hz)
+{
+	struct spi_transfer xfer;
+
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.tx_buf = tx_buf;
+	xfer.len = tx_len;
+
+	return mcp25xxfd_sync_transfer(spi, &xfer, 1, speed_hz);
+}
+
+/* spi_sync wrapper similar to spi_write_then_read that optimizes transfers */
+static int mcp25xxfd_write_then_write(struct spi_device *spi,
+				      const void *tx_buf,
+				      unsigned int tx_len,
+				      const void *tx2_buf,
+				      unsigned int tx2_len,
+				      int speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct spi_transfer xfer;
+	u8 single_reg_data[6];
+	int ret;
+
+	if (tx_len + tx2_len > MCP25XXFD_BUFFER_TXRX_SIZE)
+		return -EINVAL;
+
+	memset(&xfer, 0, sizeof(xfer));
+
+	xfer.len = tx_len + tx2_len;
+	if (xfer.len > sizeof(single_reg_data)) {
+		mutex_lock(&priv->spi_rxtx_lock);
+		xfer.tx_buf = priv->spi_tx;
+	} else {
+		xfer.tx_buf = single_reg_data;
+	}
+
+	memcpy((u8 *)xfer.tx_buf, tx_buf, tx_len);
+	memcpy((u8 *)xfer.tx_buf + tx_len, tx2_buf, tx2_len);
+
+	ret = mcp25xxfd_sync_transfer(spi, &xfer, 1, speed_hz);
+
+	if (xfer.len > sizeof(single_reg_data))
+		mutex_unlock(&priv->spi_rxtx_lock);
+
+	return ret;
+}
+
+/* mcp25xxfd spi command/protocol helper */
+
+static void mcp25xxfd_calc_cmd_addr(u16 cmd, u16 addr, u8 *data)
+{
+	cmd = cmd | (addr & ADDRESS_MASK);
+
+	data[0] = (cmd >> 8) & 0xff;
+	data[1] = (cmd >> 0) & 0xff;
+}
+
+static int mcp25xxfd_cmd_reset(struct spi_device *spi, u32 speed_hz)
+{
+	u8 cmd[2];
+
+	mcp25xxfd_calc_cmd_addr(INSTRUCTION_RESET, 0, cmd);
+
+	/* write the reset command */
+	return mcp25xxfd_write(spi, cmd, 2, speed_hz);
+}
+
+/* read multiple bytes, transform some registers */
+static int mcp25xxfd_cmd_readn(struct spi_device *spi, u32 reg,
+			       void *data, int n, u32 speed_hz)
+{
+	u8 cmd[2];
+	int ret;
+
+	mcp25xxfd_calc_cmd_addr(INSTRUCTION_READ, reg, cmd);
+
+	ret = mcp25xxfd_write_then_read(spi, &cmd, 2, data, n, speed_hz);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mcp25xxfd_convert_to_cpu(u32 *data, int n)
+{
+	int i;
+
+	for (i = 0; i < n; i++)
+		data[i] = le32_to_cpu(data[i]);
+
+	return 0;
+}
+
+static int mcp25xxfd_first_byte(u32 mask)
+{
+	return (mask & 0x0000ffff) ?
+		((mask & 0x000000ff) ? 0 : 1) :
+		((mask & 0x00ff0000) ? 2 : 3);
+}
+
+static int mcp25xxfd_last_byte(u32 mask)
+{
+	return (mask & 0xffff0000) ?
+		((mask & 0xff000000) ? 3 : 2) :
+		((mask & 0x0000ff00) ? 1 : 0);
+}
+
+/* read a register, but we are only interrested in a few bytes */
+static int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
+				   u32 *data, u32 mask, u32 speed_hz)
+{
+	int first_byte, last_byte, len_byte;
+	int ret;
+
+	/* check that at least one bit is set */
+	if (!mask)
+		return -EINVAL;
+
+	/* calculate first and last byte used */
+	first_byte = mcp25xxfd_first_byte(mask);
+	last_byte = mcp25xxfd_last_byte(mask);
+	len_byte = last_byte - first_byte + 1;
+
+	/* do a partial read */
+	*data = 0;
+	ret = mcp25xxfd_cmd_readn(spi, reg + first_byte,
+				  ((void *)data + first_byte), len_byte,
+				  speed_hz);
+	if (ret)
+		return ret;
+
+	return mcp25xxfd_convert_to_cpu(data, 1);
+}
+
+static int mcp25xxfd_cmd_read(struct spi_device *spi, u32 reg, u32 *data,
+			      u32 speed_hz)
+{
+	return mcp25xxfd_cmd_read_mask(spi, reg, data, -1, speed_hz);
+}
+
+/* read a register, but we are only interrested in a few bytes */
+static int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
+				    u32 data, u32 mask, u32 speed_hz)
+{
+	int first_byte, last_byte, len_byte;
+	u8 cmd[2];
+
+	/* check that at least one bit is set */
+	if (!mask)
+		return -EINVAL;
+
+	/* calculate first and last byte used */
+	first_byte = mcp25xxfd_first_byte(mask);
+	last_byte = mcp25xxfd_last_byte(mask);
+	len_byte = last_byte - first_byte + 1;
+
+	/* prepare buffer */
+	mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE, reg + first_byte, cmd);
+	data = cpu_to_le32(data);
+
+	return mcp25xxfd_write_then_write(spi,
+					  cmd, sizeof(cmd),
+					  ((void *)&data + first_byte),
+					  len_byte,
+					  speed_hz);
+}
+
+static int mcp25xxfd_cmd_write(struct spi_device *spi, u32 reg, u32 data,
+			       u32 speed_hz)
+{
+	return mcp25xxfd_cmd_write_mask(spi, reg, data, -1, speed_hz);
+}
+
+static int mcp25xxfd_cmd_writen(struct spi_device *spi, u32 reg,
+				void *data, int n, u32 speed_hz)
+{
+	u8 cmd[2];
+	int ret;
+
+	mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE, reg, cmd);
+
+	ret = mcp25xxfd_write_then_write(spi, &cmd, 2, data, n, speed_hz);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mcp25xxfd_clean_sram(struct spi_device *spi, u32 speed_hz)
+{
+	u8 buffer[256];
+	int i;
+	int ret;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	for (i = 0; i < FIFO_DATA_SIZE; i += sizeof(buffer)) {
+		ret = mcp25xxfd_cmd_writen(spi, FIFO_DATA(i),
+					   buffer, sizeof(buffer),
+					   speed_hz);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* mcp25xxfd opmode helper functions */
+
+static int mcp25xxfd_get_opmode(struct spi_device *spi,
+				int *mode,
+				int speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int ret;
+
+	/* read the mode */
+	ret = mcp25xxfd_cmd_read_mask(spi,
+				      CAN_CON,
+				      &priv->regs.con,
+				      CAN_CON_OPMOD_MASK,
+				      speed_hz);
+	if (ret)
+		return ret;
+	/* calculate the mode */
+	*mode = (priv->regs.con & CAN_CON_OPMOD_MASK) >>
+		CAN_CON_OPMOD_SHIFT;
+
+	/* and assign to active mode as well */
+	priv->active_can_mode = *mode;
+
+	return 0;
+}
+
+static int mcp25xxfd_set_opmode(struct spi_device *spi, int mode,
+				int speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 val = priv->regs.con & ~CAN_CON_REQOP_MASK;
+
+	/* regs.con also contains the effective register */
+	priv->regs.con = val |
+		(mode << CAN_CON_REQOP_SHIFT) |
+		(mode << CAN_CON_OPMOD_SHIFT);
+	priv->active_can_mode = mode;
+
+	/* if the opmode is sleep then the oscilator will be disabled
+	 * and also not ready
+	 */
+	if (mode == CAN_CON_MODE_SLEEP) {
+		priv->regs.osc &= ~(MCP25XXFD_OSC_OSCRDY |
+				    MCP25XXFD_OSC_PLLRDY |
+				    MCP25XXFD_OSC_SCLKRDY);
+		priv->regs.osc |= MCP25XXFD_OSC_OSCDIS;
+	}
+
+	/* but only write the relevant section */
+	return mcp25xxfd_cmd_write_mask(spi, CAN_CON,
+					priv->regs.con,
+					CAN_CON_REQOP_MASK,
+					speed_hz);
+}
+
+static int mcp25xxfd_set_normal_opmode(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int mode;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+		mode = CAN_CON_MODE_EXTERNAL_LOOPBACK;
+	else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+		mode = CAN_CON_MODE_LISTENONLY;
+	else if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+		mode = CAN_CON_MODE_MIXED;
+	else
+		mode = CAN_CON_MODE_CAN2_0;
+
+	return mcp25xxfd_set_opmode(spi, mode, priv->spi_setup_speed_hz);
+}
+
+/* clock helper */
+static int mcp25xxfd_wake_from_sleep(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 waitfor = MCP25XXFD_OSC_OSCRDY;
+	u32 mask = waitfor | MCP25XXFD_OSC_OSCDIS;
+	unsigned long timeout;
+	int ret;
+
+	/* write clock with OSCDIS cleared*/
+	priv->regs.osc &= ~MCP25XXFD_OSC_OSCDIS;
+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_OSC,
+				  priv->regs.osc,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* wait for synced pll/osc/sclk */
+	timeout = jiffies + MCP25XXFD_OSC_POLLING_JIFFIES;
+	while (time_before_eq(jiffies, timeout)) {
+		ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
+					 &priv->regs.osc,
+					 priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		if ((priv->regs.osc & mask) == waitfor) {
+			priv->active_can_mode = CAN_CON_MODE_CONFIG;
+			return 0;
+		}
+		/* wait some time */
+		msleep(100);
+	}
+
+	dev_err(&spi->dev,
+		"Clock did not enable within the timeout period\n");
+	return -ETIMEDOUT;
+}
+
+static int mcp25xxfd_hw_check_clock(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 val;
+	int ret;
+
+	/* read the osc register and check if it matches
+	 * what we have on record
+	 */
+	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
+				 &val,
+				 priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	if (val == priv->regs.osc)
+		return 0;
+
+	/* ignore all those ready bits on second try */
+	if ((val & 0xff) == (priv->regs.osc & 0xff)) {
+		dev_info(&spi->dev,
+			 "The oscillator register value %08x does not match what we expect: %08x - it is still reasonable, but please investigate\n",
+			val, priv->regs.osc);
+		return 0;
+	}
+
+	dev_err(&spi->dev,
+		"The oscillator register value %08x does not match what we expect: %08x\n",
+		val, priv->regs.osc);
+
+	return -ENODEV;
+}
+
+static int mcp25xxfd_start_clock(struct spi_device *spi, int requestor_mask)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int ret = 0;
+
+	mutex_lock(&priv->clk_user_lock);
+
+	priv->clk_user_mask |= requestor_mask;
+
+	if (priv->clk_user_mask != requestor_mask)
+		goto out;
+
+	/* check that the controller clock register
+	 * is what it is supposed to be
+	 */
+	ret = mcp25xxfd_hw_check_clock(spi);
+	if (ret) {
+		dev_err(&spi->dev,
+			"Controller clock register in unexpected state");
+		goto out;
+	}
+
+	/* and we start the clock */
+	if (!IS_ERR(priv->clk))
+		ret = clk_prepare_enable(priv->clk);
+
+	/* we wake from sleep */
+	if (priv->active_can_mode == CAN_CON_MODE_SLEEP)
+		ret = mcp25xxfd_wake_from_sleep(spi);
+
+out:
+	mutex_unlock(&priv->clk_user_lock);
+
+	return ret;
+}
+
+static int mcp25xxfd_stop_clock(struct spi_device *spi, int requestor_mask)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	mutex_lock(&priv->clk_user_lock);
+
+	priv->clk_user_mask &= ~requestor_mask;
+
+	if (!priv->clk_user_mask)
+		goto out;
+
+	/* put us into sleep mode */
+	mcp25xxfd_set_opmode(spi, CAN_CON_MODE_SLEEP,
+			     priv->spi_setup_speed_hz);
+
+	/* and we stop the clock */
+	if (!IS_ERR(priv->clk))
+		clk_disable_unprepare(priv->clk);
+
+out:
+	mutex_unlock(&priv->clk_user_lock);
+
+	return 0;
+}
+
+/* mcp25xxfd GPIO helper functions */
+#ifdef CONFIG_GPIOLIB
+
+enum mcp25xxfd_gpio_pins {
+	MCP25XXFD_GPIO_GPIO0 = 0,
+	MCP25XXFD_GPIO_GPIO1 = 1,
+};
+
+static int mcp25xxfd_gpio_request(struct gpio_chip *chip,
+				  unsigned int offset)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	int clock_requestor = offset ?
+		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return -EINVAL;
+
+	mcp25xxfd_start_clock(priv->spi, clock_requestor);
+
+	return 0;
+}
+
+static void mcp25xxfd_gpio_free(struct gpio_chip *chip,
+				unsigned int offset)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	int clock_requestor = offset ?
+		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return;
+
+	mcp25xxfd_stop_clock(priv->spi, clock_requestor);
+}
+
+static int mcp25xxfd_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	u32 mask = (offset) ? MCP25XXFD_IOCON_GPIO1 : MCP25XXFD_IOCON_GPIO0;
+	int ret;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return -EINVAL;
+
+	/* read the relevant gpio Latch */
+	ret = mcp25xxfd_cmd_read_mask(priv->spi, MCP25XXFD_IOCON,
+				      &priv->regs.iocon, mask,
+				      priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* return the match */
+	return priv->regs.iocon & mask;
+}
+
+static void mcp25xxfd_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			       int value)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	u32 mask = (offset) ? MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return;
+
+	/* update in memory representation with the corresponding value */
+	if (value)
+		priv->regs.iocon |= mask;
+	else
+		priv->regs.iocon &= ~mask;
+
+	mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
+				 priv->regs.iocon, mask,
+				 priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_gpio_direction_input(struct gpio_chip *chip,
+					  unsigned int offset)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	u32 mask_tri = (offset) ?
+		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
+	u32 mask_stby = (offset) ?
+		0 : MCP25XXFD_IOCON_XSTBYEN;
+	u32 mask_pm = (offset) ?
+		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return -EINVAL;
+
+	/* set the mask */
+	priv->regs.iocon |= mask_tri | mask_pm;
+
+	/* clear stby */
+	priv->regs.iocon &= ~mask_stby;
+
+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
+					priv->regs.iocon,
+					mask_tri | mask_stby | mask_pm,
+					priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_gpio_direction_output(struct gpio_chip *chip,
+					   unsigned int offset, int value)
+{
+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
+	u32 mask_tri = (offset) ?
+		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
+	u32 mask_lat = (offset) ?
+		MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
+	u32 mask_pm = (offset) ?
+		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
+	u32 mask_stby = (offset) ?
+		0 : MCP25XXFD_IOCON_XSTBYEN;
+
+	/* only handle gpio 0/1 */
+	if (offset > 1)
+		return -EINVAL;
+
+	/* clear the tristate bit and also clear stby */
+	priv->regs.iocon &= ~(mask_tri | mask_stby);
+
+	/* set GPIO mode */
+	priv->regs.iocon |= mask_pm;
+
+	/* set the value */
+	if (value)
+		priv->regs.iocon |= mask_lat;
+	else
+		priv->regs.iocon &= ~mask_lat;
+
+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
+					priv->regs.iocon,
+					mask_tri | mask_lat |
+					mask_pm | mask_stby,
+					priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_gpio_setup(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* gpiochip only handles GPIO0 and GPIO1 */
+	priv->gpio.owner		= THIS_MODULE;
+	priv->gpio.parent		= &spi->dev;
+	priv->gpio.label		= dev_name(&spi->dev);
+	priv->gpio.direction_input	= mcp25xxfd_gpio_direction_input;
+	priv->gpio.get			= mcp25xxfd_gpio_get;
+	priv->gpio.direction_output	= mcp25xxfd_gpio_direction_output;
+	priv->gpio.set			= mcp25xxfd_gpio_set;
+	priv->gpio.request		= mcp25xxfd_gpio_request;
+	priv->gpio.free			= mcp25xxfd_gpio_free;
+	priv->gpio.base			= -1;
+	priv->gpio.ngpio		= 2;
+	priv->gpio.can_sleep		= 1;
+
+	return devm_gpiochip_add_data(&spi->dev, &priv->gpio, priv);
+}
+
+#else
+
+static int mcp25xxfd_gpio_setup(struct spi_device *spi)
+{
+	return 0;
+}
+
+#endif
+
+/* ideally these would be defined in uapi/linux/can.h */
+#define CAN_EFF_SID_SHIFT		(CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)
+#define CAN_EFF_SID_BITS		CAN_SFF_ID_BITS
+#define CAN_EFF_SID_MASK				      \
+	GENMASK(CAN_EFF_SID_SHIFT + CAN_EFF_SID_BITS - 1,     \
+		CAN_EFF_SID_SHIFT)
+#define CAN_EFF_EID_SHIFT		0
+#define CAN_EFF_EID_BITS		CAN_EFF_SID_SHIFT
+#define CAN_EFF_EID_MASK				      \
+	GENMASK(CAN_EFF_EID_SHIFT + CAN_EFF_EID_BITS - 1,     \
+		CAN_EFF_EID_SHIFT)
+
+static void mcp25xxfd_canid_to_mcpid(u32 can_id, u32 *id, u32 *flags)
+{
+	if (can_id & CAN_EFF_FLAG) {
+		int sid = (can_id & CAN_EFF_SID_MASK) >> CAN_EFF_SID_SHIFT;
+		int eid = (can_id & CAN_EFF_EID_MASK) >> CAN_EFF_EID_SHIFT;
+		*id = (eid << CAN_OBJ_ID_EID_SHIFT) |
+			(sid << CAN_OBJ_ID_SID_SHIFT);
+		*flags = CAN_OBJ_FLAGS_IDE;
+	} else {
+		*id = can_id & CAN_SFF_MASK;
+		*flags = 0;
+	}
+
+	*flags |= (can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
+}
+
+static void mcp25xxfd_mcpid_to_canid(u32 mcpid, u32 mcpflags, u32 *id)
+{
+	u32 sid = (mcpid & CAN_OBJ_ID_SID_MASK) >> CAN_OBJ_ID_SID_SHIFT;
+	u32 eid = (mcpid & CAN_OBJ_ID_EID_MASK) >> CAN_OBJ_ID_EID_SHIFT;
+
+	if (mcpflags & CAN_OBJ_FLAGS_IDE) {
+		*id = (eid << CAN_EFF_EID_SHIFT) |
+			(sid << CAN_EFF_SID_SHIFT) |
+			CAN_EFF_FLAG;
+	} else {
+		*id = sid;
+	}
+
+	*id |= (mcpflags & CAN_OBJ_FLAGS_RTR) ? CAN_RTR_FLAG : 0;
+}
+
+static void __mcp25xxfd_stop_queue(struct net_device *net,
+				   unsigned int id)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+
+	if (priv->tx_queue_status >= TX_QUEUE_STATUS_STOPPED)
+		dev_warn(&priv->spi->dev,
+			 "tx-queue is already stopped by: %i\n",
+			 priv->tx_queue_status);
+
+	priv->tx_queue_status = id ? id : TX_QUEUE_STATUS_STOPPED;
+	netif_stop_queue(priv->net);
+}
+
+/* helper to identify who is stopping the queue by line number */
+#define mcp25xxfd_stop_queue(spi) \
+	__mcp25xxfd_stop_queue(spi, __LINE__)
+
+static void mcp25xxfd_wake_queue(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* nothing should be left pending /in flight now... */
+	priv->fifos.tx_pending_mask = 0;
+	priv->fifos.tx_submitted_mask = 0;
+	priv->fifos.tx_processed_mask = 0;
+	priv->tx_queue_status = TX_QUEUE_STATUS_RUNNING;
+
+	/* wake queue now */
+	netif_wake_queue(priv->net);
+}
+
+/* CAN transmit related*/
+
+static void mcp25xxfd_mark_tx_pending(void *context)
+{
+	struct mcp25xxfd_trigger_tx_message *txm = context;
+	struct spi_device *spi = txm->msg.spi;
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* only here or in the irq handler this value is changed,
+	 * so there is no race condition and it does not require locking
+	 * serialization happens via spi_pump_message
+	 */
+	priv->fifos.tx_pending_mask |= BIT(txm->fifo);
+}
+
+static int mcp25xxfd_fill_spi_transmit_fifos(struct mcp25xxfd_priv *priv)
+{
+	struct mcp25xxfd_trigger_tx_message *txm;
+	int i, fifo;
+	const u32 trigger = CAN_FIFOCON_TXREQ | CAN_FIFOCON_UINC;
+	const int first_byte = mcp25xxfd_first_byte(trigger);
+	u32 fifo_address;
+
+	priv->spi_transmit_fifos = kcalloc(priv->fifos.tx_fifos,
+					   sizeof(*priv->spi_transmit_fifos),
+					   GFP_KERNEL | GFP_DMA);
+	if (!priv->spi_transmit_fifos)
+		return -ENOMEM;
+
+	for (i = 0; i < priv->fifos.tx_fifos; i++) {
+		fifo = priv->fifos.tx_fifo_start + i;
+		txm = &priv->spi_transmit_fifos[i];
+		fifo_address = priv->fifos.fifo_address[fifo];
+		/* prepare the message */
+		spi_message_init(&txm->msg);
+		txm->msg.complete = mcp25xxfd_mark_tx_pending;
+		txm->msg.context = txm;
+		txm->fifo = fifo;
+		/* the payload itself */
+		txm->fill_xfer.speed_hz = priv->spi_speed_hz;
+		txm->fill_xfer.tx_buf = txm->fill_cmd;
+		txm->fill_xfer.len = 2;
+		txm->fill_xfer.cs_change = true;
+		mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE,
+					FIFO_DATA(fifo_address),
+					txm->fill_cmd);
+		spi_message_add_tail(&txm->fill_xfer, &txm->msg);
+		/* the trigger command */
+		txm->trigger_xfer.speed_hz = priv->spi_speed_hz;
+		txm->trigger_xfer.tx_buf = txm->trigger_cmd;
+		txm->trigger_xfer.len = 3;
+		mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE,
+					CAN_FIFOCON(fifo) + first_byte,
+					txm->trigger_cmd);
+		txm->trigger_data = trigger >> (8 * first_byte);
+		spi_message_add_tail(&txm->trigger_xfer, &txm->msg);
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_transmit_message_common(struct spi_device *spi,
+					     int fifo,
+					     struct mcp25xxfd_obj_tx *obj,
+					     int len,
+					     u8 *data)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_trigger_tx_message *txm =
+		&priv->spi_transmit_fifos[fifo - priv->fifos.tx_fifo_start];
+	int ret;
+
+	/* add fifo as seq */
+	obj->header.flags |= fifo << CAN_OBJ_FLAGS_SEQ_SHIFT;
+
+	/* transform to le32 */
+	mcp25xxfd_obj_to_le(&obj->header);
+
+	/* fill in details */
+	memcpy(txm->fill_obj, obj, sizeof(struct mcp25xxfd_obj_tx));
+	memset(txm->fill_data, 0, priv->fifos.payload_size);
+	memcpy(txm->fill_data, data, len);
+
+	/* transfers to FIFO RAM has to be multiple of 4 */
+	txm->fill_xfer.len =
+		2 + sizeof(struct mcp25xxfd_obj_tx) + ALIGN(len, 4);
+
+	/* and transmit asyncroniously */
+	ret = spi_async(spi, &txm->msg);
+	if (ret)
+		return NETDEV_TX_BUSY;
+
+	return NETDEV_TX_OK;
+}
+
+static int mcp25xxfd_transmit_fdmessage(struct spi_device *spi, int fifo,
+					struct canfd_frame *frame)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_obj_tx obj;
+	int dlc = can_len2dlc(frame->len);
+	u32 flags;
+
+	frame->len = can_dlc2len(dlc);
+
+	mcp25xxfd_canid_to_mcpid(frame->can_id, &obj.header.id, &flags);
+
+	flags |= dlc << CAN_OBJ_FLAGS_DLC_SHIFT;
+	flags |= (frame->can_id & CAN_EFF_FLAG) ? CAN_OBJ_FLAGS_IDE : 0;
+	flags |= (frame->can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
+	if (frame->flags & CANFD_BRS) {
+		flags |= CAN_OBJ_FLAGS_BRS;
+		priv->stats.tx_brs_count++;
+	}
+	flags |= (frame->flags & CANFD_ESI) ? CAN_OBJ_FLAGS_ESI : 0;
+	flags |= CAN_OBJ_FLAGS_FDF;
+
+	priv->stats.tx_fd_count++;
+	priv->stats.tx_dlc_usage[dlc]++;
+
+	obj.header.flags = flags;
+
+	return mcp25xxfd_transmit_message_common(spi, fifo, &obj,
+						 frame->len, frame->data);
+}
+
+static int mcp25xxfd_transmit_message(struct spi_device *spi, int fifo,
+				      struct can_frame *frame)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_obj_tx obj;
+	u32 flags;
+
+	if (frame->can_dlc > 8)
+		frame->can_dlc = 8;
+
+	priv->stats.tx_dlc_usage[frame->can_dlc]++;
+
+	mcp25xxfd_canid_to_mcpid(frame->can_id, &obj.header.id, &flags);
+
+	flags |= frame->can_dlc << CAN_OBJ_FLAGS_DLC_SHIFT;
+	flags |= (frame->can_id & CAN_EFF_FLAG) ? CAN_OBJ_FLAGS_IDE : 0;
+	flags |= (frame->can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
+
+	obj.header.flags = flags;
+
+	return mcp25xxfd_transmit_message_common(spi, fifo, &obj,
+						 frame->can_dlc, frame->data);
+}
+
+static bool mcp25xxfd_is_last_txfifo(struct spi_device *spi,
+				     int fifo)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	return (fifo ==
+		(priv->fifos.tx_fifo_start + priv->fifos.tx_fifos - 1));
+}
+
+static netdev_tx_t mcp25xxfd_start_xmit(struct sk_buff *skb,
+					struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+	u32 pending_mask;
+	int fifo;
+	int ret;
+
+	if (can_dropped_invalid_skb(net, skb))
+		return NETDEV_TX_OK;
+
+	if (priv->can.state == CAN_STATE_BUS_OFF) {
+		mcp25xxfd_stop_queue(priv->net);
+		return NETDEV_TX_BUSY;
+	}
+
+	/* get effective mask */
+	pending_mask = priv->fifos.tx_pending_mask |
+		priv->fifos.tx_submitted_mask;
+
+	/* decide on fifo to assign */
+	if (pending_mask)
+		fifo = fls(pending_mask);
+	else
+		fifo = priv->fifos.tx_fifo_start;
+
+	/* handle error - this should not happen... */
+	if (fifo >= priv->fifos.tx_fifo_start + priv->fifos.tx_fifos) {
+		dev_err(&spi->dev,
+			"reached tx-fifo %i, which is not valid\n",
+			fifo);
+		return NETDEV_TX_BUSY;
+	}
+
+	/* if we are the last one, then stop the queue */
+	if (mcp25xxfd_is_last_txfifo(spi, fifo))
+		mcp25xxfd_stop_queue(priv->net);
+
+	/* mark as submitted */
+	priv->fifos.tx_submitted_mask |= BIT(fifo);
+	priv->stats.fifo_usage[fifo]++;
+
+	/* now process it for real */
+	if (can_is_canfd_skb(skb))
+		ret = mcp25xxfd_transmit_fdmessage(spi, fifo,
+						   (struct canfd_frame *)
+						   skb->data);
+	else
+		ret = mcp25xxfd_transmit_message(spi, fifo,
+						 (struct can_frame *)
+						 skb->data);
+
+	/* keep it for reference until the message really got transmitted */
+	if (ret == NETDEV_TX_OK)
+		can_put_echo_skb(skb, priv->net, fifo);
+
+	return ret;
+}
+
+/* CAN RX Related */
+
+static int mcp25xxfd_can_transform_rx_fd(struct spi_device *spi,
+					 struct mcp25xxfd_obj_rx *rx)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct canfd_frame *frame;
+	struct sk_buff *skb;
+	u32 flags = rx->header.flags;
+	int dlc;
+
+	/* allocate the skb buffer */
+	skb = alloc_canfd_skb(priv->net, &frame);
+	if (!skb) {
+		dev_err(&spi->dev, "cannot allocate RX skb\n");
+		priv->net->stats.rx_dropped++;
+		return -ENOMEM;
+	}
+
+	mcp25xxfd_mcpid_to_canid(rx->header.id, flags, &frame->can_id);
+	frame->flags |= (flags & CAN_OBJ_FLAGS_BRS) ? CANFD_BRS : 0;
+	frame->flags |= (flags & CAN_OBJ_FLAGS_ESI) ? CANFD_ESI : 0;
+
+	dlc = (flags & CAN_OBJ_FLAGS_DLC_MASK) >> CAN_OBJ_FLAGS_DLC_SHIFT;
+	frame->len = can_dlc2len(dlc);
+
+	memcpy(frame->data, rx->data, frame->len);
+
+	priv->stats.rx_fd_count++;
+	priv->net->stats.rx_packets++;
+	priv->net->stats.rx_bytes += frame->len;
+	if (rx->header.flags & CAN_OBJ_FLAGS_BRS)
+		priv->stats.rx_brs_count++;
+	priv->stats.rx_dlc_usage[dlc]++;
+
+	can_led_event(priv->net, CAN_LED_EVENT_RX);
+
+	netif_rx_ni(skb);
+
+	return 0;
+}
+
+static int mcp25xxfd_can_transform_rx_normal(struct spi_device *spi,
+					     struct mcp25xxfd_obj_rx *rx)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct sk_buff *skb;
+	struct can_frame *frame;
+	u32 flags = rx->header.flags;
+	int len;
+	int dlc;
+
+	/* allocate the skb buffer */
+	skb = alloc_can_skb(priv->net, &frame);
+	if (!skb) {
+		dev_err(&spi->dev, "cannot allocate RX skb\n");
+		priv->net->stats.rx_dropped++;
+		return -ENOMEM;
+	}
+
+	mcp25xxfd_mcpid_to_canid(rx->header.id, flags, &frame->can_id);
+
+	dlc = (flags & CAN_OBJ_FLAGS_DLC_MASK) >> CAN_OBJ_FLAGS_DLC_SHIFT;
+	frame->can_dlc = dlc;
+
+	len = can_dlc2len(frame->can_dlc);
+
+	memcpy(frame->data, rx->data, len);
+
+	priv->net->stats.rx_packets++;
+	priv->net->stats.rx_bytes += len;
+	priv->stats.rx_dlc_usage[dlc]++;
+
+	can_led_event(priv->net, CAN_LED_EVENT_RX);
+
+	netif_rx_ni(skb);
+
+	return 0;
+}
+
+static int mcp25xxfd_process_queued_rx(struct spi_device *spi,
+				       struct mcp25xxfd_obj_ts *obj)
+{
+	struct mcp25xxfd_obj_rx *rx = container_of(obj,
+						   struct mcp25xxfd_obj_rx,
+						   header);
+
+	if (obj->flags & CAN_OBJ_FLAGS_FDF)
+		return mcp25xxfd_can_transform_rx_fd(spi, rx);
+	else
+		return mcp25xxfd_can_transform_rx_normal(spi, rx);
+}
+
+static int mcp25xxfd_normal_release_fifos(struct spi_device *spi,
+					  int start, int end)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int ret;
+
+	/* release each fifo in a separate transfer */
+	for (; start < end ; start++) {
+		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FIFOCON(start),
+					       CAN_FIFOCON_UINC,
+					       CAN_FIFOCON_UINC,
+					       priv->spi_speed_hz);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* unfortunately the CAN_FIFOCON are not directly consecutive
+ * so the optimization of "clearing all in one spi_transfer"
+ * would produce an overhead of 11 unnecessary bytes/fifo
+ * - transferring 14 (2 cmd + 12 data) bytes
+ * instead of just 3 (2 + 1).
+ * On some slower systems this may still be beneficial,
+ * but it is not good enough for the generic case.
+ * On a Raspberry Pi CM the timings for clearing 3 fifos
+ * (at 12.5MHz SPI clock speed) are:
+ * * normal:
+ *   * 3 spi transfers
+ *   * 9 bytes total
+ *   * 36.74us from first CS low to last CS high
+ *   * individual CS: 9.14us, 5.74us and 5.16us
+ *   * 77.02us from CS up of fifo transfer to last release CS up
+ * * bulk:
+ *   * 1 spi transfer
+ *   * 27 bytes total
+ *   * 29.06us CS Low
+ *   * 78.28us from CS up of fifo transfer to last release CS up
+ * this obviously varies with SPI_clock speed
+ * - the slower the clock the less efficient the optimization.
+ * similarly the faster the CPU (and bigger the code cache) the
+ * less effcient the optimization - the above case is border line.
+ */
+
+#define FIFOCON_SPACING (CAN_FIFOCON(1) - CAN_FIFOCON(0))
+#define FIFOCON_SPACINGW (FIFOCON_SPACING / sizeof(u32))
+
+static int mcp25xxfd_bulk_release_fifos(struct spi_device *spi,
+					int start, int end)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int i;
+	int ret;
+
+	/* calculate start address and length */
+	int fifos = end - start;
+	int first_byte = mcp25xxfd_first_byte(CAN_FIFOCON_UINC);
+	int addr = CAN_FIFOCON(start);
+	int len = 1 + (fifos - 1) * FIFOCON_SPACING;
+
+	/* the worsted case buffer */
+	u32 buf[32 * FIFOCON_SPACINGW], base;
+
+	base = (priv->fifos.payload_mode << CAN_FIFOCON_PLSIZE_SHIFT) |
+		((priv->fifos.rx_fifo_depth - 1) << CAN_FIFOCON_FSIZE_SHIFT) |
+		CAN_FIFOCON_RXTSEN | /* RX timestamps */
+		CAN_FIFOCON_UINC |
+		CAN_FIFOCON_TFERFFIE | /* FIFO Full */
+		CAN_FIFOCON_TFHRFHIE | /* FIFO Half Full*/
+		CAN_FIFOCON_TFNRFNIE; /* FIFO not empty */
+
+	memset(buf, 0, sizeof(buf));
+	for (i = 0; i < end - start ; i++) {
+		if (i == priv->fifos.rx_fifos - 1)
+			base |= CAN_FIFOCON_RXOVIE;
+		buf[FIFOCON_SPACINGW * i] = cpu_to_le32(base);
+	}
+
+	ret = mcp25xxfd_cmd_writen(spi, addr + first_byte,
+				   (u8 *)buf + first_byte,
+				   len,
+				   priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* queued FIFO handling for release to system */
+
+static void mcp25xxfd_clear_queued_fifos(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* prepare rfi - mostly used for sorting */
+	priv->queued_fifos.rx_count = 0;
+}
+
+static void mcp25xxfd_addto_queued_fifos(struct spi_device *spi,
+					 struct mcp25xxfd_obj_ts *obj)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_read_fifo_info *rfi = &priv->queued_fifos;
+
+	/* timestamps must ignore the highest byte, so we shift it,
+	 * so that it still compares correctly
+	 */
+	obj->ts <<= 8;
+
+	/* add pointer to queued array-list */
+	rfi->rxb[rfi->rx_count] = obj;
+	rfi->rx_count++;
+}
+
+static int mcp25xxfd_process_queued_tef(struct spi_device *spi,
+					struct mcp25xxfd_obj_ts *obj)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_obj_tef *tef = container_of(obj,
+						     struct mcp25xxfd_obj_tef,
+						     header);
+	int dlc = (obj->flags & CAN_OBJ_FLAGS_DLC_MASK)
+		>> CAN_OBJ_FLAGS_DLC_SHIFT;
+	int fifo = (tef->header.flags & CAN_OBJ_FLAGS_SEQ_MASK) >>
+		CAN_OBJ_FLAGS_SEQ_SHIFT;
+
+	/* update counters */
+	priv->net->stats.tx_packets++;
+	priv->net->stats.tx_bytes += can_dlc2len(dlc);
+	if (obj->flags & CAN_OBJ_FLAGS_FDF)
+		priv->stats.tx_fd_count++;
+	if (obj->flags & CAN_OBJ_FLAGS_BRS)
+		priv->stats.tx_brs_count++;
+	priv->stats.tx_dlc_usage[dlc]++;
+
+	/* release it */
+	can_get_echo_skb(priv->net, fifo);
+
+	can_led_event(priv->net, CAN_LED_EVENT_TX);
+
+	return 0;
+}
+
+static int mcp25xxfd_compare_obj_ts(const void *a, const void *b)
+{
+	const struct mcp25xxfd_obj_ts * const *rxa = a;
+	const struct mcp25xxfd_obj_ts * const *rxb = b;
+	/* using signed here to handle rollover correctly */
+	s32 ats = (*rxa)->ts;
+	s32 bts = (*rxb)->ts;
+
+	if (ats < bts)
+		return -EINVAL;
+	if (ats > bts)
+		return 1;
+	return 0;
+}
+
+static int mcp25xxfd_process_queued_fifos(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_read_fifo_info *rfi = &priv->queued_fifos;
+	int i;
+	int ret;
+
+	/* sort the fifos (rx and TEF) by receive timestamp */
+	sort(rfi->rxb, rfi->rx_count, sizeof(struct mcp25xxfd_obj_ts *),
+	     mcp25xxfd_compare_obj_ts, NULL);
+
+	/* process the recived fifos */
+	for (i = 0; i < rfi->rx_count ; i++) {
+		if (rfi->rxb[i]->flags & CAN_OBJ_FLAGS_CUSTOM_ISTEF)
+			ret = mcp25xxfd_process_queued_tef(spi, rfi->rxb[i]);
+		else
+			ret = mcp25xxfd_process_queued_rx(spi, rfi->rxb[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* clear queued fifos */
+	mcp25xxfd_clear_queued_fifos(spi);
+
+	return 0;
+}
+
+static int mcp25xxfd_transform_rx(struct spi_device *spi,
+				  struct mcp25xxfd_obj_rx *rx)
+{
+	int dlc;
+
+	/* transform the data to system byte order */
+	mcp25xxfd_obj_ts_from_le(&rx->header);
+
+	/* add the object to the list */
+	mcp25xxfd_addto_queued_fifos(spi, &rx->header);
+
+	/* calc length and return it */
+	dlc = (rx->header.flags & CAN_OBJ_FLAGS_DLC_MASK)
+		>> CAN_OBJ_FLAGS_DLC_SHIFT;
+	return can_dlc2len(dlc);
+}
+
+/* read_fifo implementations
+ *
+ * read_fifos is a simple implementation, that:
+ *   * loops all fifos
+ *     * read header + some data-bytes (8)
+ *     * read rest of data-bytes bytes
+ *     * release fifo
+ *   for 3 can frames dlc<=8 to read here we have:
+ *     * 6 spi transfers
+ *     * 75 bytes (= 3 * (2 + 12 + 8) bytes + 3 * 3 bytes)
+ *   for 3 canfd frames dlc>8 to read here we have:
+ *     * 9 spi transfers
+ *     * 81 (= 3 * (2 + 12 + 8 + 2) bytes + 3 * 3 bytes) + 3 * extra payload
+ *     this only transfers the required size of bytes on the spi bus.
+ *
+ * bulk_read_fifos is an optimization that is most practical for
+ * Can2.0 busses, but may also be practical for CanFD busses that
+ * have a high average payload data size.
+ *
+ * It will read all of the fifo data in a single spi_transfer:
+ *   * read all fifos in one go (as long as these are ajacent to each other)
+ *   * loop all fifos
+ *     * release fifo
+ *   for 3 can2.0 frames to read here we have:
+ *     * 4 spi transfers
+ *     * 71 bytes (= 2 + 3 * (12 + 8) bytes + 3 * 3 bytes)
+ *   for 3 canfd frames to read here we have:
+ *     * 4 spi transfers
+ *     * 230 bytes (= 2 + 3 * (12 + 64) bytes)
+ *     obviously this reads way too many bytes for framesizes <=32 bytes,
+ *     but it avoids the overhead on the CPU side and may even trigger
+ *     DMA transfers due to the high byte count, which release CPU cycles.
+ *
+ * This optimization will also be efficient for cases where a high
+ * percentage of canFD frames has a dlc-size > 8.
+ * This mode is used for Can2.0 configured busses.
+ *
+ * For now this option can get forced for CanFD via a module parameter.
+ * In the future there may be some heuristics that could trigger a usage
+ * of this mode as well in some circumstances.
+ *
+ * Note: there is a second optimization for release fifo as well,
+ *       but it is not as efficient as this optimization for the
+ *       non-CanFD case - see mcp25xxfd_bulk_release_fifos
+ */
+
+static int mcp25xxfd_read_fifos(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int fifo_header_size = sizeof(struct mcp25xxfd_obj_rx);
+	int fifo_min_payload_size = 8;
+	int fifo_min_size = fifo_header_size + fifo_min_payload_size;
+	int fifo_max_payload_size =
+		((priv->can.ctrlmode & CAN_CTRLMODE_FD) ? 64 : 8);
+	u32 mask = priv->status.rxif;
+	struct mcp25xxfd_obj_rx *rx;
+	int i, len;
+	int ret;
+	u32 fifo_address;
+	u8 *data;
+
+	/* read all the "open" segments in big chunks */
+	for (i = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
+	     i >= priv->fifos.rx_fifo_start;
+	     i--) {
+		if (!(mask & BIT(i)))
+			continue;
+		/* the fifo to fill */
+		rx = (struct mcp25xxfd_obj_rx *)
+			(priv->fifos.fifo_data + priv->fifos.fifo_address[i]);
+		/* read the minimal payload */
+		fifo_address = priv->fifos.fifo_address[i];
+		ret = mcp25xxfd_cmd_readn(spi,
+					  FIFO_DATA(fifo_address),
+					  rx,
+					  fifo_min_size,
+					  priv->spi_speed_hz);
+		if (ret)
+			return ret;
+		/* process fifo stats and get length */
+		len = min_t(int, mcp25xxfd_transform_rx(spi, rx),
+			    fifo_max_payload_size);
+
+		/* read extra payload if needed */
+		if (len > fifo_min_payload_size) {
+			data = &rx->data[fifo_min_payload_size];
+			ret = mcp25xxfd_cmd_readn(spi,
+						  FIFO_DATA(fifo_address +
+							    fifo_min_size),
+						  data,
+						  len - fifo_min_payload_size,
+						  priv->spi_speed_hz);
+			if (ret)
+				return ret;
+		}
+		/* release fifo */
+		ret = mcp25xxfd_normal_release_fifos(spi, i, i + 1);
+		if (ret)
+			return ret;
+		/* increment fifo_usage */
+		priv->stats.fifo_usage[i]++;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_bulk_read_fifo_range(struct spi_device *spi,
+					  int start, int end)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	const int fifo_header_size = sizeof(struct mcp25xxfd_obj_rx);
+	const int fifo_max_payload_size = priv->fifos.payload_size;
+	const int fifo_max_size = fifo_header_size + fifo_max_payload_size;
+	struct mcp25xxfd_obj_rx *rx;
+	int i;
+	int ret;
+
+	/* now we got start and end, so read the range */
+	ret = mcp25xxfd_cmd_readn(spi,
+				  FIFO_DATA(priv->fifos.fifo_address[start]),
+				  priv->fifos.fifo_data +
+				  priv->fifos.fifo_address[start],
+				  (end - start) * fifo_max_size,
+				  priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	/* clear all the fifos in range */
+	if (use_bulk_release_fifos)
+		ret = mcp25xxfd_bulk_release_fifos(spi, start, end);
+	else
+		ret = mcp25xxfd_normal_release_fifos(spi, start, end);
+	if (ret)
+		return ret;
+
+	/* preprocess data */
+	for (i = start; i < end ; i++) {
+		/* store the fifo to process */
+		rx = (struct mcp25xxfd_obj_rx *)
+			(priv->fifos.fifo_data + priv->fifos.fifo_address[i]);
+		/* process fifo stats */
+		mcp25xxfd_transform_rx(spi, rx);
+		/* increment usage */
+		priv->stats.fifo_usage[i]++;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_bulk_read_fifos(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 mask = priv->status.rxif;
+	int i, start, end;
+	int ret;
+
+	/* find blocks of set bits top down */
+	for (i = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
+	     mask && (i >= priv->fifos.rx_fifo_start);
+	     i--) {
+		/* if the bit is 0 then continue loop to find a 1 */
+		if ((mask & BIT(i)) == 0)
+			continue;
+
+		/* so we found a non-0 bit - this is start and end */
+		start = i;
+		end = i;
+
+		/* find the first bit set */
+		for (; mask & BIT(i); i--) {
+			mask &= ~BIT(i);
+			start = i;
+		}
+
+		/* now process that range */
+		ret = mcp25xxfd_bulk_read_fifo_range(spi, start, end + 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_rxif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 mask = priv->status.rxif;
+	int ret;
+
+	if (!mask)
+		return 0;
+
+	/* read all the fifos - for non-fd case use bulk read optimization */
+	if (((priv->can.ctrlmode & CAN_CTRLMODE_FD) == 0) ||
+	    use_complete_fdfifo_read)
+		ret = mcp25xxfd_bulk_read_fifos(spi);
+	else
+		ret = mcp25xxfd_read_fifos(spi);
+
+	return 0;
+}
+
+static void mcp25xxfd_mark_tx_processed(struct spi_device *spi,
+					int fifo)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* set mask */
+	priv->fifos.tx_processed_mask |= BIT(fifo);
+
+	/* check if we should reenable the TX-queue */
+	if (mcp25xxfd_is_last_txfifo(spi, fifo))
+		priv->tx_queue_status = TX_QUEUE_STATUS_NEEDS_START;
+}
+
+static int mcp25xxfd_can_ist_handle_tefif_handle_single(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct mcp25xxfd_obj_tef *tef;
+	int fifo;
+	int ret;
+
+	/* calc address in address space */
+	tef = (struct mcp25xxfd_obj_tef *)(priv->fifos.fifo_data +
+					   priv->fifos.tef_address);
+
+	/* read all the object data */
+	ret = mcp25xxfd_cmd_readn(spi,
+				  FIFO_DATA(priv->fifos.tef_address),
+				  tef,
+				  /* we do not read the last byte of the ts
+				   * to avoid MAB issiues
+				   */
+				  sizeof(*tef) - 1,
+				  priv->spi_speed_hz);
+	/* increment the counter to read next */
+	ret = mcp25xxfd_cmd_write_mask(spi,
+				       CAN_TEFCON,
+				       CAN_TEFCON_UINC,
+				       CAN_TEFCON_UINC,
+				       priv->spi_speed_hz);
+
+	/* transform the data to system byte order */
+	mcp25xxfd_obj_ts_from_le(&tef->header);
+
+	fifo = (tef->header.flags & CAN_OBJ_FLAGS_SEQ_MASK) >>
+		CAN_OBJ_FLAGS_SEQ_SHIFT;
+
+	/* submit to queue */
+	tef->header.flags |= CAN_OBJ_FLAGS_CUSTOM_ISTEF;
+	mcp25xxfd_addto_queued_fifos(spi, &tef->header);
+
+	/* increment tef_address with rollover */
+	priv->fifos.tef_address += sizeof(*tef);
+	if (priv->fifos.tef_address > priv->fifos.tef_address_end)
+		priv->fifos.tef_address =
+			priv->fifos.tef_address_start;
+
+	/* and mark as processed right now */
+	mcp25xxfd_mark_tx_processed(spi, fifo);
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_tefif_conservative(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 val[2];
+	int ret;
+
+	while (1) {
+		/* get the current TEFSTA and TEFUA */
+		ret = mcp25xxfd_cmd_readn(priv->spi,
+					  CAN_TEFSTA,
+					  val,
+					  8,
+					  priv->spi_speed_hz);
+		if (ret)
+			return ret;
+		mcp25xxfd_convert_to_cpu(val, 2);
+
+		/* check for interrupt flags */
+		if (!(val[0] & CAN_TEFSTA_TEFNEIF))
+			return 0;
+
+		if (priv->fifos.tef_address != val[1]) {
+			dev_err(&spi->dev,
+				"TEF Address mismatch - read: %04x calculated: %04x\n",
+				val[1], priv->fifos.tef_address);
+			priv->fifos.tef_address = val[1];
+		}
+
+		ret = mcp25xxfd_can_ist_handle_tefif_handle_single(spi);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_tefif_count(struct spi_device *spi,
+						int count)
+{
+	int i;
+	int ret;
+
+	/* now clear TEF for each */
+	/* TODO: optimize for BULK reads, as we (hopefully) know COUNT */
+	for (i = 0; i < count; i++) {
+		/* handle a single TEF */
+		ret = mcp25xxfd_can_ist_handle_tefif_handle_single(spi);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_tefif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 pending = priv->fifos.tx_pending_mask_in_irq &
+		(~priv->fifos.tx_processed_mask);
+	int count;
+
+	/* calculate the number of fifos that have been processed */
+	count = hweight_long(pending);
+	count -= hweight_long(priv->status.txreq & pending);
+
+	/* in case of unexpected results handle "safely" */
+	if (count <= 0)
+		return mcp25xxfd_can_ist_handle_tefif_conservative(spi);
+
+	return mcp25xxfd_can_ist_handle_tefif_count(spi, count);
+}
+
+static int mcp25xxfd_can_ist_handle_txatif_fifo(struct spi_device *spi,
+						int fifo)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 val;
+	int ret;
+
+	/* read fifo status */
+	ret = mcp25xxfd_cmd_read(spi,
+				 CAN_FIFOSTA(fifo),
+				 &val,
+				 priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	/* clear the relevant interrupt flags */
+	ret = mcp25xxfd_cmd_write_mask(spi,
+				       CAN_FIFOSTA(fifo),
+				       0,
+				       CAN_FIFOSTA_TXABT |
+				       CAN_FIFOSTA_TXLARB |
+				       CAN_FIFOSTA_TXERR |
+				       CAN_FIFOSTA_TXATIF,
+				       priv->spi_speed_hz);
+
+	/* for specific cases we could trigger a retransmit
+	 * instead of an abort.
+	 */
+
+	/* and we release it from the echo_skb buffer
+	 * NOTE: this is one place where packet delivery will not
+	 * be ordered, as we do not have any timing information
+	 * when this occurred
+	 */
+	can_get_echo_skb(priv->net, fifo);
+
+	/* but we need to run a bit of cleanup */
+	priv->status.txif &= ~BIT(fifo);
+	priv->net->stats.tx_aborted_errors++;
+
+	/* mark the fifo as processed */
+	 mcp25xxfd_mark_tx_processed(spi, fifo);
+
+	/* handle all the known cases accordingly - ignoring FIFO full */
+	val &= CAN_FIFOSTA_TXABT |
+		CAN_FIFOSTA_TXLARB |
+		CAN_FIFOSTA_TXERR;
+	switch (val) {
+	case CAN_FIFOSTA_TXERR:
+		break;
+	default:
+		dev_warn_ratelimited(&spi->dev,
+				     "Unknown TX-Fifo abort condition: %08x - stopping tx-queue\n",
+				     val);
+		break;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_txatif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int i, fifo;
+	int ret;
+
+	/* process all the fifos with that flag set */
+	for (i = 0, fifo = priv->fifos.tx_fifo_start;
+	    i < priv->fifos.tx_fifos; i++, fifo++) {
+		if (priv->status.txatif & BIT(fifo)) {
+			ret = mcp25xxfd_can_ist_handle_txatif_fifo(spi, fifo);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void mcp25xxfd_error_skb(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct sk_buff *skb;
+	struct can_frame *frame;
+
+	skb = alloc_can_err_skb(net, &frame);
+	if (skb) {
+		frame->can_id = priv->can_err_id;
+		memcpy(frame->data, priv->can_err_data, 8);
+		netif_rx_ni(skb);
+	} else {
+		netdev_err(net, "cannot allocate error skb\n");
+	}
+}
+
+static int mcp25xxfd_can_ist_handle_rxovif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 mask = priv->status.rxovif;
+	int i;
+	int ret;
+
+	/* clear all fifos that have an overflow bit set */
+	for (i = 0; i < 32; i++) {
+		if (mask & BIT(i)) {
+			ret = mcp25xxfd_cmd_write_mask(spi,
+						       CAN_FIFOSTA(i),
+						       0,
+						       CAN_FIFOSTA_RXOVIF,
+						       priv->spi_speed_hz);
+			if (ret)
+				return ret;
+			/* update statistics */
+			priv->net->stats.rx_over_errors++;
+			priv->net->stats.rx_errors++;
+			priv->stats.rx_overflow++;
+			priv->can_err_id |= CAN_ERR_CRTL;
+			priv->can_err_data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+		}
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_modif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int omode = priv->active_can_mode;
+	int mode;
+	int ret;
+
+	/* Note that this irq does not get triggered in all situations
+	 * for example SERRIF will move to RESTICTED or LISTENONLY
+	 * but MODIF will not be raised!
+	 */
+
+	/* get the mode */
+	ret = mcp25xxfd_get_opmode(spi, &mode, priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	/* if we are restricted, then return to "normal" mode */
+	if (mode == CAN_CON_MODE_RESTRICTED)
+		return mcp25xxfd_set_normal_opmode(spi);
+
+	/* the controller itself will transition to sleep, so we ignore it */
+	if (mode == CAN_CON_MODE_SLEEP)
+		return 0;
+
+	/* switches to the same mode as before are also ignored
+	 * - this typically happens if the driver is shortly
+	 *   switching to a different mode and then returning to the
+	 *   original mode
+	 */
+	if (mode == omode)
+		return 0;
+
+	/* these we need to handle correctly, so warn and give context */
+	dev_warn(&spi->dev,
+		 "Controller unexpectedly switched from mode %s(%u) to %s(%u)\n",
+		 mcp25xxfd_mode_names[omode], omode,
+		 mcp25xxfd_mode_names[mode], mode);
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_cerrif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* in principle we could also delay reading bdiag registers
+	 * until we get here - it would add some extra delay in the
+	 * error case, but be slightly faster in the "normal" case.
+	 * slightly faster would be saving 8 bytes of spi transfer.
+	 */
+
+	dev_err_ratelimited(&spi->dev, "CAN Bus error\n");
+	priv->can_err_id |= CAN_ERR_BUSERROR;
+
+	if (priv->status.bdiag1 &
+	    (CAN_BDIAG1_DBIT0ERR | CAN_BDIAG1_NBIT0ERR)) {
+		priv->can_err_id |= CAN_ERR_BUSERROR;
+		priv->can_err_data[2] |= CAN_ERR_PROT_BIT0;
+		priv->bdiag1_clear_mask |= CAN_BDIAG1_DBIT0ERR |
+			CAN_BDIAG1_NBIT0ERR;
+	}
+	if (priv->status.bdiag1 &
+	    (CAN_BDIAG1_DBIT1ERR | CAN_BDIAG1_NBIT1ERR)) {
+		priv->can_err_id |= CAN_ERR_BUSERROR;
+		priv->can_err_data[2] |= CAN_ERR_PROT_BIT1;
+		priv->bdiag1_clear_mask |= CAN_BDIAG1_DBIT1ERR |
+			CAN_BDIAG1_NBIT1ERR;
+	}
+	if (priv->status.bdiag1 &
+	    (CAN_BDIAG1_DSTUFERR | CAN_BDIAG1_NSTUFERR)) {
+		priv->can_err_id |= CAN_ERR_BUSERROR;
+		priv->can_err_data[2] |= CAN_ERR_PROT_STUFF;
+		priv->bdiag1_clear_mask |= CAN_BDIAG1_DSTUFERR |
+			CAN_BDIAG1_NSTUFERR;
+	}
+	if (priv->status.bdiag1 &
+	    (CAN_BDIAG1_DFORMERR | CAN_BDIAG1_NFORMERR)) {
+		priv->can_err_id |= CAN_ERR_BUSERROR;
+		priv->can_err_data[2] |= CAN_ERR_PROT_FORM;
+		priv->bdiag1_clear_mask |= CAN_BDIAG1_DFORMERR |
+			CAN_BDIAG1_NFORMERR;
+	}
+	if (priv->status.bdiag1 & CAN_BDIAG1_NACKERR) {
+		priv->can_err_id |= CAN_ERR_ACK;
+		priv->bdiag1_clear_mask |= CAN_BDIAG1_NACKERR;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_eccif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int ret;
+	u32 val;
+	u32 addr;
+
+	priv->can_err_id |= CAN_ERR_CRTL;
+	priv->can_err_data[1] |= CAN_ERR_CRTL_UNSPEC;
+
+	/* read ECC status register */
+	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_ECCSTAT, &val,
+				 priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	addr = (val & MCP25XXFD_ECCSTAT_ERRADDR_MASK) >>
+		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT;
+
+	dev_err_ratelimited(&spi->dev,
+			    "ECC %s bit error at %03x\n",
+			    (val & MCP25XXFD_ECCSTAT_DEDIF) ?
+			    "double" : "single",
+			    addr);
+
+	return mcp25xxfd_cmd_write(spi, MCP25XXFD_ECCSTAT, 0,
+				 priv->spi_speed_hz);
+}
+
+static int mcp25xxfd_can_ist_handle_serrif_txmab(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	priv->net->stats.tx_fifo_errors++;
+	priv->net->stats.tx_errors++;
+	priv->stats.tx_mab++;
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_serrif_rxmab(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	priv->net->stats.rx_dropped++;
+	priv->net->stats.rx_errors++;
+	priv->stats.rx_mab++;
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_serrif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 clear;
+	int ret;
+
+	/* clear some interrupts immediately,
+	 * so that we get notified if they happen again
+	 */
+	clear = CAN_INT_SERRIF | CAN_INT_MODIF | CAN_INT_IVMIF;
+	ret = mcp25xxfd_cmd_write_mask(spi, CAN_INT,
+				       priv->status.intf & (~clear),
+				       clear,
+				       priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	/* Errors here are:
+	 * * Bus Bandwidth Error: when a RX Message Assembly Buffer
+	 *   is still full when the next message has already arrived
+	 *   the recived message shall be ignored
+	 * * TX MAB Underflow: when a TX Message is invalid
+	 *   due to ECC errors or TXMAB underflow
+	 *   in this situatioon the system will transition to
+	 *   Restricted or Listen Only mode
+	 */
+
+	priv->can_err_id |= CAN_ERR_CRTL;
+	priv->can_err_data[1] |= CAN_ERR_CRTL_UNSPEC;
+
+	/* a mode change + invalid message would indicate
+	 * TX MAB Underflow
+	 */
+	if ((priv->status.intf & CAN_INT_MODIF) &&
+	    (priv->status.intf & CAN_INT_IVMIF)) {
+		return mcp25xxfd_can_ist_handle_serrif_txmab(spi);
+	}
+
+	/* for RX there is only the RXIF an indicator
+	 * - surprizingly RX-MAB does not change mode or anything
+	 */
+	if (priv->status.intf & CAN_INT_RXIF)
+		return mcp25xxfd_can_ist_handle_serrif_rxmab(spi);
+
+	/* the final case */
+	dev_warn_ratelimited(&spi->dev,
+			     "unidentified system error - intf =  %08x\n",
+			     priv->status.intf);
+
+	return 0;
+}
+
+static int mcp25xxfd_can_ist_handle_ivmif(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* if we have a systemerror as well, then ignore it */
+	if (priv->status.intf & CAN_INT_SERRIF)
+		return 0;
+
+	/* otherwise it is an RX issue, so account for it here */
+	priv->can_err_id |= CAN_ERR_PROT;
+	priv->can_err_data[2] |= CAN_ERR_PROT_FORM;
+	priv->net->stats.rx_frame_errors++;
+	priv->net->stats.rx_errors++;
+
+	return 0;
+}
+
+static int mcp25xxfd_disable_interrupts(struct spi_device *spi,
+					u32 speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	priv->status.intf = 0;
+	return mcp25xxfd_cmd_write(spi, CAN_INT, 0, speed_hz);
+}
+
+static int mcp25xxfd_enable_interrupts(struct spi_device *spi,
+				       u32 speed_hz)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	priv->status.intf = CAN_INT_TEFIE |
+		CAN_INT_RXIE |
+		CAN_INT_MODIE |
+		CAN_INT_SERRIE |
+		CAN_INT_IVMIE |
+		CAN_INT_CERRIE |
+		CAN_INT_RXOVIE |
+		CAN_INT_ECCIE;
+	return mcp25xxfd_cmd_write(spi, CAN_INT,
+				   priv->status.intf,
+				   speed_hz);
+}
+
+static int mcp25xxfd_hw_wake(struct spi_device *spi)
+{
+	return mcp25xxfd_start_clock(spi, MCP25XXFD_CLK_USER_CAN);
+}
+
+static void mcp25xxfd_hw_sleep(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	/* disable interrupts */
+	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
+
+	/* stop the clocks */
+	mcp25xxfd_stop_clock(spi, MCP25XXFD_CLK_USER_CAN);
+}
+
+static int mcp25xxfd_can_ist_handle_status(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	const u32 clear_irq = CAN_INT_TBCIF |
+		CAN_INT_MODIF |
+		CAN_INT_SERRIF |
+		CAN_INT_CERRIF |
+		CAN_INT_WAKIF |
+		CAN_INT_IVMIF;
+	int ret;
+
+	/* clear all the interrupts asap */
+	ret = mcp25xxfd_cmd_write_mask(spi, CAN_INT,
+				       priv->status.intf & (~clear_irq),
+				       clear_irq,
+				       priv->spi_speed_hz);
+	if (ret)
+		return ret;
+
+	/* interrupt clearing info */
+	priv->bdiag1_clear_value = 0;
+	priv->bdiag1_clear_mask = 0;
+	priv->can_err_id = 0;
+	memset(priv->can_err_data, 0, 8);
+
+	/* state changes */
+	priv->new_state = priv->can.state;
+
+	/* clear queued fifos */
+	mcp25xxfd_clear_queued_fifos(spi);
+
+	/* system error interrupt needs to get handled first
+	 * to get us out of restricted mode
+	 */
+	if (priv->status.intf & CAN_INT_SERRIF) {
+		priv->stats.int_serr_count++;
+		ret = mcp25xxfd_can_ist_handle_serrif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* mode change interrupt */
+	if (priv->status.intf & CAN_INT_MODIF) {
+		priv->stats.int_mod_count++;
+		ret = mcp25xxfd_can_ist_handle_modif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* handle the rx */
+	if (priv->status.intf & CAN_INT_RXIF) {
+		priv->stats.int_rx_count++;
+		ret = mcp25xxfd_can_ist_handle_rxif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* handle aborted TX FIFOs */
+	if (priv->status.txatif) {
+		priv->stats.int_txat_count++;
+		ret = mcp25xxfd_can_ist_handle_txatif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* handle the tef */
+	if (priv->status.intf & CAN_INT_TEFIF) {
+		priv->stats.int_tef_count++;
+		ret = mcp25xxfd_can_ist_handle_tefif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* process the queued fifos */
+	ret = mcp25xxfd_process_queued_fifos(spi);
+
+	/* handle error interrupt flags */
+	if (priv->status.rxovif) {
+		priv->stats.int_rxov_count++;
+		ret = mcp25xxfd_can_ist_handle_rxovif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* sram ECC error interrupt */
+	if (priv->status.intf & CAN_INT_ECCIF) {
+		priv->stats.int_ecc_count++;
+		ret = mcp25xxfd_can_ist_handle_eccif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* message format interrupt */
+	if (priv->status.intf & CAN_INT_IVMIF) {
+		priv->stats.int_ivm_count++;
+		ret = mcp25xxfd_can_ist_handle_ivmif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* handle bus errors in more detail */
+	if (priv->status.intf & CAN_INT_CERRIF) {
+		priv->stats.int_cerr_count++;
+		ret = mcp25xxfd_can_ist_handle_cerrif(spi);
+		if (ret)
+			return ret;
+	}
+
+	/* Error counter handling */
+	if (priv->status.trec & CAN_TREC_TXWARN) {
+		priv->new_state = CAN_STATE_ERROR_WARNING;
+		priv->can_err_id |= CAN_ERR_CRTL;
+		priv->can_err_data[1] |= CAN_ERR_CRTL_TX_WARNING;
+	}
+	if (priv->status.trec & CAN_TREC_RXWARN) {
+		priv->new_state = CAN_STATE_ERROR_WARNING;
+		priv->can_err_id |= CAN_ERR_CRTL;
+		priv->can_err_data[1] |= CAN_ERR_CRTL_RX_WARNING;
+	}
+	if (priv->status.trec & CAN_TREC_TXBP) {
+		priv->new_state = CAN_STATE_ERROR_PASSIVE;
+		priv->can_err_id |= CAN_ERR_CRTL;
+		priv->can_err_data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+	}
+	if (priv->status.trec & CAN_TREC_RXBP) {
+		priv->new_state = CAN_STATE_ERROR_PASSIVE;
+		priv->can_err_id |= CAN_ERR_CRTL;
+		priv->can_err_data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+	}
+	if (priv->status.trec & CAN_TREC_TXBO) {
+		priv->new_state = CAN_STATE_BUS_OFF;
+		priv->can_err_id |= CAN_ERR_BUSOFF;
+	}
+
+	/* based on the last state state check the new state */
+	switch (priv->can.state) {
+	case CAN_STATE_ERROR_ACTIVE:
+		if (priv->new_state >= CAN_STATE_ERROR_WARNING &&
+		    priv->new_state <= CAN_STATE_BUS_OFF)
+			priv->can.can_stats.error_warning++;
+		/* fallthrough */
+	case CAN_STATE_ERROR_WARNING:
+		if (priv->new_state >= CAN_STATE_ERROR_PASSIVE &&
+		    priv->new_state <= CAN_STATE_BUS_OFF)
+			priv->can.can_stats.error_passive++;
+		break;
+	default:
+		break;
+	}
+	priv->can.state = priv->new_state;
+
+	/* and send error packet */
+	if (priv->can_err_id)
+		mcp25xxfd_error_skb(priv->net);
+
+	/* handle BUS OFF */
+	if (priv->can.state == CAN_STATE_BUS_OFF) {
+		if (priv->can.restart_ms == 0) {
+			mcp25xxfd_stop_queue(priv->net);
+			priv->force_quit = 1;
+			priv->can.can_stats.bus_off++;
+			can_bus_off(priv->net);
+			mcp25xxfd_hw_sleep(spi);
+		}
+	} else {
+		/* restart the tx queue if needed */
+		if (priv->fifos.tx_processed_mask == priv->fifos.tx_fifo_mask)
+			mcp25xxfd_wake_queue(spi);
+	}
+
+	/* clear bdiag flags */
+	if (priv->bdiag1_clear_mask) {
+		ret = mcp25xxfd_cmd_write_mask(spi,
+					       CAN_BDIAG1,
+					       priv->bdiag1_clear_value,
+					       priv->bdiag1_clear_mask,
+					       priv->spi_speed_hz);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static irqreturn_t mcp25xxfd_can_ist(int irq, void *dev_id)
+{
+	struct mcp25xxfd_priv *priv = dev_id;
+	struct spi_device *spi = priv->spi;
+	int ret;
+
+	priv->stats.irq_calls++;
+	priv->stats.irq_state = IRQ_STATE_RUNNING;
+
+	while (!priv->force_quit) {
+		/* count irq loops */
+		priv->stats.irq_loops++;
+
+		/* copy pending to in_irq - any
+		 * updates that happen asyncronously
+		 * are not taken into account here
+		 */
+		priv->fifos.tx_pending_mask_in_irq =
+			priv->fifos.tx_pending_mask;
+
+		/* read interrupt status flags */
+		ret = mcp25xxfd_cmd_readn(spi, CAN_INT,
+					  &priv->status,
+					  sizeof(priv->status),
+					  priv->spi_speed_hz);
+		if (ret)
+			return ret;
+
+		/* only act if the mask is applied */
+		if ((priv->status.intf &
+		     (priv->status.intf >> CAN_INT_IE_SHIFT)) == 0)
+			break;
+
+		/* handle the status */
+		ret = mcp25xxfd_can_ist_handle_status(spi);
+		if (ret)
+			return ret;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mcp25xxfd_get_berr_counter(const struct net_device *net,
+				      struct can_berr_counter *bec)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+
+	bec->txerr = (priv->status.trec & CAN_TREC_TEC_MASK) >>
+		CAN_TREC_TEC_SHIFT;
+	bec->rxerr = (priv->status.trec & CAN_TREC_REC_MASK) >>
+		CAN_TREC_REC_SHIFT;
+
+	return 0;
+}
+
+static int mcp25xxfd_power_enable(struct regulator *reg, int enable)
+{
+	return 0;
+}
+
+static int mcp25xxfd_do_set_mode(struct net_device *net, enum can_mode mode)
+{
+	switch (mode) {
+	case CAN_MODE_START:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mcp25xxfd_do_set_nominal_bittiming(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct spi_device *spi = priv->spi;
+
+	int sjw = bt->sjw;
+	int pseg2 = bt->phase_seg2;
+	int pseg1 = bt->phase_seg1;
+	int propseg = bt->prop_seg;
+	int brp = bt->brp;
+
+	int tseg1 = propseg + pseg1;
+	int tseg2 = pseg2;
+
+	/* calculate nominal bit timing */
+	priv->regs.nbtcfg = ((sjw - 1) << CAN_NBTCFG_SJW_SHIFT) |
+		((tseg2 - 1) << CAN_NBTCFG_TSEG2_SHIFT) |
+		((tseg1 - 1) << CAN_NBTCFG_TSEG1_SHIFT) |
+		((brp - 1) << CAN_NBTCFG_BRP_SHIFT);
+
+	return mcp25xxfd_cmd_write(spi, CAN_NBTCFG,
+				   priv->regs.nbtcfg,
+				   priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_do_set_data_bittiming(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct can_bittiming *bt = &priv->can.data_bittiming;
+	struct spi_device *spi = priv->spi;
+
+	int sjw = bt->sjw;
+	int pseg2 = bt->phase_seg2;
+	int pseg1 = bt->phase_seg1;
+	int propseg = bt->prop_seg;
+	int brp = bt->brp;
+
+	int tseg1 = propseg + pseg1;
+	int tseg2 = pseg2;
+
+	int ret;
+
+	/* set up Transmitter delay compensation */
+	if (!priv->regs.tdc)
+		priv->regs.tdc = CAN_TDC_EDGFLTEN |
+			(CAN_TDC_TDCMOD_AUTO << CAN_TDC_TDCMOD_SHIFT);
+	ret = mcp25xxfd_cmd_write(spi, CAN_TDC, priv->regs.tdc,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* calculate nominal bit timing */
+	priv->regs.dbtcfg = ((sjw - 1) << CAN_DBTCFG_SJW_SHIFT) |
+		((tseg2 - 1) << CAN_DBTCFG_TSEG2_SHIFT) |
+		((tseg1 - 1) << CAN_DBTCFG_TSEG1_SHIFT) |
+		((brp - 1) << CAN_DBTCFG_BRP_SHIFT);
+
+	return mcp25xxfd_cmd_write(spi, CAN_DBTCFG,
+				   priv->regs.dbtcfg,
+				   priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_hw_probe(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int ret;
+
+	/* Wait for oscillator startup timer after power up */
+	msleep(MCP25XXFD_OST_DELAY_MS);
+
+	/* send a "blind" reset, hoping we are in Config mode */
+	mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
+
+	/* Wait for oscillator startup again */
+	msleep(MCP25XXFD_OST_DELAY_MS);
+
+	/* check clock register that the clock is ready or disabled */
+	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
+				 &priv->regs.osc,
+				 priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* there can only be one... */
+	switch (priv->regs.osc &
+		(MCP25XXFD_OSC_OSCRDY | MCP25XXFD_OSC_OSCDIS)) {
+	case MCP25XXFD_OSC_OSCRDY: /* either the clock is ready */
+		break;
+	case MCP25XXFD_OSC_OSCDIS: /* or the clock is disabled */
+		/* wakeup sleeping system */
+		ret = mcp25xxfd_wake_from_sleep(spi);
+		if (ret)
+			return ret;
+		/* send a reset, hoping we are now in Config mode */
+		mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
+
+		/* Wait for oscillator startup again */
+		msleep(MCP25XXFD_OST_DELAY_MS);
+		break;
+	default:
+		/* otherwise there is no valid device (or in strange state)
+		 *
+		 * if PLL is enabled but not ready, then there may be
+		 * something "fishy"
+		 * this happened during driver development
+		 * (enabling pll, when when on wrong clock), so best warn
+		 * about such a possibility
+		 */
+		if ((priv->regs.osc &
+		     (MCP25XXFD_OSC_PLLEN | MCP25XXFD_OSC_PLLRDY))
+		    == MCP25XXFD_OSC_PLLEN)
+			dev_err(&spi->dev,
+				"mcp25xxfd may be in a strange state - a power disconnect may be required\n");
+
+		return -ENODEV;
+	}
+
+	/* check if we are in config mode already*/
+
+	/* read CON register and match */
+	ret = mcp25xxfd_cmd_read(spi, CAN_CON,
+				 &priv->regs.con,
+				 priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* apply mask and check */
+	if ((priv->regs.con & CAN_CON_DEFAULT_MASK) == CAN_CON_DEFAULT) {
+		priv->active_can_mode = CAN_CON_MODE_CONFIG;
+		return 0;
+	}
+
+	/* as per datasheet a reset only works in Config Mode
+	 * so as we have in principle no knowledge of the current
+	 * mode that the controller is in we have no safe way
+	 * to detect the device correctly
+	 * hence we need to "blindly" put the controller into
+	 * config mode.
+	 * on the "save" side, the OSC reg has to be valid already,
+	 * so there is a chance we got the controller...
+	 */
+
+	/* blindly force it into config mode */
+	priv->regs.con = CAN_CON_DEFAULT;
+	priv->active_can_mode = CAN_CON_MODE_CONFIG;
+	ret = mcp25xxfd_cmd_write(spi, CAN_CON, CAN_CON_DEFAULT,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* delay some time */
+	msleep(MCP25XXFD_OST_DELAY_MS);
+
+	/* reset can controller */
+	mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
+
+	/* delay some time */
+	msleep(MCP25XXFD_OST_DELAY_MS);
+
+	/* read CON register and match a final time */
+	ret = mcp25xxfd_cmd_read(spi, CAN_CON,
+				 &priv->regs.con,
+				 priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* apply mask and check */
+	if ((priv->regs.con & CAN_CON_DEFAULT_MASK) != CAN_CON_DEFAULT)
+		return -ENODEV;
+
+	/* just in case: disable interrupts on controller */
+	return mcp25xxfd_disable_interrupts(spi,
+					    priv->spi_setup_speed_hz);
+}
+
+static int mcp25xxfd_setup_osc(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	int val = ((priv->config.clock_pll) ? MCP25XXFD_OSC_PLLEN : 0)
+		| ((priv->config.clock_div2) ? MCP25XXFD_OSC_SCLKDIV : 0);
+	int waitfor = ((priv->config.clock_pll) ? MCP25XXFD_OSC_PLLRDY : 0)
+		| ((priv->config.clock_div2) ? MCP25XXFD_OSC_SCLKRDY : 0)
+		| MCP25XXFD_OSC_OSCRDY;
+	int ret;
+	unsigned long timeout;
+
+	/* manage clock_out divider */
+	switch (priv->config.clock_odiv) {
+	case 10:
+		val |= (MCP25XXFD_OSC_CLKODIV_10)
+			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
+		break;
+	case 4:
+		val |= (MCP25XXFD_OSC_CLKODIV_4)
+			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
+		break;
+	case 2:
+		val |= (MCP25XXFD_OSC_CLKODIV_2)
+			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
+		break;
+	case 1:
+		val |= (MCP25XXFD_OSC_CLKODIV_1)
+			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
+		break;
+	case 0:
+		/* this means implicitly SOF output */
+		val |= (MCP25XXFD_OSC_CLKODIV_10)
+			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
+		break;
+	default:
+		dev_err(&spi->dev,
+			"Unsupported output clock divider %i\n",
+			priv->config.clock_odiv);
+		return -EINVAL;
+	}
+
+	/* write clock */
+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_OSC, val,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* wait for synced pll/osc/sclk */
+	timeout = jiffies + MCP25XXFD_OSC_POLLING_JIFFIES;
+	while (time_before_eq(jiffies, timeout)) {
+		ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
+					 &priv->regs.osc,
+					 priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		if ((priv->regs.osc & waitfor) == waitfor)
+			return 0;
+	}
+
+	dev_err(&spi->dev,
+		"Clock did not lock within the timeout period\n");
+
+	/* we timed out */
+	return -ENODEV;
+}
+
+static int mcp25xxfd_setup_fifo(struct net_device *net,
+				struct mcp25xxfd_priv *priv,
+				struct spi_device *spi)
+{
+	u32 val, available_memory, tx_memory_used;
+	int ret;
+	int i, fifo;
+
+	/* clear all filter */
+	for (i = 0; i < 32; i++) {
+		ret = mcp25xxfd_cmd_write(spi, CAN_FLTOBJ(i), 0,
+					  priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		ret = mcp25xxfd_cmd_write(spi, CAN_FLTMASK(i), 0,
+					  priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FLTCON(i), 0,
+					       CAN_FILCON_MASK(i),
+					       priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+	}
+
+	/* decide on TEF, tx and rx FIFOS */
+	switch (net->mtu) {
+	case CAN_MTU:
+		/* note: if we have INT1 connected to a GPIO
+		 * then we could handle this differently and more
+		 * efficiently
+		 */
+
+		/* mtu is 8 */
+		priv->fifos.payload_size = 8;
+		priv->fifos.payload_mode = CAN_TXQCON_PLSIZE_8;
+
+		/* 7 tx fifos starting at fifo 1 */
+		priv->fifos.tx_fifos = 7;
+
+		/* 24 rx fifos with 1 buffers/fifo */
+		priv->fifos.rx_fifo_depth = 1;
+
+		break;
+	case CANFD_MTU:
+		/* wish there was a way to have hw filters
+		 * that can separate based on length ...
+		 */
+		/* MTU is 64 */
+		priv->fifos.payload_size = 64;
+		priv->fifos.payload_mode = CAN_TXQCON_PLSIZE_64;
+
+		/* 7 tx fifos */
+		priv->fifos.tx_fifos = 7;
+
+		/* 19 rx fifos with 1 buffer/fifo */
+		priv->fifos.rx_fifo_depth = 1;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* if defined as a module modify the number of tx_fifos */
+	if (tx_fifos) {
+		dev_info(&spi->dev,
+			 "Using %i tx-fifos as per module parameter\n",
+			 tx_fifos);
+		priv->fifos.tx_fifos = tx_fifos;
+	}
+
+	/* check range - we need 1 RX-fifo and one tef-fifo, hence 30 */
+	if (priv->fifos.tx_fifos > 30) {
+		dev_err(&spi->dev,
+			"There is an absolute maximum of 30 tx-fifos\n");
+		return -EINVAL;
+	}
+
+	tx_memory_used = priv->fifos.tx_fifos *
+		(sizeof(struct mcp25xxfd_obj_tef) +
+		 sizeof(struct mcp25xxfd_obj_tx) +
+		 priv->fifos.payload_size);
+	/* check that we are not exceeding memory limits with 1 RX buffer */
+	if (tx_memory_used + (sizeof(struct mcp25xxfd_obj_rx) +
+		   priv->fifos.payload_size) > MCP25XXFD_BUFFER_TXRX_SIZE) {
+		dev_err(&spi->dev,
+			"Configured %i tx-fifos exceeds available memory already\n",
+			priv->fifos.tx_fifos);
+		return -EINVAL;
+	}
+
+	/* calculate possible amount of RX fifos */
+	available_memory = MCP25XXFD_BUFFER_TXRX_SIZE - tx_memory_used;
+
+	priv->fifos.rx_fifos = available_memory /
+		(sizeof(struct mcp25xxfd_obj_rx) +
+		 priv->fifos.payload_size) /
+		priv->fifos.rx_fifo_depth;
+
+	/* we only support 31 FIFOS in total (TEF = FIFO0),
+	 * so modify rx accordingly
+	 */
+	if (priv->fifos.tx_fifos + priv->fifos.rx_fifos > 31)
+		priv->fifos.rx_fifos = 31 - priv->fifos.tx_fifos;
+
+	/* calculate effective memory used */
+	available_memory -= priv->fifos.rx_fifos *
+		(sizeof(struct mcp25xxfd_obj_rx) +
+		 priv->fifos.payload_size) *
+		priv->fifos.rx_fifo_depth;
+
+	/* calcluate tef size */
+	priv->fifos.tef_fifos = priv->fifos.tx_fifos;
+	fifo = available_memory / sizeof(struct mcp25xxfd_obj_tef);
+	if (fifo > 0) {
+		priv->fifos.tef_fifos += fifo;
+		if (priv->fifos.tef_fifos > 32)
+			priv->fifos.tef_fifos = 32;
+	}
+
+	/* calculate rx/tx fifo start */
+	priv->fifos.rx_fifo_start = 1;
+	priv->fifos.tx_fifo_start =
+		priv->fifos.rx_fifo_start + priv->fifos.rx_fifos;
+
+	/* set up TEF SIZE to the number of tx_fifos and IRQ */
+	priv->regs.tefcon = CAN_TEFCON_FRESET |
+		CAN_TEFCON_TEFNEIE |
+		CAN_TEFCON_TEFTSEN |
+		((priv->fifos.tef_fifos - 1) << CAN_TEFCON_FSIZE_SHIFT);
+
+	ret = mcp25xxfd_cmd_write(spi, CAN_TEFCON,
+				  priv->regs.tefcon,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* set up tx fifos */
+	val = CAN_FIFOCON_TXEN |
+		CAN_FIFOCON_TXATIE | /* show up txatie flags in txatif reg */
+		CAN_FIFOCON_FRESET | /* reset FIFO */
+		(priv->fifos.payload_mode << CAN_FIFOCON_PLSIZE_SHIFT) |
+		(0 << CAN_FIFOCON_FSIZE_SHIFT); /* 1 FIFO only */
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+		if (three_shot)
+			val |= CAN_FIFOCON_TXAT_THREE_SHOT <<
+				CAN_FIFOCON_TXAT_SHIFT;
+		else
+			val |= CAN_FIFOCON_TXAT_ONE_SHOT <<
+				CAN_FIFOCON_TXAT_SHIFT;
+	else
+		val |= CAN_FIFOCON_TXAT_UNLIMITED <<
+			CAN_FIFOCON_TXAT_SHIFT;
+
+	for (i = 0; i < priv->fifos.tx_fifos; i++) {
+		fifo = priv->fifos.tx_fifo_start + i;
+		ret = mcp25xxfd_cmd_write(spi, CAN_FIFOCON(fifo),
+					  /* the prioriy needs to be inverted
+					   * we need to run from lowest to
+					   * highest to avoid MAB errors
+					   */
+					  val | ((31 - fifo) <<
+						 CAN_FIFOCON_TXPRI_SHIFT),
+					  priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		priv->fifos.tx_fifo_mask |= BIT(fifo);
+	}
+
+	/* now set up RX FIFO */
+	for (i = 0,
+	     fifo = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
+	     i < priv->fifos.rx_fifos; i++, fifo--) {
+		/* prepare the fifo itself */
+		ret = mcp25xxfd_cmd_write(spi, CAN_FIFOCON(fifo),
+					  (priv->fifos.payload_mode <<
+					   CAN_FIFOCON_PLSIZE_SHIFT) |
+					  ((priv->fifos.rx_fifo_depth - 1) <<
+					   CAN_FIFOCON_FSIZE_SHIFT) |
+					  /* RX timestamps: */
+					  CAN_FIFOCON_RXTSEN |
+					  /* reset FIFO: */
+					  CAN_FIFOCON_FRESET |
+					  /* FIFO Full: */
+					  CAN_FIFOCON_TFERFFIE |
+					  /* FIFO Half Full: */
+					  CAN_FIFOCON_TFHRFHIE |
+					  /* FIFO not empty: */
+					  CAN_FIFOCON_TFNRFNIE |
+					  /* on last fifo add overflow flag: */
+					  ((i == priv->fifos.rx_fifos - 1) ?
+					   CAN_FIFOCON_RXOVIE : 0),
+					  priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		/* prepare the rx filter config: filter i directs to fifo
+		 * FLTMSK and FLTOBJ are 0 already, so they match everything
+		 */
+		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FLTCON(i),
+					       CAN_FIFOCON_FLTEN(i) |
+					       (fifo << CAN_FILCON_SHIFT(i)),
+					       CAN_FIFOCON_FLTEN(i) |
+					       CAN_FILCON_MASK(i),
+					       priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+
+		priv->fifos.rx_fifo_mask |= BIT(fifo);
+	}
+
+	/* we need to move out of CONFIG mode shortly to get the addresses */
+	ret = mcp25xxfd_set_opmode(spi, CAN_CON_MODE_INTERNAL_LOOPBACK,
+				   priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* for the TEF fifo */
+	ret = mcp25xxfd_cmd_read(spi, CAN_TEFUA, &val,
+				 priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+	priv->fifos.tef_address = val;
+	priv->fifos.tef_address_start = val;
+	priv->fifos.tef_address_end = priv->fifos.tef_address_start +
+		priv->fifos.tef_fifos * sizeof(struct mcp25xxfd_obj_tef) -
+		1;
+
+	/* get all the relevant addresses for the transmit fifos */
+	for (i = 0; i < priv->fifos.tx_fifos; i++) {
+		fifo = priv->fifos.tx_fifo_start + i;
+		ret = mcp25xxfd_cmd_read(spi, CAN_FIFOUA(fifo),
+					 &val, priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+		priv->fifos.fifo_address[fifo] = val;
+	}
+
+	/* and prepare the spi_messages */
+	ret = mcp25xxfd_fill_spi_transmit_fifos(priv);
+	if (ret)
+		return ret;
+
+	/* get all the relevant addresses for the rx fifos */
+	for (i = 0; i < priv->fifos.rx_fifos; i++) {
+		fifo = priv->fifos.rx_fifo_start + i;
+		ret = mcp25xxfd_cmd_read(spi, CAN_FIFOUA(fifo),
+					 &val, priv->spi_setup_speed_hz);
+		if (ret)
+			return ret;
+	       priv->fifos.fifo_address[fifo] = val;
+	}
+
+	/* now get back into config mode */
+	ret = mcp25xxfd_set_opmode(spi, CAN_CON_MODE_CONFIG,
+				   priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mcp25xxfd_setup(struct net_device *net,
+			   struct mcp25xxfd_priv *priv,
+			   struct spi_device *spi)
+{
+	int ret;
+
+	/* set up pll/clock if required */
+	ret = mcp25xxfd_setup_osc(spi);
+	if (ret)
+		return ret;
+
+	/* set up RAM ECC */
+	priv->regs.ecccon = MCP25XXFD_ECCCON_ECCEN |
+		MCP25XXFD_ECCCON_SECIE |
+		MCP25XXFD_ECCCON_DEDIE;
+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_ECCCON,
+				  priv->regs.ecccon,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* clean SRAM now that we have ECC enabled
+	 * only this case it is clear that all RAM cels have
+	 * valid ECC bits
+	 */
+	ret = mcp25xxfd_clean_sram(spi, priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* time stamp control register - 1ns resolution, but disabled */
+	ret = mcp25xxfd_cmd_write(spi, CAN_TBC, 0,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+	priv->regs.tscon = CAN_TSCON_TBCEN |
+		((priv->can.clock.freq / 1000000)
+		 << CAN_TSCON_TBCPRE_SHIFT);
+	ret = mcp25xxfd_cmd_write(spi, CAN_TSCON,
+				  priv->regs.tscon,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* setup value of con_register */
+	priv->regs.con = CAN_CON_STEF /* enable TEF */;
+
+	/* transmission bandwidth sharing bits */
+	if (bw_sharing_log2bits > 12)
+		bw_sharing_log2bits = 12;
+	priv->regs.con |= bw_sharing_log2bits << CAN_CON_TXBWS_SHIFT;
+	/* non iso FD mode */
+	if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
+		priv->regs.con |= CAN_CON_ISOCRCEN;
+	/* one shot */
+	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+		priv->regs.con |= CAN_CON_RTXAT;
+
+	/* and put us into default mode = CONFIG */
+	priv->regs.con |= (CAN_CON_MODE_CONFIG << CAN_CON_REQOP_SHIFT) |
+		(CAN_CON_MODE_CONFIG << CAN_CON_OPMOD_SHIFT);
+	/* apply it now - later we will only switch opsmodes... */
+	ret = mcp25xxfd_cmd_write(spi, CAN_CON,
+				  priv->regs.con,
+				  priv->spi_setup_speed_hz);
+
+	/* setup fifos - this also puts the system into sleep mode */
+	return mcp25xxfd_setup_fifo(net, priv, spi);
+}
+
+static int mcp25xxfd_open(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+	int ret;
+
+	//pr_err("mcp25xxfd_open start\n");
+	ret = open_candev(net);
+	if (ret) {
+		dev_err(&spi->dev, "unable to set initial baudrate!\n");
+		return ret;
+	}
+
+	mcp25xxfd_gpio_direction_output(&priv->gpio, 0, 0);
+
+	mcp25xxfd_power_enable(priv->transceiver, 1);
+
+	priv->force_quit = 0;
+
+	/* clear those statistics */
+	memset(&priv->stats, 0, sizeof(priv->stats));
+
+	ret = request_threaded_irq(spi->irq, NULL,
+				   mcp25xxfd_can_ist,
+				   IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+				   DEVICE_NAME, priv);
+	if (ret) {
+		dev_err(&spi->dev, "failed to acquire irq %d - %i\n",
+			spi->irq, ret);
+		mcp25xxfd_power_enable(priv->transceiver, 0);
+		close_candev(net);
+		return ret;
+	}
+
+	/* wake from sleep if necessary */
+	ret = mcp25xxfd_hw_wake(spi);
+	if (ret)
+		goto open_clean;
+
+	ret = mcp25xxfd_setup(net, priv, spi);
+	if (ret)
+		goto open_clean;
+
+	mcp25xxfd_do_set_nominal_bittiming(net);
+	mcp25xxfd_do_set_data_bittiming(net);
+
+	ret = mcp25xxfd_set_normal_opmode(spi);
+	if (ret)
+		goto open_clean;
+	/* setting up default state */
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	/* only now enable the interrupt on the controller */
+	ret =  mcp25xxfd_enable_interrupts(spi,
+					   priv->spi_setup_speed_hz);
+	if (ret)
+		goto open_clean;
+
+	can_led_event(net, CAN_LED_EVENT_OPEN);
+
+	priv->tx_queue_status = TX_QUEUE_STATUS_RUNNING;
+	netif_wake_queue(net);
+
+	return 0;
+
+open_clean:
+	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
+	free_irq(spi->irq, priv);
+	mcp25xxfd_hw_sleep(spi);
+	mcp25xxfd_power_enable(priv->transceiver, 0);
+	close_candev(net);
+
+	return ret;
+}
+
+static void mcp25xxfd_clean(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	int i;
+
+	for (i = 0; i < priv->fifos.tx_fifos; i++) {
+		if (priv->fifos.tx_pending_mask & BIT(i)) {
+			can_free_echo_skb(priv->net, 0);
+			priv->net->stats.tx_errors++;
+		}
+	}
+
+	priv->fifos.tx_pending_mask = 0;
+}
+
+static int mcp25xxfd_stop(struct net_device *net)
+{
+	struct mcp25xxfd_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+
+	close_candev(net);
+	mcp25xxfd_gpio_direction_output(&priv->gpio, 0, 1);
+	kfree(priv->spi_transmit_fifos);
+	priv->spi_transmit_fifos = NULL;
+
+	priv->force_quit = 1;
+	free_irq(spi->irq, priv);
+
+	/* Disable and clear pending interrupts */
+	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
+
+	mcp25xxfd_clean(net);
+
+	mcp25xxfd_hw_sleep(spi);
+
+	mcp25xxfd_power_enable(priv->transceiver, 0);
+
+	priv->can.state = CAN_STATE_STOPPED;
+
+	can_led_event(net, CAN_LED_EVENT_STOP);
+
+	return 0;
+}
+
+static const struct net_device_ops mcp25xxfd_netdev_ops = {
+	.ndo_open = mcp25xxfd_open,
+	.ndo_stop = mcp25xxfd_stop,
+	.ndo_start_xmit = mcp25xxfd_start_xmit,
+	.ndo_change_mtu = can_change_mtu,
+};
+
+static const struct of_device_id mcp25xxfd_of_match[] = {
+	{
+		.compatible	= "microchip,mcp2517fd",
+		.data		= (void *)CAN_MCP2517FD,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mcp25xxfd_of_match);
+
+static const struct spi_device_id mcp25xxfd_id_table[] = {
+	{
+		.name		= "mcp2517fd",
+		.driver_data	= (kernel_ulong_t)CAN_MCP2517FD,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, mcp25xxfd_id_table);
+
+static int mcp25xxfd_dump_regs(struct seq_file *file, void *offset)
+{
+	struct spi_device *spi = file->private;
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	u32 data[CAN_TXQUA - CAN_CON + 4];
+	int i;
+	int count;
+	int ret;
+
+	count = (CAN_TXQUA - CAN_CON) / 4 + 1;
+	ret = mcp25xxfd_cmd_readn(spi, CAN_CON, data, 4 * count,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	mcp25xxfd_convert_to_cpu((u32 *)data, 4 * count);
+
+	for (i = 0; i < count; i++) {
+		seq_printf(file, "Reg 0x%03x = 0x%08x\n",
+			   CAN_CON + 4 * i,
+			   ((u32 *)data)[i]);
+	}
+
+	count = (MCP25XXFD_ECCSTAT - MCP25XXFD_OSC) / 4 + 1;
+	ret = mcp25xxfd_cmd_readn(spi, MCP25XXFD_OSC, data, 4 * count,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+	mcp25xxfd_convert_to_cpu((u32 *)data, 4 * count);
+
+	for (i = 0; i < count; i++) {
+		seq_printf(file, "Reg 0x%03x = 0x%08x\n",
+			   MCP25XXFD_OSC + 4 * i,
+			   ((u32 *)data)[i]);
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static void mcp25xxfd_debugfs_add(struct mcp25xxfd_priv *priv)
+{
+	struct dentry *root, *fifousage, *fifoaddr, *rx, *tx, *status,
+		*regs, *stats, *rxdlc, *txdlc;
+	char name[32];
+	int i;
+
+	/* create the net device name */
+	snprintf(name, sizeof(name), DEVICE_NAME "-%s", priv->net->name);
+	priv->debugfs_dir = debugfs_create_dir(name, NULL);
+	root = priv->debugfs_dir;
+
+	rx = debugfs_create_dir("rx", root);
+	tx = debugfs_create_dir("tx", root);
+	fifoaddr = debugfs_create_dir("fifo_address", root);
+	status = debugfs_create_dir("status", root);
+	regs = debugfs_create_dir("regs", root);
+	stats = debugfs_create_dir("stats", root);
+	fifousage = debugfs_create_dir("fifo_usage", stats);
+	rxdlc = debugfs_create_dir("rx_dlc_usage", stats);
+	txdlc = debugfs_create_dir("tx_dlc_usage", stats);
+
+	/* add spi speed info */
+	debugfs_create_u32("spi_setup_speed_hz", 0444, root,
+			   &priv->spi_setup_speed_hz);
+	debugfs_create_u32("spi_speed_hz", 0444, root,
+			   &priv->spi_speed_hz);
+
+	/* add irq state info */
+	debugfs_create_u32("irq_state", 0444, root, &priv->stats.irq_state);
+
+	/* for the clock user mask */
+	debugfs_create_u32("clk_user_mask", 0444, root, &priv->clk_user_mask);
+
+	/* add fd statistics */
+	debugfs_create_u64("rx_fd_frames", 0444, stats,
+			   &priv->stats.rx_fd_count);
+	debugfs_create_u64("tx_fd_frames", 0444, stats,
+			   &priv->stats.tx_fd_count);
+	debugfs_create_u64("rx_brs_frames", 0444, stats,
+			   &priv->stats.rx_brs_count);
+	debugfs_create_u64("tx_brs_frames", 0444, stats,
+			   &priv->stats.tx_brs_count);
+
+	/* export the status structure */
+	debugfs_create_x32("intf", 0444, status, &priv->status.intf);
+	debugfs_create_x32("rx_if", 0444, status, &priv->status.rxif);
+	debugfs_create_x32("tx_if", 0444, status, &priv->status.txif);
+	debugfs_create_x32("rx_ovif", 0444, status, &priv->status.rxovif);
+	debugfs_create_x32("tx_atif", 0444, status, &priv->status.txatif);
+	debugfs_create_x32("tx_req", 0444, status, &priv->status.txreq);
+	debugfs_create_x32("trec", 0444, status, &priv->status.trec);
+	debugfs_create_x32("bdiag0", 0444, status, &priv->status.bdiag0);
+	debugfs_create_x32("bdiag1", 0444, status, &priv->status.bdiag1);
+
+	/* some configuration registers */
+	debugfs_create_x32("con", 0444, regs, &priv->regs.con);
+	debugfs_create_x32("ecccon", 0444, regs, &priv->regs.ecccon);
+	debugfs_create_x32("osc", 0444, regs, &priv->regs.osc);
+	debugfs_create_x32("iocon", 0444, regs, &priv->regs.iocon);
+	debugfs_create_x32("tdc", 0774, regs, &priv->regs.tdc);
+	debugfs_create_x32("tscon", 0444, regs, &priv->regs.tscon);
+	debugfs_create_x32("nbtcfg", 0444, regs, &priv->regs.nbtcfg);
+	debugfs_create_x32("dbtcfg", 0444, regs, &priv->regs.dbtcfg);
+
+	/* information on fifos */
+	debugfs_create_u32("fifo_start", 0444, rx,
+			   &priv->fifos.rx_fifo_start);
+	debugfs_create_u32("fifo_count", 0444, rx,
+			   &priv->fifos.rx_fifos);
+	debugfs_create_x32("fifo_mask", 0444, rx,
+			   &priv->fifos.rx_fifo_mask);
+	debugfs_create_u64("rx_overflow", 0444, rx,
+			   &priv->stats.rx_overflow);
+	debugfs_create_u64("rx_mab", 0444, stats,
+			   &priv->stats.rx_mab);
+
+	debugfs_create_u32("fifo_start", 0444, tx,
+			   &priv->fifos.tx_fifo_start);
+	debugfs_create_u32("fifo_count", 0444, tx,
+			   &priv->fifos.tx_fifos);
+	debugfs_create_x32("fifo_mask", 0444, tx,
+			   &priv->fifos.tx_fifo_mask);
+	debugfs_create_x32("fifo_pending", 0444, tx,
+			   &priv->fifos.tx_pending_mask);
+	debugfs_create_x32("fifo_submitted", 0444, tx,
+			   &priv->fifos.tx_submitted_mask);
+	debugfs_create_x32("fifo_processed", 0444, tx,
+			   &priv->fifos.tx_processed_mask);
+	debugfs_create_u32("queue_status", 0444, tx,
+			   &priv->tx_queue_status);
+	debugfs_create_u64("tx_mab", 0444, stats,
+			   &priv->stats.tx_mab);
+
+	debugfs_create_u32("tef_count", 0444, tx,
+			   &priv->fifos.tef_fifos);
+
+	debugfs_create_u32("fifo_max_payload_size", 0444, root,
+			   &priv->fifos.payload_size);
+
+	/* interrupt statistics */
+	debugfs_create_u64("int", 0444, stats,
+			   &priv->stats.irq_calls);
+	debugfs_create_u64("int_loops", 0444, stats,
+			   &priv->stats.irq_loops);
+	debugfs_create_u64("int_ivm", 0444, stats,
+			   &priv->stats.int_ivm_count);
+	debugfs_create_u64("int_wake", 0444, stats,
+			   &priv->stats.int_wake_count);
+	debugfs_create_u64("int_cerr", 0444, stats,
+			   &priv->stats.int_cerr_count);
+	debugfs_create_u64("int_serr", 0444, stats,
+			   &priv->stats.int_serr_count);
+	debugfs_create_u64("int_rxov", 0444, stats,
+			   &priv->stats.int_rxov_count);
+	debugfs_create_u64("int_txat", 0444, stats,
+			   &priv->stats.int_txat_count);
+	debugfs_create_u64("int_spicrc", 0444, stats,
+			   &priv->stats.int_spicrc_count);
+	debugfs_create_u64("int_ecc", 0444, stats,
+			   &priv->stats.int_ecc_count);
+	debugfs_create_u64("int_tef", 0444, stats,
+			   &priv->stats.int_tef_count);
+	debugfs_create_u64("int_mod", 0444, stats,
+			   &priv->stats.int_mod_count);
+	debugfs_create_u64("int_tbc", 0444, stats,
+			   &priv->stats.int_tbc_count);
+	debugfs_create_u64("int_rx", 0444, stats,
+			   &priv->stats.int_rx_count);
+	debugfs_create_u64("int_tx", 0444, stats,
+			   &priv->stats.int_tx_count);
+
+	/* dlc statistics */
+	for (i = 0; i < 16; i++) {
+		snprintf(name, sizeof(name), "%02i", i);
+		debugfs_create_u64(name, 0444, rxdlc,
+				   &priv->stats.rx_dlc_usage[i]);
+		debugfs_create_u64(name, 0444, txdlc,
+				   &priv->stats.tx_dlc_usage[i]);
+	}
+
+	/* statistics on fifo buffer usage and address */
+	for (i = 1; i < 32; i++) {
+		snprintf(name, sizeof(name), "%02i", i);
+		debugfs_create_u64(name, 0444, fifousage,
+				   &priv->stats.fifo_usage[i]);
+		debugfs_create_u32(name, 0444, fifoaddr,
+				   &priv->fifos.fifo_address[i]);
+	}
+
+	/* dump the controller registers themselves */
+	debugfs_create_devm_seqfile(&priv->spi->dev, "reg_dump",
+				    root, mcp25xxfd_dump_regs);
+}
+
+static void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
+{
+	debugfs_remove_recursive(priv->debugfs_dir);
+}
+
+#else
+static void mcp25xxfd_debugfs_add(struct mcp25xxfd_priv *priv)
+{
+	return 0;
+}
+
+static void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
+{
+}
+#endif
+
+#ifdef CONFIG_OF_DYNAMIC
+int mcp25xxfd_of_parse(struct mcp25xxfd_priv *priv)
+{
+	struct spi_device *spi = priv->spi;
+	const struct device_node *np = spi->dev.of_node;
+	u32 val;
+	int ret;
+
+	priv->config.clock_div2 =
+		of_property_read_bool(np, "microchip,clock-div2");
+
+	ret = of_property_read_u32_index(np, "microchip,clock-out-div",
+					 0, &val);
+	if (!ret) {
+		switch (val) {
+		case 0:
+		case 1:
+		case 2:
+		case 4:
+		case 10:
+			priv->config.clock_odiv = val;
+			break;
+		default:
+			dev_err(&spi->dev,
+				"Invalid value in device tree for microchip,clock_out_div: %u - valid values: 0, 1, 2, 4, 10\n",
+				val);
+			return -EINVAL;
+		}
+	}
+
+	priv->config.gpio_opendrain =
+		of_property_read_bool(np, "gpio-open-drain");
+
+	return 0;
+}
+#else
+int mcp25xxfd_of_parse(struct mcp25xxfd_priv *priv)
+{
+	return 0;
+}
+#endif
+
+static int mcp25xxfd_can_probe(struct spi_device *spi)
+{
+	const struct of_device_id *of_id =
+		of_match_device(mcp25xxfd_of_match, &spi->dev);
+	struct net_device *net;
+	struct mcp25xxfd_priv *priv;
+	struct clk *clk;
+	int ret, freq;
+
+	/* as irq_create_fwspec_mapping() can return 0, check for it */
+	if (spi->irq <= 0) {
+		dev_err(&spi->dev, "no valid irq line defined: irq = %i\n",
+			spi->irq);
+		return -EINVAL;
+	}
+
+	clk = devm_clk_get(&spi->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&spi->dev,
+			"Can't get Clock source\n");
+		return PTR_ERR(clk);
+	}
+	freq = clk_get_rate(clk);
+	if (freq < MCP25XXFD_MIN_CLOCK_FREQUENCY ||
+	    freq > MCP25XXFD_MAX_CLOCK_FREQUENCY) {
+		dev_err(&spi->dev,
+			"Clock frequency %i is not in range [%i:%i]\n",
+			freq,
+			MCP25XXFD_MIN_CLOCK_FREQUENCY,
+			MCP25XXFD_MAX_CLOCK_FREQUENCY);
+		return -ERANGE;
+	}
+
+	/* Allocate can/net device */
+	net = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
+	if (!net)
+		return -ENOMEM;
+
+	net->netdev_ops = &mcp25xxfd_netdev_ops;
+	net->flags |= IFF_ECHO;
+
+	priv = netdev_priv(net);
+	priv->can.bittiming_const = &mcp25xxfd_nominal_bittiming_const;
+	priv->can.do_set_bittiming = &mcp25xxfd_do_set_nominal_bittiming;
+	priv->can.data_bittiming_const = &mcp25xxfd_data_bittiming_const;
+	priv->can.do_set_data_bittiming = &mcp25xxfd_do_set_data_bittiming;
+	priv->can.do_set_mode = mcp25xxfd_do_set_mode;
+	priv->can.do_get_berr_counter = mcp25xxfd_get_berr_counter;
+
+	priv->can.ctrlmode_supported =
+		CAN_CTRLMODE_FD |
+		CAN_CTRLMODE_LOOPBACK |
+		CAN_CTRLMODE_LISTENONLY |
+		CAN_CTRLMODE_BERR_REPORTING |
+		CAN_CTRLMODE_FD_NON_ISO |
+		CAN_CTRLMODE_ONE_SHOT;
+
+	if (of_id)
+		priv->model = (enum mcp25xxfd_model)of_id->data;
+	else
+		priv->model = spi_get_device_id(spi)->driver_data;
+
+	spi_set_drvdata(spi, priv);
+	priv->spi = spi;
+	priv->net = net;
+	priv->clk = clk;
+
+	priv->clk_user_mask = MCP25XXFD_CLK_USER_CAN;
+
+	mutex_init(&priv->clk_user_lock);
+	mutex_init(&priv->spi_rxtx_lock);
+
+	/* enable the clock and mark as enabled */
+	priv->clk_user_mask = MCP25XXFD_CLK_USER_CAN;
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		goto out_free;
+
+	/* Setup GPIO controller */
+	ret = mcp25xxfd_gpio_setup(spi);
+	if (ret)
+		goto out_clk;
+
+	/* all by default as push/pull */
+	priv->config.gpio_opendrain = false;
+
+	/* do not use the SCK clock divider of 2 */
+	priv->config.clock_div2 = false;
+
+	/* clock output is divided by 10 */
+	priv->config.clock_odiv = 10;
+
+	/* as a first guess we assume we are in CAN_CON_MODE_SLEEP
+	 * this is how we leave the controller when removing ourselves
+	 */
+	priv->active_can_mode = CAN_CON_MODE_SLEEP;
+
+	/* if we have a clock that is smaller then 4MHz, then enable the pll */
+	priv->config.clock_pll =
+		(freq <= MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY);
+
+	/* check in device tree for overrrides */
+	ret = mcp25xxfd_of_parse(priv);
+	if (ret)
+		return ret;
+
+	/* decide on real can clock rate */
+	priv->can.clock.freq = freq;
+	if (priv->config.clock_pll) {
+		priv->can.clock.freq *= MCP25XXFD_PLL_MULTIPLIER;
+		if (priv->can.clock.freq > MCP25XXFD_MAX_CLOCK_FREQUENCY) {
+			dev_err(&spi->dev,
+				"PLL clock frequency %i would exceed limit\n",
+				priv->can.clock.freq
+				);
+			return -EINVAL;
+		}
+	}
+	if (priv->config.clock_div2)
+		priv->can.clock.freq /= MCP25XXFD_SCLK_DIVIDER;
+
+	/* calclculate the clock frequencies to use */
+	priv->spi_setup_speed_hz = freq / 2;
+	priv->spi_speed_hz = priv->can.clock.freq / 2;
+	if (priv->config.clock_div2) {
+		priv->spi_setup_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
+		priv->spi_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
+	}
+
+	if (spi->max_speed_hz) {
+		priv->spi_setup_speed_hz = min_t(int,
+						 priv->spi_setup_speed_hz,
+						 spi->max_speed_hz);
+		priv->spi_speed_hz = min_t(int,
+					   priv->spi_speed_hz,
+					   spi->max_speed_hz);
+	}
+	/* Configure the SPI bus */
+	spi->bits_per_word = 8;
+	ret = spi_setup(spi);
+	if (ret)
+		goto out_clk;
+
+	ret = mcp25xxfd_power_enable(priv->power, 1);
+	if (ret)
+		goto out_clk;
+
+	SET_NETDEV_DEV(net, &spi->dev);
+
+	ret = mcp25xxfd_hw_probe(spi);
+	/* on error retry a second time */
+	if (ret == -ENODEV) {
+		ret = mcp25xxfd_hw_probe(spi);
+		if (!ret)
+			dev_info(&spi->dev,
+				 "found device only during retry\n");
+	}
+	if (ret) {
+		if (ret == -ENODEV)
+			dev_err(&spi->dev,
+				"Cannot initialize MCP%x. Wrong wiring?\n",
+				priv->model);
+	}
+
+	/* setting up GPIO+INT as PUSHPULL , TXCAN PUSH/PULL, no Standby */
+	priv->regs.iocon = 0;
+
+	/* SOF/CLOCKOUT pin 3 */
+	if (priv->config.clock_odiv < 1)
+		priv->regs.iocon |= MCP25XXFD_IOCON_SOF;
+
+	/* INT/GPIO (probably also clockout) as open drain */
+	if (priv->config.gpio_opendrain)
+		priv->regs.iocon |= MCP25XXFD_IOCON_INTOD;
+
+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_IOCON, priv->regs.iocon,
+				  priv->spi_setup_speed_hz);
+	if (ret)
+		return ret;
+
+	/* and put controller to sleep */
+	mcp25xxfd_hw_sleep(spi);
+
+	ret = register_candev(net);
+	if (ret)
+		goto error_probe;
+
+	/* register debugfs */
+	mcp25xxfd_debugfs_add(priv);
+
+	devm_can_led_init(net);
+
+	netdev_info(net, "MCP%x successfully initialized.\n", priv->model);
+	return 0;
+
+error_probe:
+	mcp25xxfd_power_enable(priv->power, 0);
+
+out_clk:
+	mcp25xxfd_stop_clock(spi, MCP25XXFD_CLK_USER_CAN);
+
+out_free:
+	free_candev(net);
+	dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
+	return ret;
+}
+
+static int mcp25xxfd_can_remove(struct spi_device *spi)
+{
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct net_device *net = priv->net;
+
+	mcp25xxfd_debugfs_remove(priv);
+
+	unregister_candev(net);
+
+	mcp25xxfd_power_enable(priv->power, 0);
+
+	if (!IS_ERR(priv->clk))
+		clk_disable_unprepare(priv->clk);
+
+	free_candev(net);
+
+	return 0;
+}
+
+static int __maybe_unused mcp25xxfd_can_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+	struct net_device *net = priv->net;
+
+	priv->force_quit = 1;
+	disable_irq(spi->irq);
+
+	if (netif_running(net)) {
+		netif_device_detach(net);
+
+		mcp25xxfd_hw_sleep(spi);
+		mcp25xxfd_power_enable(priv->transceiver, 0);
+		priv->after_suspend = AFTER_SUSPEND_UP;
+	} else {
+		priv->after_suspend = AFTER_SUSPEND_DOWN;
+	}
+
+	if (!IS_ERR_OR_NULL(priv->power)) {
+		regulator_disable(priv->power);
+		priv->after_suspend |= AFTER_SUSPEND_POWER;
+	}
+
+	return 0;
+}
+
+static int __maybe_unused mcp25xxfd_can_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+	if (priv->after_suspend & AFTER_SUSPEND_POWER)
+		mcp25xxfd_power_enable(priv->power, 1);
+
+	if (priv->after_suspend & AFTER_SUSPEND_UP)
+		mcp25xxfd_power_enable(priv->transceiver, 1);
+	else
+		priv->after_suspend = 0;
+
+	priv->force_quit = 0;
+
+	enable_irq(spi->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mcp25xxfd_can_pm_ops, mcp25xxfd_can_suspend,
+	mcp25xxfd_can_resume);
+
+static struct spi_driver mcp25xxfd_can_driver = {
+	.driver = {
+		.name = DEVICE_NAME,
+		.of_match_table = mcp25xxfd_of_match,
+		.pm = &mcp25xxfd_can_pm_ops,
+	},
+	.probe = mcp25xxfd_can_probe,
+	.remove = mcp25xxfd_can_remove,
+};
+
+static int __init mcp25xxfd_can_driver_init(void)
+{
+	int ret;
+
+	ret = spi_register_driver(&mcp25xxfd_can_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+module_init(mcp25xxfd_can_driver_init);
+
+static void __exit mcp25xxfd_can_driver_exit(void)
+{
+	spi_unregister_driver(&mcp25xxfd_can_driver);
+}
+module_exit(mcp25xxfd_can_driver_exit);
+
+MODULE_DESCRIPTION("Microchip 25XXFD CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c
index 3aa9395..0131148 100644
--- a/drivers/net/can/spi/qti-can.c
+++ b/drivers/net/can/spi/qti-can.c
@@ -1049,6 +1049,40 @@
 	return -EINVAL;
 }
 
+static int qti_can_end_fwupgrade_ioctl(struct net_device *netdev,
+				       struct ifreq *ifr, int cmd)
+{
+	int spi_cmd, ret;
+
+	struct qti_can *priv_data;
+	struct qti_can_netdev_privdata *netdev_priv_data;
+	struct spi_device *spi;
+	int len = 0;
+	u8 *data = NULL;
+
+	netdev_priv_data = netdev_priv(netdev);
+	priv_data = netdev_priv_data->qti_can;
+	spi = priv_data->spidev;
+	spi_cmd = qti_can_convert_ioctl_cmd_to_spi_cmd(cmd);
+	LOGDI("%s spi_cmd %x\n", __func__, spi_cmd);
+	if (spi_cmd < 0) {
+		LOGDE("%s wrong command %d\n", __func__, cmd);
+		return spi_cmd;
+	}
+
+	if (!ifr)
+		return -EINVAL;
+
+	mutex_lock(&priv_data->spi_lock);
+	LOGDI("%s len %d\n", __func__, len);
+
+	ret = qti_can_send_spi_locked(priv_data, spi_cmd, len, data);
+
+	mutex_unlock(&priv_data->spi_lock);
+
+	return ret;
+}
+
 static int qti_can_do_blocking_ioctl(struct net_device *netdev,
 				     struct ifreq *ifr, int cmd)
 {
@@ -1184,10 +1218,12 @@
 		qti_can_frame_filter(netdev, ifr, cmd);
 		ret = 0;
 		break;
+	case IOCTL_END_FIRMWARE_UPGRADE:
+		ret = qti_can_end_fwupgrade_ioctl(netdev, ifr, cmd);
+		break;
 	case IOCTL_GET_FW_BR_VERSION:
 	case IOCTL_BEGIN_FIRMWARE_UPGRADE:
 	case IOCTL_FIRMWARE_UPGRADE_DATA:
-	case IOCTL_END_FIRMWARE_UPGRADE:
 	case IOCTL_BEGIN_BOOT_ROM_UPGRADE:
 	case IOCTL_BOOT_ROM_UPGRADE_DATA:
 	case IOCTL_END_BOOT_ROM_UPGRADE:
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 0ab6e90..2c11464 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -187,7 +187,19 @@
 	__stringify(RESERVERD_PROD_74),
 	__stringify(IPA_CLIENT_MHI_DPL_CONS),
 	__stringify(RESERVERD_PROD_76),
-	__stringify(IPA_CLIENT_DUMMY_CONS1)
+	__stringify(IPA_CLIENT_DUMMY_CONS1),
+	__stringify(IPA_CLIENT_WIGIG_PROD),
+	__stringify(IPA_CLIENT_WIGIG1_CONS),
+	__stringify(RESERVERD_PROD_80),
+	__stringify(IPA_CLIENT_WIGIG2_CONS),
+	__stringify(RESERVERD_PROD_82),
+	__stringify(IPA_CLIENT_WIGIG3_CONS),
+	__stringify(RESERVERD_PROD_84),
+	__stringify(IPA_CLIENT_WIGIG4_CONS),
+	__stringify(IPA_CLIENT_MHI2_PROD),
+	__stringify(IPA_CLIENT_MHI2_CONS),
+	__stringify(IPA_CLIENT_Q6_CV2X_PROD),
+	__stringify(IPA_CLIENT_Q6_CV2X_CONS)
 };
 
 /**
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index 7c97381..e211473 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -66,8 +66,8 @@
 #define IPA_MHI_SUSPEND_SLEEP_MIN 900
 #define IPA_MHI_SUSPEND_SLEEP_MAX 1100
 
-#define IPA_MHI_MAX_UL_CHANNELS 1
-#define IPA_MHI_MAX_DL_CHANNELS 2
+#define IPA_MHI_MAX_UL_CHANNELS 2
+#define IPA_MHI_MAX_DL_CHANNELS 3
 
 /* bit #40 in address should be asserted for MHI transfers over pcie */
 #define IPA_MHI_CLIENT_HOST_ADDR_COND(addr) \
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index 704308f..eccdeab 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -144,13 +144,15 @@
 enum ipa3_usb_transport_type {
 	IPA_USB_TRANSPORT_TETH,
 	IPA_USB_TRANSPORT_DPL,
+	IPA_USB_TRANSPORT_TETH_2,
 	IPA_USB_TRANSPORT_MAX
 };
 
 /* Get transport type from tethering protocol */
 #define IPA3_USB_GET_TTYPE(__teth_prot) \
 	(((__teth_prot) == IPA_USB_DIAG) ? \
-	IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH)
+	IPA_USB_TRANSPORT_DPL : (((__teth_prot) == IPA_USB_RMNET_CV2X) ? \
+	IPA_USB_TRANSPORT_TETH_2 : IPA_USB_TRANSPORT_TETH))
 
 /* Does the given transport type is DPL? */
 #define IPA3_USB_IS_TTYPE_DPL(__ttype) \
@@ -186,7 +188,7 @@
 	struct ipa3_usb_teth_prot_context
 		teth_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE];
 	int num_init_prot; /* without dpl */
-	struct teth_bridge_init_params teth_bridge_params;
+	struct teth_bridge_init_params teth_bridge_params[IPA_TETH_BRIDGE_MAX];
 	struct completion dev_ready_comp;
 	u32 qmi_req_id;
 	spinlock_t state_lock;
@@ -198,6 +200,7 @@
 	struct dentry *dfile_state_info;
 	struct dentry *dent;
 	struct ipa3_usb_smmu_reg_map smmu_reg_map;
+	struct ipa3_usb_smmu_reg_map smmu_reg_map_dummy;
 };
 
 enum ipa3_usb_op {
@@ -704,6 +707,8 @@
 	case IPA_USB_RMNET:
 	case IPA_USB_MBIM:
 		return "teth_bridge";
+	case IPA_USB_RMNET_CV2X:
+		return "teth_bridge_cv2x";
 	case IPA_USB_DIAG:
 		return "dpl";
 	default:
@@ -719,6 +724,8 @@
 	switch (teth_prot) {
 	case IPA_USB_RMNET:
 		return "rmnet";
+	case IPA_USB_RMNET_CV2X:
+		return "rmnet_cv2x";
 	case IPA_USB_MBIM:
 		return "mbim";
 	default:
@@ -728,11 +735,18 @@
 	return "unsupported";
 }
 
-static int ipa3_usb_init_teth_bridge(void)
+static int ipa3_usb_init_teth_bridge(enum ipa_usb_teth_prot teth_prot)
 {
 	int result;
 
-	result = teth_bridge_init(&ipa3_usb_ctx->teth_bridge_params);
+	if (teth_prot == IPA_USB_RMNET_CV2X)
+		result =
+		teth_bridge_init(
+		&ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2]);
+	else
+		result =
+		teth_bridge_init(
+		&ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1]);
 	if (result) {
 		IPA_USB_ERR("Failed to initialize teth_bridge.\n");
 		return result;
@@ -746,15 +760,26 @@
 	struct ipa3_usb_transport_type_ctx *ttype_ctx =
 		&ipa3_usb_ctx->ttype_ctx[ttype];
 	int result;
+	enum ipa_client_type consumer;
 
-	/* there is one PM resource for teth and one for DPL */
-	if (!IPA3_USB_IS_TTYPE_DPL(ttype) && ipa3_usb_ctx->num_init_prot > 0)
+	/*
+	 * One PM resource for teth1,
+	 * One PM resource for teth2 (CV2X),
+	 * One for DPL,
+	 */
+
+	if (!IPA3_USB_IS_TTYPE_DPL(ttype) && (ipa3_usb_ctx->num_init_prot > 0)
+		&& (ttype != IPA_USB_TRANSPORT_TETH_2))
 		return 0;
 
 	memset(&ttype_ctx->pm_ctx.reg_params, 0,
 		sizeof(ttype_ctx->pm_ctx.reg_params));
-	ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
-				"USB DPL" : "USB";
+	ttype_ctx->pm_ctx.reg_params.name =
+				(ttype == IPA_USB_TRANSPORT_DPL) ?
+				"USB DPL" :
+				(ttype == IPA_USB_TRANSPORT_TETH_2) ?
+				"USB2" : "USB";
+
 	ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb;
 	ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx;
 	ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT;
@@ -766,9 +791,12 @@
 		goto fail_pm_reg;
 	}
 
+	consumer = (ttype == IPA_USB_TRANSPORT_DPL) ?
+		IPA_CLIENT_USB_DPL_CONS :
+		(ttype == IPA_USB_TRANSPORT_TETH_2) ?
+		IPA_CLIENT_USB2_CONS : IPA_CLIENT_USB_CONS;
 	result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl,
-		(ttype == IPA_USB_TRANSPORT_DPL) ?
-		IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS);
+		consumer);
 	if (result) {
 		IPA_USB_ERR("fail to associate cons with PM %d\n", result);
 		goto fail_pm_cons;
@@ -994,9 +1022,11 @@
 			goto bad_params;
 		}
 		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
-		result = ipa3_usb_init_teth_bridge();
+
+		result = ipa3_usb_init_teth_bridge(teth_prot);
 		if (result)
 			goto teth_prot_init_fail;
+
 		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
 			IPA_USB_TETH_PROT_INITIALIZED;
 		ipa3_usb_ctx->num_init_prot++;
@@ -1004,6 +1034,26 @@
 			ipa3_usb_teth_prot_to_string(teth_prot),
 			ipa3_usb_teth_bridge_prot_to_string(teth_prot));
 		break;
+	case IPA_USB_RMNET_CV2X:
+		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
+			IPA_USB_TETH_PROT_INVALID) {
+			IPA_USB_DBG("%s already initialized\n",
+				ipa3_usb_teth_prot_to_string(teth_prot));
+			result = -EPERM;
+			goto bad_params;
+		}
+		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
+
+		result = ipa3_usb_init_teth_bridge(teth_prot);
+		if (result)
+			goto teth_prot_init_fail;
+
+		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
+			IPA_USB_TETH_PROT_INITIALIZED;
+		IPA_USB_DBG("initialized %s %s\n",
+			ipa3_usb_teth_prot_to_string(teth_prot),
+			ipa3_usb_teth_bridge_prot_to_string(teth_prot));
+		break;
 	case IPA_USB_DIAG:
 		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
 			IPA_USB_TETH_PROT_INVALID) {
@@ -1031,7 +1081,8 @@
 
 teth_prot_init_fail:
 	if ((IPA3_USB_IS_TTYPE_DPL(ttype))
-		|| (ipa3_usb_ctx->num_init_prot == 0)) {
+		|| (ipa3_usb_ctx->num_init_prot == 0)
+		|| (teth_prot == IPA_USB_RMNET_CV2X)) {
 		if (ipa_pm_is_used()) {
 			ipa3_usb_deregister_pm(ttype);
 		} else {
@@ -1114,6 +1165,7 @@
 		}
 		break;
 	case IPA_USB_RMNET:
+	case IPA_USB_RMNET_CV2X:
 	case IPA_USB_MBIM:
 		if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
 			IPA_USB_TETH_PROT_INVALID) {
@@ -1131,6 +1183,102 @@
 	return true;
 }
 
+/*
+ * ipa3_usb_smmu_map_dummy: Does the same job of ipa3_usb_smmu_map_xdci_channel.
+ * API to map geventcount dummy addr, which will be provided
+ * to GSI from USB to handle sw path. Where USB driver will take
+ * care of replenishing desc to ipa hw. This dummy gevntcount addr
+ * cannot be in same page as other, since other are actual usb hw addr.
+ * We map this dummy addr to AP smmu context, so that there will
+ * not be any NOC issue when IPA/GSI tries to access it.
+ */
+static int ipa3_usb_smmu_map_dummy(
+			struct ipa_usb_xdci_chan_params *params,
+			bool map
+			)
+{
+	int result = 0;
+	u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE);
+	u32 xfer_scratch_r =
+		rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
+
+	if ((ipa3_usb_ctx->smmu_reg_map.addr != xfer_scratch_r) &&
+		(ipa3_usb_ctx->smmu_reg_map.cnt != 0)) {
+		IPA_USB_ERR("No support more than 1 page map for USB regs");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (map) {
+		if (ipa3_usb_ctx->smmu_reg_map_dummy.cnt == 0) {
+			ipa3_usb_ctx->smmu_reg_map_dummy.addr = gevntcount_r;
+			result = ipa3_smmu_map_peer_reg(
+				ipa3_usb_ctx->smmu_reg_map_dummy.addr, true,
+				IPA_SMMU_CB_AP);
+			if (result) {
+				IPA_USB_ERR("failed to map USB regs %d\n",
+					result);
+				return result;
+			}
+
+			if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
+				ipa3_usb_ctx->smmu_reg_map.addr =
+					xfer_scratch_r;
+				result = ipa3_smmu_map_peer_reg(
+					ipa3_usb_ctx->smmu_reg_map.addr, true,
+					IPA_SMMU_CB_AP);
+				if (result) {
+					IPA_USB_ERR(
+						"failed to map USB regs %d\n",
+						result);
+					return result;
+				}
+			}
+			ipa3_usb_ctx->smmu_reg_map.cnt++;
+			ipa3_usb_ctx->smmu_reg_map_dummy.cnt++;
+		}
+	} else {
+		if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map_dummy.addr) {
+			IPA_USB_ERR(
+				"No support for unmap different reg\n");
+			return -EINVAL;
+		}
+
+		if (ipa3_usb_ctx->smmu_reg_map_dummy.cnt == 1) {
+			result = ipa3_smmu_map_peer_reg(
+				ipa3_usb_ctx->smmu_reg_map_dummy.addr, false,
+				IPA_SMMU_CB_AP);
+			if (result) {
+				IPA_USB_ERR("failed to unmap USB regs %d\n",
+					result);
+				return result;
+			}
+
+			if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
+				if (xfer_scratch_r !=
+					ipa3_usb_ctx->smmu_reg_map.addr) {
+					IPA_USB_ERR(
+						"No support for un map different reg\n");
+					return -EINVAL;
+				}
+
+				result = ipa3_smmu_map_peer_reg(
+					ipa3_usb_ctx->smmu_reg_map.addr, false,
+					IPA_SMMU_CB_AP);
+				if (result) {
+					IPA_USB_ERR(
+						"failed to unmap USB regs %d\n",
+						result);
+					return result;
+				}
+			}
+			ipa3_usb_ctx->smmu_reg_map.cnt--;
+			ipa3_usb_ctx->smmu_reg_map_dummy.cnt--;
+		}
+	}
+	return result;
+}
+
 static int ipa3_usb_smmu_map_xdci_channel(
 	struct ipa_usb_xdci_chan_params *params, bool map)
 {
@@ -1139,13 +1287,22 @@
 	u32 xfer_scratch_r =
 		rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
 
-	if (gevntcount_r != xfer_scratch_r) {
+	if ((gevntcount_r != xfer_scratch_r) &&
+		(params->is_sw_path == false)) {
 		IPA_USB_ERR("No support more than 1 page map for USB regs\n");
 		WARN_ON(1);
 		return -EINVAL;
 	}
 
-	if (map) {
+	if (params->is_sw_path == true) {
+		result = ipa3_usb_smmu_map_dummy(params, map);
+		if (result) {
+			IPA_USB_ERR("failed to %s USB regs %d\n",
+				(map == true)?"map":"unmap",
+				result);
+			return result;
+		}
+	} else if (map) {
 		if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
 			ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r;
 			result = ipa3_smmu_map_peer_reg(
@@ -1184,7 +1341,6 @@
 		ipa3_usb_ctx->smmu_reg_map.cnt--;
 	}
 
-
 	result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
 		params->xfer_ring_len, map, params->sgt_xfer_rings,
 		IPA_SMMU_CB_AP);
@@ -1266,11 +1422,25 @@
 	case IPA_USB_RMNET:
 	case IPA_USB_MBIM:
 		chan_params.priv =
-			ipa3_usb_ctx->teth_bridge_params.private_data;
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].
+			private_data;
 		chan_params.notify =
-			ipa3_usb_ctx->teth_bridge_params.usb_notify_cb;
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].
+			usb_notify_cb;
 		chan_params.skip_ep_cfg =
-			ipa3_usb_ctx->teth_bridge_params.skip_ep_cfg;
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].
+			skip_ep_cfg;
+		break;
+	case IPA_USB_RMNET_CV2X:
+		chan_params.priv =
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].
+			private_data;
+		chan_params.notify =
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].
+			usb_notify_cb;
+		chan_params.skip_ep_cfg =
+			ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].
+			skip_ep_cfg;
 		break;
 	case IPA_USB_DIAG:
 		chan_params.priv = NULL;
@@ -1571,6 +1741,16 @@
 	return 0;
 }
 
+static int ipa3_get_tethering_mode(enum ipa_usb_teth_prot teth_prot)
+{
+	if (teth_prot == IPA_USB_RMNET)
+		return TETH_TETHERING_MODE_RMNET;
+	else if (teth_prot == IPA_USB_RMNET_CV2X)
+		return TETH_TETHERING_MODE_RMNET_2;
+	else
+		return TETH_TETHERING_MODE_MBIM;
+}
+
 static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
 {
 	int result;
@@ -1639,6 +1819,7 @@
 			ipa3_usb_teth_prot_to_string(teth_prot));
 		break;
 	case IPA_USB_RMNET:
+	case IPA_USB_RMNET_CV2X:
 	case IPA_USB_MBIM:
 		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
 			IPA_USB_TETH_PROT_CONNECTED) {
@@ -1646,7 +1827,8 @@
 				ipa3_usb_teth_prot_to_string(teth_prot));
 			break;
 		}
-		result = ipa3_usb_init_teth_bridge();
+
+		result = ipa3_usb_init_teth_bridge(teth_prot);
 		if (result)
 			return result;
 
@@ -1658,14 +1840,19 @@
 		teth_bridge_params.usb_ipa_pipe_hdl =
 			teth_conn_params->usb_to_ipa_clnt_hdl;
 		teth_bridge_params.tethering_mode =
-			(teth_prot == IPA_USB_RMNET) ?
-			(TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
-		teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
+			ipa3_get_tethering_mode(teth_prot);
+
+		if (teth_prot == IPA_USB_RMNET_CV2X)
+			teth_bridge_params.client_type = IPA_CLIENT_USB2_PROD;
+		else
+			teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
+
 		result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
 		if (result) {
 			ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
 			return result;
 		}
+
 		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
 			IPA_USB_TETH_PROT_CONNECTED;
 		ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
@@ -1704,11 +1891,15 @@
 	return 0;
 }
 
-static int ipa3_usb_disconnect_teth_bridge(void)
+static int ipa3_usb_disconnect_teth_bridge(enum ipa_usb_teth_prot teth_prot)
 {
 	int result;
 
-	result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
+	if (teth_prot == IPA_USB_RMNET_CV2X)
+		result = teth_bridge_disconnect(IPA_CLIENT_USB2_PROD);
+	else
+		result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
+
 	if (result) {
 		IPA_USB_ERR("failed to disconnect teth_bridge.\n");
 		return result;
@@ -1774,6 +1965,7 @@
 			ipa3_usb_teth_prot_to_string(teth_prot));
 		break;
 	case IPA_USB_RMNET:
+	case IPA_USB_RMNET_CV2X:
 	case IPA_USB_MBIM:
 		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
 			IPA_USB_TETH_PROT_CONNECTED) {
@@ -1782,7 +1974,8 @@
 				ipa3_usb_teth_bridge_prot_to_string(teth_prot));
 			return -EPERM;
 		}
-		result = ipa3_usb_disconnect_teth_bridge();
+
+		result = ipa3_usb_disconnect_teth_bridge(teth_prot);
 		if (result)
 			break;
 
@@ -1828,8 +2021,7 @@
 		return -EINVAL;
 	}
 
-	ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
-		IPA_USB_TRANSPORT_TETH;
+	ttype = IPA3_USB_GET_TTYPE(params->teth_prot);
 
 	if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
 		IPA_USB_ERR("Illegal operation.\n");
@@ -2013,7 +2205,9 @@
 	for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) {
 		if (ipa3_usb_ctx->teth_prot_ctx[i].state ==
 			IPA_USB_TETH_PROT_INITIALIZED) {
-			if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM))
+			if ((i == IPA_USB_RMNET) ||
+				(i == IPA_USB_MBIM) ||
+				(i == IPA_USB_RMNET_CV2X))
 				status->inited_prots[status->num_init_prot++] =
 					ipa3_usb_teth_bridge_prot_to_string(i);
 			else
@@ -2023,6 +2217,7 @@
 			IPA_USB_TETH_PROT_CONNECTED) {
 			switch (i) {
 			case IPA_USB_RMNET:
+			case IPA_USB_RMNET_CV2X:
 			case IPA_USB_MBIM:
 				status->teth_connected_prot =
 					ipa3_usb_teth_bridge_prot_to_string(i);
@@ -2527,6 +2722,24 @@
 			ipa3_usb_teth_prot_to_string(teth_prot),
 			ipa3_usb_teth_bridge_prot_to_string(teth_prot));
 		break;
+	case IPA_USB_RMNET_CV2X:
+		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
+			IPA_USB_TETH_PROT_INITIALIZED) {
+			IPA_USB_ERR("%s (%s) is not initialized\n",
+				ipa3_usb_teth_prot_to_string(teth_prot),
+				ipa3_usb_teth_bridge_prot_to_string(teth_prot));
+			result = -EINVAL;
+			goto bad_params;
+		}
+
+		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
+			NULL;
+		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
+			IPA_USB_TETH_PROT_INVALID;
+		IPA_USB_DBG("deinitialized %s (%s)\n",
+			ipa3_usb_teth_prot_to_string(teth_prot),
+			ipa3_usb_teth_bridge_prot_to_string(teth_prot));
+		break;
 	case IPA_USB_DIAG:
 		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
 			IPA_USB_TETH_PROT_INITIALIZED) {
@@ -2549,7 +2762,8 @@
 	}
 
 	if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
-		(ipa3_usb_ctx->num_init_prot == 0)) {
+		(ipa3_usb_ctx->num_init_prot == 0) ||
+		(teth_prot == IPA_USB_RMNET_CV2X)) {
 		if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
 			IPA_USB_ERR(
 				"failed to change state to invalid\n");
@@ -2976,6 +3190,9 @@
 	pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
 	pm_ctx->hdl = ~0;
 	pm_ctx->remote_wakeup_work = &ipa3_usb_notify_remote_wakeup_work;
+	pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH_2].pm_ctx;
+	pm_ctx->hdl = ~0;
+	pm_ctx->remote_wakeup_work = &ipa3_usb_notify_remote_wakeup_work;
 	pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
 	pm_ctx->hdl = ~0;
 	pm_ctx->remote_wakeup_work = &ipa3_usb_dpl_notify_remote_wakeup_work;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 095d60b..50bb9bc 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -1067,9 +1067,8 @@
 	 * tables
 	 */
 	if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
-	    (tbl->rule_cnt > 0) && (at_rear != 0)) {
-		IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n",
-		       tbl->rule_cnt, at_rear);
+	    (tbl->rule_cnt > 0)) {
+		IPAERR_RL("cannot add rules to default rt table\n");
 		goto error;
 	}
 
@@ -1608,6 +1607,11 @@
 		goto error;
 	}
 
+	if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+		IPAERR_RL("Default tbl rule cannot be modified\n");
+		return -EINVAL;
+	}
+
 	/* Adding check to confirm still
 	 * header entry present in header table or not
 	 */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 6de07dc..80513d2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -624,6 +624,185 @@
 	kfree(buff);
 }
 
+static void ipa3_get_usb_ep_info(
+		struct ipa_ioc_get_ep_info *ep_info,
+		struct ipa_ep_pair_info *pair_info
+		)
+{
+	int ep_index = -1, i;
+
+	ep_info->num_ep_pairs = 0;
+	for (i = 0; i < ep_info->max_ep_pairs; i++) {
+		pair_info[i].consumer_pipe_num = -1;
+		pair_info[i].producer_pipe_num = -1;
+		pair_info[i].ep_id = -1;
+	}
+
+	ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
+
+	if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+		pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+		ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_CONS);
+		if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+			pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+				ep_index;
+			pair_info[ep_info->num_ep_pairs].ep_id =
+				IPA_USB0_EP_ID;
+
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+			ep_info->num_ep_pairs++;
+		} else {
+			pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+		}
+	}
+
+	ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_PROD);
+
+	if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+		pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+		ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_CONS);
+		if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+			pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+				ep_index;
+			pair_info[ep_info->num_ep_pairs].ep_id =
+				IPA_USB1_EP_ID;
+
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+			ep_info->num_ep_pairs++;
+		} else {
+			pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+		}
+	}
+}
+
+static void ipa3_get_pcie_ep_info(
+			struct ipa_ioc_get_ep_info *ep_info,
+			struct ipa_ep_pair_info *pair_info
+			)
+{
+	int ep_index = -1, i;
+
+	ep_info->num_ep_pairs = 0;
+	for (i = 0; i < ep_info->max_ep_pairs; i++) {
+		pair_info[i].consumer_pipe_num = -1;
+		pair_info[i].producer_pipe_num = -1;
+		pair_info[i].ep_id = -1;
+	}
+
+	ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_PROD);
+
+	if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+		pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+		ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_CONS);
+		if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+			pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+				ep_index;
+			pair_info[ep_info->num_ep_pairs].ep_id =
+				IPA_PCIE0_EP_ID;
+
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+			ep_info->num_ep_pairs++;
+		} else {
+			pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+		}
+	}
+
+	ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_PROD);
+
+	if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+		pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+		ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_CONS);
+		if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+			pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+				ep_index;
+			pair_info[ep_info->num_ep_pairs].ep_id =
+				IPA_PCIE1_EP_ID;
+
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+			ep_info->num_ep_pairs++;
+		} else {
+			pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+			IPADBG("ep_pair_info consumer_pipe_num %d",
+				pair_info[ep_info->num_ep_pairs].
+				consumer_pipe_num);
+			IPADBG(" producer_pipe_num %d ep_id %d\n",
+				pair_info[ep_info->num_ep_pairs].
+				producer_pipe_num,
+				pair_info[ep_info->num_ep_pairs].ep_id);
+		}
+	}
+}
+
+
+static int ipa3_get_ep_info(struct ipa_ioc_get_ep_info *ep_info,
+							u8 *param)
+{
+	int ret = 0;
+	struct ipa_ep_pair_info *pair_info = (struct ipa_ep_pair_info *)param;
+
+	switch (ep_info->ep_type) {
+	case IPA_DATA_EP_TYP_HSUSB:
+		ipa3_get_usb_ep_info(ep_info, pair_info);
+		break;
+
+	case IPA_DATA_EP_TYP_PCIE:
+		ipa3_get_pcie_ep_info(ep_info, pair_info);
+		break;
+
+	default:
+		IPAERR_RL("Undefined ep_type %d\n", ep_info->ep_type);
+		ret = -EFAULT;
+		break;
+	}
+
+	return ret;
+}
+
 static int ipa3_send_gsb_msg(unsigned long usr_param, uint8_t msg_type)
 {
 	int retval;
@@ -689,8 +868,10 @@
 	struct ipa_ioc_rm_dependency rm_depend;
 	struct ipa_ioc_nat_dma_cmd *table_dma_cmd;
 	struct ipa_ioc_get_vlan_mode vlan_mode;
+	struct ipa_ioc_get_ep_info ep_info;
 	size_t sz;
 	int pre_entry;
+	unsigned long uptr = 0;
 
 	IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
 
@@ -1878,6 +2059,60 @@
 		}
 		break;
 
+	case IPA_IOC_GET_PHERIPHERAL_EP_INFO:
+		IPADBG("Got IPA_IOC_GET_EP_INFO\n");
+		if (copy_from_user(&ep_info, (const void __user *)arg,
+			sizeof(struct ipa_ioc_get_ep_info))) {
+			IPAERR_RL("copy_from_user fails\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		if (ep_info.max_ep_pairs != QUERY_MAX_EP_PAIRS)
+			IPAERR_RL("unexpected max_ep_pairs %d\n",
+			ep_info.max_ep_pairs);
+
+		if (ep_info.ep_pair_size !=
+			(QUERY_MAX_EP_PAIRS * sizeof(struct ipa_ep_pair_info)))
+			IPAERR_RL("unexpected ep_pair_size %d\n",
+			ep_info.max_ep_pairs);
+
+		uptr = ep_info.info;
+		if (unlikely(!uptr)) {
+			IPAERR_RL("unexpected NULL info\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		param = kzalloc(ep_info.ep_pair_size, GFP_KERNEL);
+		if (!param) {
+			IPAERR_RL("kzalloc fails\n");
+			retval = -ENOMEM;
+			break;
+		}
+
+		retval = ipa3_get_ep_info(&ep_info, param);
+		if (retval < 0) {
+			IPAERR("ipa3_get_ep_info failed\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		if (copy_to_user((void __user *)uptr, param,
+			ep_info.ep_pair_size)) {
+			IPAERR_RL("copy_to_user fails\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		if (copy_to_user((void __user *)arg, &ep_info,
+			sizeof(struct ipa_ioc_get_ep_info))) {
+			IPAERR_RL("copy_to_user fails\n");
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
 	default:
 		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 		return -ENOTTY;
@@ -2619,9 +2854,14 @@
 
 	ipa3_q6_pipe_delay(true);
 	ipa3_q6_avoid_holb();
-	if (ipa3_ctx->ipa_config_is_mhi)
+	if (ipa3_ctx->ipa_config_is_mhi) {
 		ipa3_set_reset_client_cons_pipe_sus_holb(true,
 		IPA_CLIENT_MHI_CONS);
+		if (ipa3_ctx->ipa_config_is_auto)
+			ipa3_set_reset_client_cons_pipe_sus_holb(true,
+				IPA_CLIENT_MHI2_CONS);
+	}
+
 	if (ipa3_q6_clean_q6_tables()) {
 		IPAERR("Failed to clean Q6 tables\n");
 		BUG();
@@ -2636,9 +2876,16 @@
 	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_config_is_auto)
+		ipa3_set_reset_client_prod_pipe_delay(true,
+		IPA_CLIENT_USB2_PROD);
+	if (ipa3_ctx->ipa_config_is_mhi) {
 		ipa3_set_reset_client_prod_pipe_delay(true,
 		IPA_CLIENT_MHI_PROD);
+		if (ipa3_ctx->ipa_config_is_auto)
+			ipa3_set_reset_client_prod_pipe_delay(true,
+				IPA_CLIENT_MHI2_PROD);
+	}
 
 	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	IPADBG_LOW("Exit with success\n");
@@ -6371,6 +6618,7 @@
 		/* map SMEM memory for IPA table accesses */
 		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
 				SMEM_MODEM, 0);
+		q6_smem_size = IPA_SMEM_SIZE;
 	} else {
 		IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
 		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
@@ -6383,7 +6631,7 @@
 		phys_addr_t pa_p;
 		u32 size_p;
 
-		IPA_SMMU_ROUND_TO_PAGE(iova, pa, IPA_SMEM_SIZE,
+		IPA_SMMU_ROUND_TO_PAGE(iova, pa, q6_smem_size,
 			iova_p, pa_p, size_p);
 		IPADBG("mapping 0x%lx to 0x%pa size %d\n",
 			iova_p, &pa_p, size_p);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index c4eb731..cc15baa 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -383,6 +383,7 @@
 	int res;
 	struct gsi_device_scratch gsi_scratch;
 	const struct ipa_gsi_ep_config *gsi_ep_info;
+	u32 ipa_mhi_max_ul_channels, ipa_mhi_max_dl_channels;
 
 	IPA_MHI_FUNC_ENTRY();
 
@@ -391,7 +392,16 @@
 		return -EINVAL;
 	}
 
-	if ((IPA_MHI_MAX_UL_CHANNELS + IPA_MHI_MAX_DL_CHANNELS) >
+	ipa_mhi_max_ul_channels = IPA_MHI_MAX_UL_CHANNELS;
+	ipa_mhi_max_dl_channels = IPA_MHI_MAX_DL_CHANNELS;
+
+	/* In case of Auto-pcie config, MHI2_PROD and MHI2_CONS is used */
+	if (ipa3_ctx->ipa_config_is_auto == true) {
+		ipa_mhi_max_ul_channels++;
+		ipa_mhi_max_dl_channels++;
+	}
+
+	if ((ipa_mhi_max_ul_channels + ipa_mhi_max_dl_channels) >
 		((ipa3_ctx->mhi_evid_limits[1] -
 		ipa3_ctx->mhi_evid_limits[0]) + 1)) {
 		IPAERR("Not enough event rings for MHI\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 03b0c72..60af28d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1593,12 +1593,12 @@
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
 			QMB_MASTER_SELECT_DDR,
 			{ 5, 7, 20, 24, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } },
-	[IPA_4_0_AUTO][IPA_CLIENT_ODU_PROD]            = {
-			false, IPA_v4_0_GROUP_UL_DL,
+	[IPA_4_0_AUTO][IPA_CLIENT_Q6_CV2X_PROD]            = {
+			true, IPA_v4_0_GROUP_CV2X,
 			true,
 			IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
 			QMB_MASTER_SELECT_DDR,
-			{ 1, 0, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } },
+			{ 1, 2, 8, 16, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY } },
 	[IPA_4_0_AUTO][IPA_CLIENT_ETHERNET_PROD]	  = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			true,
@@ -1606,13 +1606,13 @@
 			QMB_MASTER_SELECT_DDR,
 			{ 9, 0, 8, 16, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO][IPA_CLIENT_Q6_WAN_PROD]         = {
-			false, IPA_v4_0_GROUP_UL_DL,
+			true, IPA_v4_0_GROUP_UL_DL,
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
 			{ 3, 0, 16, 32, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO][IPA_CLIENT_Q6_CMD_PROD]	  = {
-			false, IPA_v4_0_GROUP_UL_DL,
+			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
@@ -1711,23 +1711,23 @@
 			QMB_MASTER_SELECT_DDR,
 			{ 22, 1, 9, 9, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO][IPA_CLIENT_Q6_LAN_CONS]         = {
-			false, IPA_v4_0_GROUP_UL_DL,
+			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
 			{ 14, 4, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO][IPA_CLIENT_Q6_WAN_CONS]         = {
-			false, IPA_v4_0_GROUP_UL_DL,
+			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
 			{ 13, 3, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
-	[IPA_4_0_AUTO][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
-			false, IPA_v4_0_GROUP_UL_DL,
+	[IPA_4_0_AUTO][IPA_CLIENT_Q6_CV2X_CONS] = {
+			true, IPA_v4_0_GROUP_CV2X,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 16, 5, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
+			{ 16, 5, 9, 9, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY } },
 	/* Only for test purpose */
 	/* MBIM aggregation test pipes should have the same QMB as USB_CONS */
 	[IPA_4_0_AUTO][IPA_CLIENT_TEST_CONS]           = {
@@ -1799,14 +1799,20 @@
 			IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
 			QMB_MASTER_SELECT_DDR,
 			{ 9, 0, 8, 16, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } },
+	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_CV2X_PROD]            = {
+			true, IPA_v4_0_GROUP_CV2X,
+			true,
+			IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
+			QMB_MASTER_SELECT_DDR,
+			{ 1, 2, 8, 16, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_WAN_PROD]         = {
-			false, IPA_v4_0_GROUP_UL_DL,
+			true, IPA_v4_0_GROUP_UL_DL,
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
 			{ 3, 0, 16, 32, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_CMD_PROD]	  = {
-			false, IPA_v4_0_MHI_GROUP_PCIE,
+			true, IPA_v4_0_MHI_GROUP_PCIE,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
@@ -1887,17 +1893,23 @@
 			QMB_MASTER_SELECT_DDR,
 			{ 22, 1, 9, 9, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_LAN_CONS]         = {
-			false, IPA_v4_0_MHI_GROUP_DDR,
+			true, IPA_v4_0_MHI_GROUP_DDR,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
 			{ 14, 4, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
 	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_WAN_CONS]         = {
-			false, IPA_v4_0_MHI_GROUP_DDR,
+			true, IPA_v4_0_MHI_GROUP_DDR,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
 			{ 13, 3, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } },
+	[IPA_4_0_AUTO_MHI][IPA_CLIENT_Q6_CV2X_CONS] = {
+			true, IPA_v4_0_GROUP_CV2X,
+			false,
+			IPA_DPS_HPS_SEQ_TYPE_INVALID,
+			QMB_MASTER_SELECT_DDR,
+			{ 16, 5, 9, 9, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY } },
 	[IPA_4_0_AUTO_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = {
 			true, IPA_v4_0_MHI_GROUP_DMA,
 			false,
@@ -2076,6 +2088,7 @@
 		return false;
 
 	if (client == IPA_CLIENT_USB_CONS     ||
+		client == IPA_CLIENT_USB2_CONS    ||
 	    client == IPA_CLIENT_USB_DPL_CONS ||
 	    client == IPA_CLIENT_MHI_CONS     ||
 	    client == IPA_CLIENT_HSIC1_CONS   ||
@@ -3856,6 +3869,7 @@
 
 	meta.qmap_id = param_in->qmap_id;
 	if (param_in->client == IPA_CLIENT_USB_PROD ||
+		param_in->client == IPA_CLIENT_USB2_PROD ||
 	    param_in->client == IPA_CLIENT_HSIC1_PROD ||
 	    param_in->client == IPA_CLIENT_ODU_PROD ||
 	    param_in->client == IPA_CLIENT_ETHERNET_PROD) {
@@ -5412,8 +5426,8 @@
 	case IPA_4_0_AUTO_MHI:
 		src_rsrc_type_max = IPA_v4_0_RSRC_GRP_TYPE_SRC_MAX;
 		dst_rsrc_type_max = IPA_v4_0_RSRC_GRP_TYPE_DST_MAX;
-		src_grp_idx_max = IPA_v4_0_GROUP_CV2X;
-		dst_grp_idx_max = IPA_v4_0_GROUP_CV2X;
+		src_grp_idx_max = IPA_v4_0_SRC_GROUP_MAX;
+		dst_grp_idx_max = IPA_v4_0_DST_GROUP_MAX;
 		break;
 	default:
 		IPAERR("invalid hw type index\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 530adef..35d5efc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -3479,6 +3479,7 @@
 int ipahal_fltrt_allocate_hw_sys_tbl(struct ipa_mem_buffer *tbl_mem)
 {
 	struct ipahal_fltrt_obj *obj;
+	gfp_t flag = GFP_KERNEL;
 
 	IPAHAL_DBG_LOW("Entry\n");
 
@@ -3496,10 +3497,14 @@
 
 	/* add word for rule-set terminator */
 	tbl_mem->size += obj->tbl_width;
-
+alloc:
 	tbl_mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, tbl_mem->size,
-		&tbl_mem->phys_base, GFP_KERNEL);
+		&tbl_mem->phys_base, flag);
 	if (!tbl_mem->base) {
+		if (flag == GFP_KERNEL) {
+			flag = GFP_ATOMIC;
+			goto alloc;
+		}
 		IPAHAL_ERR("fail to alloc DMA buf of size %d\n",
 			tbl_mem->size);
 		return -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
index 0f5c61e..566e7bf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -38,6 +38,12 @@
 #define TETH_ERR(fmt, args...) \
 	pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
 
+enum ipa_num_teth_iface {
+	IPA_TETH_IFACE_1 = 0,
+	IPA_TETH_IFACE_2 = 1,
+	IPA_TETH_IFACE_MAX
+};
+
 /**
  * struct ipa3_teth_bridge_ctx - Tethering bridge driver context information
  * @class: kernel class pointer
@@ -50,7 +56,7 @@
 	dev_t dev_num;
 	struct device *dev;
 	struct cdev cdev;
-	u32 modem_pm_hdl;
+	u32 modem_pm_hdl[IPA_TETH_IFACE_MAX];
 };
 static struct ipa3_teth_bridge_ctx *ipa3_teth_ctx;
 
@@ -120,21 +126,32 @@
 int ipa3_teth_bridge_disconnect(enum ipa_client_type client)
 {
 	int res = 0;
+	int *pm_hdl = NULL;
 
 	TETH_DBG_FUNC_ENTRY();
 	if (ipa_pm_is_used()) {
-		res = ipa_pm_deactivate_sync(ipa3_teth_ctx->modem_pm_hdl);
+
+		if (client == IPA_CLIENT_USB2_PROD)
+			pm_hdl = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_2];
+		else
+			pm_hdl = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_1];
+
+		res = ipa_pm_deactivate_sync(*pm_hdl);
 		if (res) {
 			TETH_ERR("fail to deactivate modem %d\n", res);
 			return res;
 		}
-		res = ipa_pm_deregister(ipa3_teth_ctx->modem_pm_hdl);
-		ipa3_teth_ctx->modem_pm_hdl = ~0;
+		res = ipa_pm_deregister(*pm_hdl);
+		*pm_hdl = ~0;
 	} else {
-		ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
-					IPA_RM_RESOURCE_Q6_CONS);
-		ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
-					IPA_RM_RESOURCE_USB_CONS);
+		if (client == IPA_CLIENT_USB2_PROD) {
+			TETH_ERR("No support for rm added/validated.\n");
+		} else {
+			ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+				IPA_RM_RESOURCE_Q6_CONS);
+			ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+				IPA_RM_RESOURCE_USB_CONS);
+		}
 	}
 	TETH_DBG_FUNC_EXIT();
 
@@ -154,23 +171,37 @@
 {
 	int res = 0;
 	struct ipa_pm_register_params reg_params;
+	u32 *pm = NULL;
 
 	memset(&reg_params, 0, sizeof(reg_params));
 
 	TETH_DBG_FUNC_ENTRY();
 
 	if (ipa_pm_is_used()) {
-		reg_params.name = "MODEM (USB RMNET)";
+		if (connect_params->tethering_mode ==
+			TETH_TETHERING_MODE_RMNET_2) {
+			reg_params.name = "MODEM (USB RMNET_CV2X)";
+			pm = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_2];
+		} else {
+			reg_params.name = "MODEM (USB RMNET)";
+			pm = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_1];
+		}
 		reg_params.group = IPA_PM_GROUP_MODEM;
 		reg_params.skip_clk_vote = true;
 		res = ipa_pm_register(&reg_params,
-			&ipa3_teth_ctx->modem_pm_hdl);
+			pm);
 		if (res) {
 			TETH_ERR("fail to register with PM %d\n", res);
 			return res;
 		}
 
-		res = ipa_pm_activate_sync(ipa3_teth_ctx->modem_pm_hdl);
+		res = ipa_pm_activate_sync(*pm);
+		goto bail;
+	}
+
+	if (connect_params->tethering_mode == TETH_TETHERING_MODE_RMNET_2) {
+		res = -EINVAL;
+		TETH_ERR("No support for rm added/validated.\n");
 		goto bail;
 	}
 
@@ -225,7 +256,7 @@
 */
 int ipa3_teth_bridge_driver_init(void)
 {
-	int res;
+	int res, i;
 
 	TETH_DBG("Tethering bridge driver init\n");
 	ipa3_teth_ctx = kzalloc(sizeof(*ipa3_teth_ctx), GFP_KERNEL);
@@ -266,7 +297,9 @@
 		goto fail_cdev_add;
 	}
 
-	ipa3_teth_ctx->modem_pm_hdl = ~0;
+	for (i = 0; i < IPA_TETH_IFACE_MAX; i++)
+		ipa3_teth_ctx->modem_pm_hdl[i] = ~0;
+
 	TETH_DBG("Tethering bridge driver init OK\n");
 
 	return 0;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a2cbfd8..4691257 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -199,6 +199,8 @@
 	ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
 	ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
 	ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
+	ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+	ICNSS_DRIVER_EVENT_IDLE_RESTART,
 	ICNSS_DRIVER_EVENT_MAX,
 };
 
@@ -291,6 +293,7 @@
 	ICNSS_MODE_ON,
 	ICNSS_BLOCK_SHUTDOWN,
 	ICNSS_PDR,
+	ICNSS_MODEM_CRASHED,
 };
 
 struct ce_irq_list {
@@ -626,6 +629,10 @@
 		return "PD_SERVICE_DOWN";
 	case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
 		return "FW_EARLY_CRASH_IND";
+	case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+		return "IDLE_SHUTDOWN";
+	case ICNSS_DRIVER_EVENT_IDLE_RESTART:
+		return "IDLE_RESTART";
 	case ICNSS_DRIVER_EVENT_MAX:
 		return "EVENT_MAX";
 	}
@@ -2361,6 +2368,7 @@
 	icnss_call_driver_shutdown(priv);
 
 	clear_bit(ICNSS_PDR, &priv->state);
+	clear_bit(ICNSS_MODEM_CRASHED, &priv->state);
 	clear_bit(ICNSS_REJUVENATE, &priv->state);
 	clear_bit(ICNSS_PD_RESTART, &priv->state);
 	priv->early_crash_ind = false;
@@ -2707,6 +2715,51 @@
 	return ret;
 }
 
+static int icnss_driver_event_idle_shutdown(void *data)
+{
+	int ret = 0;
+
+	if (!penv->ops || !penv->ops->idle_shutdown)
+		return 0;
+
+	if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
+			test_bit(ICNSS_PDR, &penv->state) ||
+			test_bit(ICNSS_REJUVENATE, &penv->state)) {
+		icnss_pr_err("SSR/PDR is already in-progress during idle shutdown callback\n");
+		ret = -EBUSY;
+	} else {
+		icnss_pr_dbg("Calling driver idle shutdown, state: 0x%lx\n",
+								penv->state);
+		icnss_block_shutdown(true);
+		ret = penv->ops->idle_shutdown(&penv->pdev->dev);
+		icnss_block_shutdown(false);
+	}
+
+	return ret;
+}
+
+static int icnss_driver_event_idle_restart(void *data)
+{
+	int ret = 0;
+
+	if (!penv->ops || !penv->ops->idle_restart)
+		return 0;
+
+	if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
+			test_bit(ICNSS_PDR, &penv->state) ||
+			test_bit(ICNSS_REJUVENATE, &penv->state)) {
+		icnss_pr_err("SSR/PDR is already in-progress during idle restart callback\n");
+		ret = -EBUSY;
+	} else {
+		icnss_pr_dbg("Calling driver idle restart, state: 0x%lx\n",
+								penv->state);
+		icnss_block_shutdown(true);
+		ret = penv->ops->idle_restart(&penv->pdev->dev);
+		icnss_block_shutdown(false);
+	}
+
+	return ret;
+}
 
 static void icnss_driver_event_work(struct work_struct *work)
 {
@@ -2753,6 +2806,12 @@
 			ret = icnss_driver_event_early_crash_ind(penv,
 								 event->data);
 			break;
+		case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+			ret = icnss_driver_event_idle_shutdown(event->data);
+			break;
+		case ICNSS_DRIVER_EVENT_IDLE_RESTART:
+			ret = icnss_driver_event_idle_restart(event->data);
+			break;
 		default:
 			icnss_pr_err("Invalid Event type: %d", event->type);
 			kfree(event);
@@ -2861,6 +2920,9 @@
 
 	priv->is_ssr = true;
 
+	if (notif->crashed)
+		set_bit(ICNSS_MODEM_CRASHED, &priv->state);
+
 	if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed &&
 	    test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
 		if (!wait_for_completion_timeout(&priv->unblock_shutdown,
@@ -3745,6 +3807,48 @@
 }
 EXPORT_SYMBOL(icnss_trigger_recovery);
 
+int icnss_idle_shutdown(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (!priv) {
+		icnss_pr_err("Invalid drvdata: dev %pK", dev);
+		return -EINVAL;
+	}
+
+	if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
+			test_bit(ICNSS_PDR, &priv->state) ||
+			test_bit(ICNSS_REJUVENATE, &penv->state)) {
+		icnss_pr_err("SSR/PDR is already in-progress during idle shutdown\n");
+		return -EBUSY;
+	}
+
+	return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+					ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(icnss_idle_shutdown);
+
+int icnss_idle_restart(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (!priv) {
+		icnss_pr_err("Invalid drvdata: dev %pK", dev);
+		return -EINVAL;
+	}
+
+	if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
+			test_bit(ICNSS_PDR, &priv->state) ||
+			test_bit(ICNSS_REJUVENATE, &penv->state)) {
+		icnss_pr_err("SSR/PDR is already in-progress during idle restart\n");
+		return -EBUSY;
+	}
+
+	return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_RESTART,
+					ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(icnss_idle_restart);
+
 
 static int icnss_smmu_init(struct icnss_priv *priv)
 {
@@ -4241,6 +4345,10 @@
 			continue;
 		case ICNSS_PDR:
 			seq_puts(s, "PDR TRIGGERED");
+			continue;
+		case ICNSS_MODEM_CRASHED:
+			seq_puts(s, "MODEM CRASHED");
+			continue;
 		}
 
 		seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index ecae4c9..d54e68b 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -98,6 +98,153 @@
 			pr_info(x);			\
 	} while (0)
 
+
+static DECLARE_WAIT_QUEUE_HEAD(event_wait);
+static DEFINE_SPINLOCK(lmk_event_lock);
+static struct circ_buf event_buffer;
+#define MAX_BUFFERED_EVENTS 8
+#define MAX_TASKNAME 128
+
+struct lmk_event {
+	char taskname[MAX_TASKNAME];
+	pid_t pid;
+	uid_t uid;
+	pid_t group_leader_pid;
+	unsigned long min_flt;
+	unsigned long maj_flt;
+	unsigned long rss_in_pages;
+	short oom_score_adj;
+	short min_score_adj;
+	unsigned long long start_time;
+	struct list_head list;
+};
+
+void handle_lmk_event(struct task_struct *selected, int selected_tasksize,
+		      short min_score_adj)
+{
+	int head;
+	int tail;
+	struct lmk_event *events;
+	struct lmk_event *event;
+	int res;
+	char taskname[MAX_TASKNAME];
+
+	res = get_cmdline(selected, taskname, MAX_TASKNAME - 1);
+
+	/* No valid process name means this is definitely not associated with a
+	 * userspace activity.
+	 */
+
+	if (res <= 0 || res >= MAX_TASKNAME)
+		return;
+
+	taskname[res] = '\0';
+
+	spin_lock(&lmk_event_lock);
+
+	head = event_buffer.head;
+	tail = READ_ONCE(event_buffer.tail);
+
+	/* Do not continue to log if no space remains in the buffer. */
+	if (CIRC_SPACE(head, tail, MAX_BUFFERED_EVENTS) < 1) {
+		spin_unlock(&lmk_event_lock);
+		return;
+	}
+
+	events = (struct lmk_event *) event_buffer.buf;
+	event = &events[head];
+
+	memcpy(event->taskname, taskname, res + 1);
+
+	event->pid = selected->pid;
+	event->uid = from_kuid_munged(current_user_ns(), task_uid(selected));
+	if (selected->group_leader)
+		event->group_leader_pid = selected->group_leader->pid;
+	else
+		event->group_leader_pid = -1;
+	event->min_flt = selected->min_flt;
+	event->maj_flt = selected->maj_flt;
+	event->oom_score_adj = selected->signal->oom_score_adj;
+	event->start_time = nsec_to_clock_t(selected->real_start_time);
+	event->rss_in_pages = selected_tasksize;
+	event->min_score_adj = min_score_adj;
+
+	event_buffer.head = (head + 1) & (MAX_BUFFERED_EVENTS - 1);
+
+	spin_unlock(&lmk_event_lock);
+
+	wake_up_interruptible(&event_wait);
+}
+
+static int lmk_event_show(struct seq_file *s, void *unused)
+{
+	struct lmk_event *events = (struct lmk_event *) event_buffer.buf;
+	int head;
+	int tail;
+	struct lmk_event *event;
+
+	spin_lock(&lmk_event_lock);
+
+	head = event_buffer.head;
+	tail = event_buffer.tail;
+
+	if (head == tail) {
+		spin_unlock(&lmk_event_lock);
+		return -EAGAIN;
+	}
+
+	event = &events[tail];
+
+	seq_printf(s, "%lu %lu %lu %lu %lu %lu %hd %hd %llu\n%s\n",
+		(unsigned long) event->pid, (unsigned long) event->uid,
+		(unsigned long) event->group_leader_pid, event->min_flt,
+		event->maj_flt, event->rss_in_pages, event->oom_score_adj,
+		event->min_score_adj, event->start_time, event->taskname);
+
+	event_buffer.tail = (tail + 1) & (MAX_BUFFERED_EVENTS - 1);
+
+	spin_unlock(&lmk_event_lock);
+	return 0;
+}
+
+static unsigned int lmk_event_poll(struct file *file, poll_table *wait)
+{
+	int ret = 0;
+
+	poll_wait(file, &event_wait, wait);
+	spin_lock(&lmk_event_lock);
+	if (event_buffer.head != event_buffer.tail)
+		ret = POLLIN;
+	spin_unlock(&lmk_event_lock);
+	return ret;
+}
+
+static int lmk_event_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, lmk_event_show, inode->i_private);
+}
+
+static const struct file_operations event_file_ops = {
+	.open = lmk_event_open,
+	.poll = lmk_event_poll,
+	.read = seq_read
+};
+
+static void lmk_event_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	event_buffer.head = 0;
+	event_buffer.tail = 0;
+	event_buffer.buf = kmalloc(
+		sizeof(struct lmk_event) * MAX_BUFFERED_EVENTS, GFP_KERNEL);
+	if (!event_buffer.buf)
+		return;
+	entry = proc_create("lowmemorykiller", 0, NULL, &event_file_ops);
+	if (!entry)
+		pr_err("error creating kernel lmk event file\n");
+}
+
 static unsigned long lowmem_count(struct shrinker *s,
 				  struct shrink_control *sc)
 {
@@ -635,6 +782,7 @@
 		lowmem_deathpending_timeout = jiffies + HZ;
 		rem += selected_tasksize;
 		rcu_read_unlock();
+		get_task_struct(selected);
 		/* give the system time to free up the memory */
 		msleep_interruptible(20);
 		trace_almk_shrink(selected_tasksize, ret,
@@ -649,6 +797,10 @@
 		     sc->nr_to_scan, sc->gfp_mask, rem);
 	mutex_unlock(&scan_mutex);
 
+	if (selected) {
+		handle_lmk_event(selected, selected_tasksize, min_score_adj);
+		put_task_struct(selected);
+	}
 	return rem;
 }
 
@@ -662,6 +814,7 @@
 {
 	register_shrinker(&lowmem_shrinker);
 	vmpressure_notifier_register(&lmk_vmpr_nb);
+	lmk_event_init();
 	return 0;
 }
 device_initcall(lowmem_init);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a2a4438..83df750 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -71,6 +71,12 @@
 module_param(cpu_to_affin, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu");
 
+/* Interrupt moderation for normal endpoints */
+static unsigned int dwc3_gadget_imod_val;
+module_param(dwc3_gadget_imod_val, int, 0644);
+MODULE_PARM_DESC(dwc3_gadget_imod_val,
+			"Interrupt moderation in usecs for normal EPs");
+
 /* XHCI registers */
 #define USB3_HCSPARAMS1		(0x4)
 #define USB3_HCCPARAMS2		(0x1c)
@@ -120,6 +126,12 @@
 #define GSI_RING_BASE_ADDR_L(n)	((QSCRATCH_REG_OFFSET + 0x130) + (n*4))
 #define GSI_RING_BASE_ADDR_H(n)	((QSCRATCH_REG_OFFSET + 0x144) + (n*4))
 
+#define IMOD(n)			((QSCRATCH_REG_OFFSET + 0x170) + (n*4))
+#define IMOD_EE_EN_MASK		BIT(12)
+#define IMOD_EE_CNT_MASK	0x7FF
+
+#define USEC_CNT	(QSCRATCH_REG_OFFSET + 0x180)
+
 #define	GSI_IF_STS	(QSCRATCH_REG_OFFSET + 0x1A4)
 #define	GSI_WR_CTRL_STATE_MASK	BIT(15)
 
@@ -4405,9 +4417,22 @@
 		msm_dwc3_perf_vote_update(mdwc, true);
 		schedule_delayed_work(&mdwc->perf_vote_work,
 				msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+		if (dwc3_gadget_imod_val > 0) {
+			dwc3_msm_write_reg(mdwc->base, USEC_CNT, 0x7D);
+			dwc3_msm_write_reg_field(mdwc->base, IMOD(0),
+						 IMOD_EE_CNT_MASK,
+						 dwc3_gadget_imod_val);
+			dwc3_msm_write_reg_field(mdwc->base, IMOD(0),
+						 IMOD_EE_EN_MASK, 0x1);
+		}
 	} else {
 		dev_dbg(mdwc->dev, "%s: turn off gadget %s\n",
 					__func__, dwc->gadget.name);
+		dwc3_msm_write_reg_field(mdwc->base, IMOD(0),
+					 IMOD_EE_EN_MASK, 0x0);
+		dwc3_msm_write_reg_field(mdwc->base, IMOD(0),
+					 IMOD_EE_CNT_MASK, 0x0);
+		dwc3_msm_write_reg(mdwc->base, USEC_CNT, 0x0);
 		cancel_delayed_work_sync(&mdwc->perf_vote_work);
 		msm_dwc3_perf_vote_update(mdwc, false);
 		pm_qos_remove_request(&mdwc->pm_qos_req_dma);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 1235287..8438999 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -744,6 +744,21 @@
 
 		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
 	}
+
+	if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) {
+		unsigned int dir;
+
+		dbg_log_string("CTRLPEND %d", dwc->ep0state);
+		dir = !!dwc->ep0_expect_in;
+		if (dwc->ep0state == EP0_DATA_PHASE)
+			dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
+		else
+			dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
+
+		dwc->eps[0]->trb_enqueue = 0;
+		dwc->eps[1]->trb_enqueue = 0;
+	}
+
 	dbg_log_string("DONE for %s(%d)", dep->name, dep->number);
 }
 
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index d58b20a..1cd612a 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -535,6 +535,7 @@
 {
 	int ret;
 	struct f_gsi *gsi = d_port_to_gsi(d_port);
+	struct f_gsi *gsi_rmnet_v2x = __gsi[USB_PROT_RMNET_V2X_IPA];
 	struct ipa_usb_xdci_chan_params *in_params =
 				&d_port->ipa_in_channel_params;
 	struct ipa_usb_xdci_chan_params *out_params =
@@ -663,6 +664,23 @@
 			gsi_channel_info.depcmd_hi_addr;
 	}
 
+	/*
+	 * When both RmNet LTE and V2X instances are enabled in a composition,
+	 * set 'is_sw_path' flag to true for LTE, so that IPA can ignore the
+	 * dummy address for GEVENTCOUNT register.
+	 */
+	in_params->is_sw_path = false;
+	if (gsi->prot_id == USB_PROT_RMNET_IPA &&
+	    gsi_rmnet_v2x->function.fs_descriptors)
+		in_params->is_sw_path = true;
+
+	if (d_port->out_ep) {
+		out_params->is_sw_path = false;
+		if (gsi->prot_id == USB_PROT_RMNET_IPA &&
+		    gsi_rmnet_v2x->function.fs_descriptors)
+			out_params->is_sw_path = true;
+	}
+
 	/* Populate connection params */
 	conn_params->max_pkt_size =
 		(cdev->gadget->speed == USB_SPEED_SUPER) ?
@@ -2206,7 +2224,6 @@
 			queue_work(gsi->c_port.uevent_wq,
 					&gsi->c_port.uevent_work);
 
-		gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
 		value = 0;
 		break;
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -2415,6 +2432,7 @@
 						unsigned int alt)
 {
 	struct f_gsi	 *gsi = func_to_gsi(f);
+	struct f_gsi	 *gsi_rmnet_v2x = __gsi[USB_PROT_RMNET_V2X_IPA];
 	struct usb_composite_dev *cdev = f->config->cdev;
 	struct net_device	*net;
 	int ret;
@@ -2489,12 +2507,18 @@
 				goto notify_ep_disable;
 			}
 
-			/* Configure EPs for GSI */
+			/*
+			 * Configure EPs for GSI. Note that when both RmNet LTE
+			 * and V2X instances are enabled in a composition,
+			 * configure HW accelerated EPs for V2X instance and
+			 * normal EPs for LTE.
+			 */
 			if (gsi->d_port.in_ep &&
 				gsi->prot_id <= USB_PROT_RMNET_V2X_IPA) {
 				if (gsi->prot_id == USB_PROT_DIAG_IPA)
 					gsi->d_port.in_ep->ep_intr_num = 3;
-				else if (gsi->prot_id == USB_PROT_RMNET_V2X_IPA)
+				else if (gsi->prot_id == USB_PROT_RMNET_IPA &&
+					 gsi_rmnet_v2x->function.fs_descriptors)
 					gsi->d_port.in_ep->ep_intr_num = 0;
 				else
 					gsi->d_port.in_ep->ep_intr_num = 2;
@@ -2505,7 +2529,8 @@
 
 			if (gsi->d_port.out_ep &&
 				gsi->prot_id <= USB_PROT_RMNET_V2X_IPA) {
-				if (gsi->prot_id == USB_PROT_RMNET_V2X_IPA)
+				if (gsi->prot_id == USB_PROT_RMNET_IPA &&
+				    gsi_rmnet_v2x->function.fs_descriptors)
 					gsi->d_port.out_ep->ep_intr_num = 0;
 				else
 					gsi->d_port.out_ep->ep_intr_num = 1;
@@ -2575,7 +2600,10 @@
 	if (gsi->prot_id == USB_PROT_DIAG_IPA ||
 				gsi->prot_id == USB_PROT_DPL_ETHER ||
 				gsi->prot_id == USB_PROT_GPS_CTRL ||
-				gsi->prot_id == USB_PROT_MBIM_IPA)
+				gsi->prot_id == USB_PROT_MBIM_IPA ||
+				gsi->prot_id == USB_PROT_RMNET_IPA ||
+				gsi->prot_id == USB_PROT_RMNET_V2X_IPA ||
+				gsi->prot_id == USB_PROT_RMNET_ETHER)
 		gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
 
 	if (gsi->c_port.uevent_wq)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8e710e0..5578aa8 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3624,8 +3624,9 @@
 	ssize_t ret;
 	int rw = iov_iter_rw(iter);
 
-#ifdef CONFIG_FS_ENCRYPTION
-	if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
+	if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)
+		&& !fscrypt_using_hardware_encryption(inode))
 		return 0;
 #endif
 
diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h
index 901dae0..b4e2128 100644
--- a/include/linux/bluetooth-power.h
+++ b/include/linux/bluetooth-power.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -88,4 +88,7 @@
 #define BT_CMD_SLIM_TEST		0xbfac
 #define BT_CMD_PWR_CTRL			0xbfad
 #define BT_CMD_CHIPSET_VERS		0xbfae
+
+#define BT_RESET_GPIO_HIGH_VAL	0x1
+
 #endif /* __LINUX_BLUETOOTH_POWER_H */
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 2c31666..b0828a0 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -754,6 +754,7 @@
 enum teth_tethering_mode {
 	TETH_TETHERING_MODE_RMNET,
 	TETH_TETHERING_MODE_MBIM,
+	TETH_TETHERING_MODE_RMNET_2,
 	TETH_TETHERING_MODE_MAX,
 };
 
diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h
index cceae83..9dbdb9f 100644
--- a/include/linux/ipa_usb.h
+++ b/include/linux/ipa_usb.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -19,9 +19,16 @@
 	IPA_USB_RMNET = 2,
 	IPA_USB_MBIM = 3,
 	IPA_USB_DIAG = 4,
+	IPA_USB_RMNET_CV2X = 5,
 	IPA_USB_MAX_TETH_PROT_SIZE
 };
 
+enum teth_bridge_params {
+	IPA_TETH_BRIDGE_1 = 0,
+	IPA_TETH_BRIDGE_2 = 1,
+	IPA_TETH_BRIDGE_MAX
+};
+
 /**
  * ipa_usb_teth_params - parameters for RDNIS/ECM initialization API
  *
@@ -151,6 +158,7 @@
 	u64 data_buff_base_addr_iova;
 	struct sg_table *sgt_xfer_rings;
 	struct sg_table *sgt_data_buff;
+	bool is_sw_path;
 };
 
 /**
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index e55353a..bff4d3f 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -51,6 +51,8 @@
 	int (*resume_noirq)(struct device *dev);
 	int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
 	int (*set_therm_state)(struct device *dev, unsigned long thermal_state);
+	int (*idle_shutdown)(struct device *dev);
+	int (*idle_restart)(struct device *dev);
 };
 
 
@@ -151,4 +153,6 @@
 extern void icnss_thermal_unregister(struct device *dev);
 extern int icnss_get_curr_therm_state(struct device *dev,
 					unsigned long *thermal_state);
+extern int icnss_idle_restart(struct device *dev);
+extern int icnss_idle_shutdown(struct device *dev);
 #endif /* _ICNSS_WLAN_H_ */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index e64942a..73d65a6 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -107,7 +107,7 @@
 #define IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING       60
 #define IPA_IOCTL_GSB_CONNECT                   61
 #define IPA_IOCTL_GSB_DISCONNECT                62
-
+#define IPA_IOCTL_GET_PHERIPHERAL_EP_INFO       63
 
 
 /**
@@ -334,11 +334,14 @@
 
 	IPA_CLIENT_MHI2_PROD			= 86,
 	IPA_CLIENT_MHI2_CONS			= 87,
+
+	IPA_CLIENT_Q6_CV2X_PROD			= 88,
+	IPA_CLIENT_Q6_CV2X_CONS			= 89,
 };
 
 #define IPA_CLIENT_DUMMY_CONS IPA_CLIENT_DUMMY_CONS1
 #define IPA_CLIENT_WIGIG4_CONS IPA_CLIENT_WIGIG4_CONS
-#define IPA_CLIENT_MAX (IPA_CLIENT_MHI2_CONS + 1)
+#define IPA_CLIENT_MAX (IPA_CLIENT_Q6_CV2X_CONS + 1)
 
 #define IPA_CLIENT_IS_APPS_CONS(client) \
 	((client) == IPA_CLIENT_APPS_LAN_CONS || \
@@ -367,20 +370,23 @@
 	(client) == IPA_CLIENT_Q6_DUN_CONS || \
 	(client) == IPA_CLIENT_Q6_DECOMP_CONS || \
 	(client) == IPA_CLIENT_Q6_DECOMP2_CONS || \
-	(client) == IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS)
+	(client) == IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS || \
+	(client) == IPA_CLIENT_Q6_CV2X_CONS)
 
 #define IPA_CLIENT_IS_Q6_PROD(client) \
 	((client) == IPA_CLIENT_Q6_LAN_PROD || \
 	(client) == IPA_CLIENT_Q6_WAN_PROD || \
 	(client) == IPA_CLIENT_Q6_CMD_PROD || \
 	(client) == IPA_CLIENT_Q6_DECOMP_PROD || \
-	(client) == IPA_CLIENT_Q6_DECOMP2_PROD)
+	(client) == IPA_CLIENT_Q6_DECOMP2_PROD || \
+	(client) == IPA_CLIENT_Q6_CV2X_PROD)
 
 #define IPA_CLIENT_IS_Q6_NON_ZIP_CONS(client) \
 	((client) == IPA_CLIENT_Q6_LAN_CONS || \
 	(client) == IPA_CLIENT_Q6_WAN_CONS || \
 	(client) == IPA_CLIENT_Q6_DUN_CONS || \
-	(client) == IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS)
+	(client) == IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS || \
+	(client) == IPA_CLIENT_Q6_CV2X_CONS)
 
 #define IPA_CLIENT_IS_Q6_ZIP_CONS(client) \
 	((client) == IPA_CLIENT_Q6_DECOMP_CONS || \
@@ -389,7 +395,8 @@
 #define IPA_CLIENT_IS_Q6_NON_ZIP_PROD(client) \
 	((client) == IPA_CLIENT_Q6_LAN_PROD || \
 	(client) == IPA_CLIENT_Q6_WAN_PROD || \
-	(client) == IPA_CLIENT_Q6_CMD_PROD)
+	(client) == IPA_CLIENT_Q6_CMD_PROD || \
+	(client) == IPA_CLIENT_Q6_CV2X_PROD)
 
 #define IPA_CLIENT_IS_Q6_ZIP_PROD(client) \
 	((client) == IPA_CLIENT_Q6_DECOMP_PROD || \
@@ -411,6 +418,8 @@
 #define IPA_CLIENT_IS_MHI(client) \
 	((client) == IPA_CLIENT_MHI_CONS || \
 	(client) == IPA_CLIENT_MHI_PROD || \
+	(client) == IPA_CLIENT_MHI2_PROD || \
+	(client) == IPA_CLIENT_MHI2_CONS || \
 	(client) == IPA_CLIENT_MHI_DPL_CONS)
 
 #define IPA_CLIENT_IS_TEST_PROD(client) \
@@ -1750,6 +1759,46 @@
 	char name[IPA_RESOURCE_NAME_MAX];
 };
 
+#define QUERY_MAX_EP_PAIRS	2
+
+#define IPA_USB0_EP_ID		11
+#define IPA_USB1_EP_ID		12
+
+#define IPA_PCIE0_EP_ID		21
+#define IPA_PCIE1_EP_ID		22
+
+enum ipa_peripheral_ep_type {
+	IPA_DATA_EP_TYP_RESERVED = 0,
+	IPA_DATA_EP_TYP_HSIC = 1,
+	IPA_DATA_EP_TYP_HSUSB = 2,
+	IPA_DATA_EP_TYP_PCIE = 3,
+	IPA_DATA_EP_TYP_EMBEDDED = 4,
+	IPA_DATA_EP_TYP_BAM_DMUX,
+};
+
+struct ipa_ep_pair_info {
+	uint32_t consumer_pipe_num;
+	uint32_t producer_pipe_num;
+	uint32_t ep_id;
+};
+
+/**
+ * struct ipa_ioc_get_ep_info - flt/rt counter id query
+ * @ep_type: type USB/PCIE - i/p param
+ * @max_ep_pairs: max number of ep_pairs (constant),
+					(QUERY_MAX_EP_PAIRS)
+ * @num_ep_pairs: number of ep_pairs - o/p param
+ * @ep_pair_size: sizeof(ipa_ep_pair_info) * max_ep_pairs
+ * @info: structure contains ep pair info
+ */
+struct ipa_ioc_get_ep_info {
+	enum ipa_peripheral_ep_type ep_type;
+	uint8_t max_ep_pairs;
+	uint8_t num_ep_pairs;
+	uint32_t ep_pair_size;
+	uintptr_t info;
+};
+
 /**
  * struct ipa_msg_meta - Format of the message meta-data.
  * @msg_type: the type of the message
@@ -2191,6 +2240,10 @@
 				IPA_IOCTL_GSB_DISCONNECT, \
 				struct ipa_ioc_gsb_info)
 
+#define IPA_IOC_GET_PHERIPHERAL_EP_INFO _IOWR(IPA_IOC_MAGIC, \
+				IPA_IOCTL_GET_PHERIPHERAL_EP_INFO, \
+				struct ipa_ioc_get_ep_info)
+
 /*
  * unique magic number of the Tethering bridge ioctls
  */
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 11e4af2f..d471752 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,6 +49,7 @@
 #include <linux/sched/deadline.h>
 #include <linux/timer.h>
 #include <linux/freezer.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 
@@ -149,6 +150,7 @@
 			raw_spin_unlock_irqrestore(&base->cpu_base->lock, *flags);
 		}
 		cpu_relax();
+		ndelay(TIMER_LOCK_TIGHT_LOOP_DELAY_NS);
 	}
 }
 
@@ -1043,6 +1045,7 @@
 		if (ret >= 0)
 			return ret;
 		cpu_relax();
+		ndelay(TIMER_LOCK_TIGHT_LOOP_DELAY_NS);
 	}
 }
 EXPORT_SYMBOL_GPL(hrtimer_cancel);
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index f7382510..0059764 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -165,3 +165,4 @@
 
 extern u64 get_next_timer_interrupt(unsigned long basej, u64 basem);
 void timer_clear_idle(void);
+#define TIMER_LOCK_TIGHT_LOOP_DELAY_NS	350
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index af9a29e..018e2f5 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -942,6 +942,7 @@
 			spin_unlock_irqrestore(&base->lock, *flags);
 		}
 		cpu_relax();
+		ndelay(TIMER_LOCK_TIGHT_LOOP_DELAY_NS);
 	}
 }
 
@@ -1264,6 +1265,7 @@
 		if (ret >= 0)
 			return ret;
 		cpu_relax();
+		ndelay(TIMER_LOCK_TIGHT_LOOP_DELAY_NS);
 	}
 }
 EXPORT_SYMBOL(del_timer_sync);