diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts
index 6c7fc881615092b91a804553a0e4568fa9b7ee92..279f051e75b60baa0620b9599be5184b72b9b176 100644
--- a/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts
+++ b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts
@@ -7,9 +7,102 @@
 #include "sa8775p-ride-r3.dts"
 #include "qcs9100-thermal.dtsi"
 
+/delete-node/ &pil_adsp_mem;
+/delete-node/ &pil_gdsp0_mem;
+/delete-node/ &pil_gdsp1_mem;
+/delete-node/ &pil_cdsp0_mem;
+/delete-node/ &pil_gpu_mem;
+/delete-node/ &pil_cdsp1_mem;
+/delete-node/ &pil_cvp_mem;
+/delete-node/ &pil_video_mem;
+/delete-node/ &audio_mdf_mem;
+/delete-node/ &trusted_apps_mem;
+
+
 / {
 	model = "Qualcomm QCS9100 Ride Rev3";
 	compatible = "qcom,qcs9100-ride-r3", "qcom,qcs9100", "qcom,sa8775p";
 	qcom,msm-id = <667 0x10000>, <667 0x20000>;
 	qcom,board-id = <0x20025 1>;
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		gunyah_md_mem: gunyah-md@91a80000 {
+			reg = <0x0 0x91a80000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_adsp_mem: pil-adsp@95900000 {
+			reg = <0x0 0x95900000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		q6_adsp_dtb_mem: q6-adsp-dtb@97700000 {
+			reg = <0x0 0x97700000 0x0 0x80000>;
+			no-map;
+		};
+
+		q6_gdsp0_dtb_mem: q6-gdsp0-dtb@97780000 {
+			reg = <0x0 0x97780000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_gdsp0_mem: pil-gdsp0@97800000 {
+			reg = <0x0 0x97800000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_gdsp1_mem: pil-gdsp1@99600000 {
+			reg = <0x0 0x99600000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		q6_gdsp1_dtb_mem: q6-gdsp1-dtb@9b400000 {
+			reg = <0x0 0x9b400000 0x0 0x80000>;
+			no-map;
+		};
+
+		q6_cdsp0_dtb_mem: q6-cdsp0-dtb@9b480000 {
+			reg = <0x0 0x9b480000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_cdsp0_mem: pil-cdsp0@9b500000 {
+			reg = <0x0 0x9b500000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_gpu_mem: pil-gpu@9d300000 {
+			reg = <0x0 0x9d300000 0x0 0x2000>;
+			no-map;
+		};
+
+		q6_cdsp1_dtb_mem: q6-cdsp1-dtb@9d380000 {
+			reg = <0x0 0x9d380000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_cdsp1_mem: pil-cdsp1@9d400000 {
+			reg = <0x0 0x9d400000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_cvp_mem: pil-cvp@9f200000 {
+			reg = <0x0 0x9f200000 0x0 0x700000>;
+			no-map;
+		};
+
+		pil_video_mem: pil-video@9f900000 {
+			reg = <0x0 0x9f900000 0x0 0x1000000>;
+			no-map;
+		};
+
+		trusted_apps_mem: trusted-apps@d1900000 {
+			reg = <0x0 0xd1900000 0x0 0x1c00000>;
+			no-map;
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts
index e5e47f28990310f7e708bb5e83a5ad110105704f..b76a51c8ad948449f738c632ad46051015892113 100644
--- a/arch/arm64/boot/dts/qcom/qcs9100-ride.dts
+++ b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts
@@ -7,9 +7,102 @@
 #include "sa8775p-ride.dts"
 #include "qcs9100-thermal.dtsi"
 
+/delete-node/ &pil_adsp_mem;
+/delete-node/ &pil_gdsp0_mem;
+/delete-node/ &pil_gdsp1_mem;
+/delete-node/ &pil_cdsp0_mem;
+/delete-node/ &pil_gpu_mem;
+/delete-node/ &pil_cdsp1_mem;
+/delete-node/ &pil_cvp_mem;
+/delete-node/ &pil_video_mem;
+/delete-node/ &audio_mdf_mem;
+/delete-node/ &trusted_apps_mem;
+
+
 / {
 	model = "Qualcomm QCS9100 Ride";
 	compatible = "qcom,qcs9100-ride", "qcom,qcs9100", "qcom,sa8775p";
 	qcom,msm-id = <667 0x10000>, <667 0x20000>;
 	qcom,board-id = <0x10019 0>, <0x10025 1>;
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		gunyah_md_mem: gunyah-md@91a80000 {
+			reg = <0x0 0x91a80000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_adsp_mem: pil-adsp@95900000 {
+			reg = <0x0 0x95900000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		q6_adsp_dtb_mem: q6-adsp-dtb@97700000 {
+			reg = <0x0 0x97700000 0x0 0x80000>;
+			no-map;
+		};
+
+		q6_gdsp0_dtb_mem: q6-gdsp0-dtb@97780000 {
+			reg = <0x0 0x97780000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_gdsp0_mem: pil-gdsp0@97800000 {
+			reg = <0x0 0x97800000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_gdsp1_mem: pil-gdsp1@99600000 {
+			reg = <0x0 0x99600000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		q6_gdsp1_dtb_mem: q6-gdsp1-dtb@9b400000 {
+			reg = <0x0 0x9b400000 0x0 0x80000>;
+			no-map;
+		};
+
+		q6_cdsp0_dtb_mem: q6-cdsp0-dtb@9b480000 {
+			reg = <0x0 0x9b480000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_cdsp0_mem: pil-cdsp0@9b500000 {
+			reg = <0x0 0x9b500000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_gpu_mem: pil-gpu@9d300000 {
+			reg = <0x0 0x9d300000 0x0 0x2000>;
+			no-map;
+		};
+
+		q6_cdsp1_dtb_mem: q6-cdsp1-dtb@9d380000 {
+			reg = <0x0 0x9d380000 0x0 0x80000>;
+			no-map;
+		};
+
+		pil_cdsp1_mem: pil-cdsp1@9d400000 {
+			reg = <0x0 0x9d400000 0x0 0x1e00000>;
+			no-map;
+		};
+
+		pil_cvp_mem: pil-cvp@9f200000 {
+			reg = <0x0 0x9f200000 0x0 0x700000>;
+			no-map;
+		};
+
+		pil_video_mem: pil-video@9f900000 {
+			reg = <0x0 0x9f900000 0x0 0x1000000>;
+			no-map;
+		};
+
+		trusted_apps_mem: trusted-apps@d1900000 {
+			reg = <0x0 0xd1900000 0x0 0x1c00000>;
+			no-map;
+		};
+	};
 };
diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
index 29f0e4945f1924eabd30b055da16e596bc25ebef..4a1c22cbb07c6bedc9ee82057d842fca23b0c03a 100644
--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -3,6 +3,7 @@
  * Hardware monitoring driver for EMC2305 fan controller
  *
  * Copyright (C) 2022 Nvidia Technologies Ltd.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/err.h>
@@ -530,6 +531,18 @@ static int emc2305_identify(struct device *dev)
 	return 0;
 }
 
+
+static int emc2305_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	strscpy(info->type, "emc2303", I2C_NAME_SIZE);
+	return 0;
+}
+
 static int emc2305_probe(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
@@ -618,10 +631,27 @@ static struct i2c_driver emc2305_driver = {
 	.probe = emc2305_probe,
 	.remove	  = emc2305_remove,
 	.id_table = emc2305_ids,
+	.detect = emc2305_detect,
 	.address_list = emc2305_normal_i2c,
 };
 
-module_i2c_driver(emc2305_driver);
+static struct i2c_board_info emc2305_i2c_info = {
+	I2C_BOARD_INFO("emc2303", 0x2c),
+};
+
+static int __init emc2305_init(void)
+{
+	i2c_register_board_info(1, &emc2305_i2c_info, 1);
+	return i2c_add_driver(&emc2305_driver);
+}
+
+static void __exit emc2305_exit(void)
+{
+	i2c_del_driver(&emc2305_driver);
+}
+
+module_init(emc2305_init);
+module_exit(emc2305_exit);
 
 MODULE_AUTHOR("Nvidia");
 MODULE_DESCRIPTION("Microchip EMC2305 fan controller driver");
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index bba9ed302f78b426650e41cdfcccf707cb8625b1..3db0aa2c98e5a57193aeb9a05264f8563e76f252 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -329,6 +329,7 @@ struct ath11k_vif {
 
 	u16 tx_seq_no;
 	struct wmi_wmm_params_all_arg wmm_params;
+	struct wmi_wmm_params_all_arg muedca_params;
 	struct list_head list;
 	union {
 		struct {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index ffb99502f23d95f98ed963f25467cdca1c97c976..1658a0f06cfafb2d5a21ceff20fa528e0b0d407e 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -5097,6 +5097,51 @@ static int ath11k_conf_tx_uapsd(struct ath11k *ar, struct ieee80211_vif *vif,
 	return ret;
 }
 
+static int ath11k_mac_op_conf_tx_mu_edca(struct ieee80211_hw *hw,
+					 struct ieee80211_vif *vif,
+					 unsigned int link_id, u16 ac,
+					 const struct ieee80211_tx_queue_params *params)
+{
+	struct ath11k *ar = hw->priv;
+	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+	struct wmi_wmm_params_arg *p = NULL;
+	int ret;
+
+	switch (ac) {
+	case IEEE80211_AC_VO:
+		p = &arvif->muedca_params.ac_vo;
+		break;
+	case IEEE80211_AC_VI:
+		p = &arvif->muedca_params.ac_vi;
+		break;
+	case IEEE80211_AC_BE:
+		p = &arvif->muedca_params.ac_be;
+		break;
+	case IEEE80211_AC_BK:
+		p = &arvif->muedca_params.ac_bk;
+		break;
+	}
+
+	if (WARN_ON(!p)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	p->cwmin = params->mu_edca_param_rec.ecw_min_max & 0x0f;
+	p->cwmax = (params->mu_edca_param_rec.ecw_min_max & 0xf0) >> 4;
+	p->aifs = params->mu_edca_param_rec.aifsn & 0x0f;
+	p->txop = params->mu_edca_param_rec.mu_edca_timer;
+
+	ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
+						 &arvif->muedca_params,
+						 WMM_PARAM_TYPE_11AX_MU_EDCA);
+	if (ret)
+		ath11k_warn(ar->ab, "failed to set mu_edca params: %d\n", ret);
+
+exit:
+	return ret;
+}
+
 static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
 				 unsigned int link_id, u16 ac,
@@ -5135,12 +5180,21 @@ static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
 	p->txop = params->txop;
 
 	ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
-						 &arvif->wmm_params);
+					 &arvif->wmm_params, WMM_PARAM_TYPE_LEGACY);
 	if (ret) {
 		ath11k_warn(ar->ab, "failed to set wmm params: %d\n", ret);
 		goto exit;
 	}
 
+	if (params->mu_edca) {
+		ret = ath11k_mac_op_conf_tx_mu_edca(hw, vif, link_id, ac,
+						    params);
+		if (ret) {
+			ath11k_warn(ar->ab, "failed to set mu_edca params: %d\n", ret);
+			goto exit;
+		}
+	}
+
 	ret = ath11k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
 
 	if (ret)
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index f99de4874df119475f9a59812a5d40b4625743f7..4955570bcc85e44070fb3b1c9ba5b7ca0f3ba49a 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -2554,7 +2554,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
 }
 
 int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
-				       struct wmi_wmm_params_all_arg *param)
+				       struct wmi_wmm_params_all_arg *param, u32 wmm_param_type)
 {
 	struct ath11k_pdev_wmi *wmi = ar->wmi;
 	struct wmi_vdev_set_wmm_params_cmd *cmd;
@@ -2573,7 +2573,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
 			  FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 
 	cmd->vdev_id = vdev_id;
-	cmd->wmm_param_type = 0;
+	cmd->wmm_param_type = wmm_param_type;
 
 	for (ac = 0; ac < WME_NUM_AC; ac++) {
 		switch (ac) {
@@ -2606,8 +2606,8 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
 		wmm_param->no_ack = wmi_wmm_arg->no_ack;
 
 		ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
-			   "wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",
-			   ac, wmm_param->aifs, wmm_param->cwmin,
+			   "wmm set type %d ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",
+			   wmm_param_type, ac, wmm_param->aifs, wmm_param->cwmin,
 			   wmm_param->cwmax, wmm_param->txoplimit,
 			   wmm_param->acm, wmm_param->no_ack);
 	}
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 2b0eefe17ce3b89d414a0e0ff205b69ef53b9d77..363c8dac25d5ee69bab127f19fc4fe1557c79a73 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -6292,6 +6292,11 @@ enum wmi_sta_keepalive_method {
 #define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT	30
 #define WMI_STA_KEEPALIVE_INTERVAL_DISABLE	0
 
+enum wmm_edca_params_type {
+	WMM_PARAM_TYPE_LEGACY = 0,
+	WMM_PARAM_TYPE_11AX_MU_EDCA = 1,
+};
+
 const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
 					size_t len, gfp_t gfp);
 int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
@@ -6346,7 +6351,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
 int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar,
 				  struct scan_cancel_param *param);
 int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
-				       struct wmi_wmm_params_all_arg *param);
+				       struct wmi_wmm_params_all_arg *param, u32 wmm_param_type);
 int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt,
 			    u32 pdev_id);
 int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 99b15b77dfd576dace539b7166dd574fe134fcdf..6659e917ea261988c8ed7a5e7ab4fcdaac925e14 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -251,6 +251,15 @@ config USB_EZUSB_FX2
 	  Say Y here if you need EZUSB device support.
 	  (Cypress FX/FX2/FX2LP microcontrollers)
 
+config USB_HUB_USB5807
+	tristate "USB5807 Hub Controller Configuration Driver"
+	depends on I2C
+	help
+	  This option enables support for configuration via SMBus of the
+	  Microchip USB5807 USB 3.1 Hub Controller. Configuration parameters may
+	  be set in devicetree.
+	  Say Y or M here if you need to configure such a device via SMBus.
+
 config USB_HUB_USB251XB
 	tristate "USB251XB Hub Controller Configuration Driver"
 	depends on I2C
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 1992cc284d8aba91f2229810d6b1d9e3b663ef2e..e827ed251fa53e6adef67aea7149e614fc3cb76f 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_USB_USS720)		+= uss720.o
 obj-$(CONFIG_USB_SEVSEG)		+= usbsevseg.o
 obj-$(CONFIG_USB_YUREX)			+= yurex.o
 obj-$(CONFIG_USB_HUB_USB251XB)		+= usb251xb.o
+obj-$(CONFIG_USB_HUB_USB5807)		+= usb5807.o
 obj-$(CONFIG_USB_HSIC_USB3503)		+= usb3503.o
 obj-$(CONFIG_USB_HSIC_USB4604)		+= usb4604.o
 obj-$(CONFIG_USB_CHAOSKEY)		+= chaoskey.o
diff --git a/drivers/usb/misc/usb5807.c b/drivers/usb/misc/usb5807.c
new file mode 100644
index 0000000000000000000000000000000000000000..d37d682c1a12aff5aa4e6c725a9affddae446e05
--- /dev/null
+++ b/drivers/usb/misc/usb5807.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Microchip USB5807 USB 3.1 Hub
+ * Configuration via SMBus.
+ *
+ * Copyright (c) 2023 Topic Embedded Products
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#define USB5807_CMD_ATTACH 0xAA55
+#define USB5807_CMD_CONFIG 0x9937
+
+#define USB5807_REG_LANE_SWAP 0x30FA
+
+#define USB5807_NUM_PORTS 7
+
+
+static int usb5807_write(struct i2c_client *i2c, void *buf, u8 len)
+{
+	int ret;
+	struct i2c_msg msg = {
+		.addr	= i2c->addr,
+		.flags  = 0x0,
+		.len	= len,
+		.buf	= buf,
+	};
+
+	ret = i2c_transfer(i2c->adapter, &msg, 1);
+	return ret < 0 ? ret : 0;
+}
+
+/*
+ * Send a command sequence, which is an I2C write transaction, with the command
+ * word in big endian and a terminating "0" byte.
+ */
+static int usb5807_command(struct i2c_client *i2c, u16 cmd)
+{
+	u8 buf[3] = {cmd >> 8, cmd & 0xff, 0};
+
+	return usb5807_write(i2c, buf, sizeof(buf));
+}
+
+static int usb5807_prepare_reg_u8(struct i2c_client *i2c, u16 reg, u8 value)
+{
+	u8 buf[] = {
+		0x00,
+		0x00,		/* Memory offset */
+		1 + 4,		/* Transaction size */
+		0x00,		/* 0 = Register write operation */
+		1,		/* Size of register data */
+		(reg >> 8) & 0xff,
+		reg & 0xff,	/* Register offset */
+		value,		/* Register data */
+		0		/* Terminating zero */
+	};
+
+	return usb5807_write(i2c, buf, sizeof(buf));
+}
+
+/*
+ * Write an 8-bit register. First we must write the "set register" operation to
+ * the chip's internal memory at offset 0, then issue a command to execute said
+ * operation.
+ */
+static int usb5807_write_reg_u8(struct i2c_client *i2c, u16 reg, u8 value)
+{
+	int ret;
+
+	ret = usb5807_prepare_reg_u8(i2c, reg, value);
+	if (ret)
+		return ret;
+
+	return usb5807_command(i2c, USB5807_CMD_CONFIG);
+}
+
+/* Decode array of port numbers property into bit mask */
+static u8 usb5807_get_ports_field(struct device *dev, const char *prop_name)
+{
+	struct property *prop;
+	const __be32 *p;
+	u32 port;
+	u8 result = 0;
+
+	of_property_for_each_u32(dev->of_node, prop_name, prop, p, port) {
+		if (port < USB5807_NUM_PORTS)
+			result |= BIT(port);
+		else
+			dev_warn(dev, "%s: port %u doesn't exist\n", prop_name,
+				 port);
+	}
+	return result;
+}
+
+static int usb5807_i2c_probe(struct i2c_client *i2c)
+{
+	struct device_node *np = i2c->dev.of_node;
+	struct gpio_desc *reset_gpio;
+	int ret;
+	u8 val;
+
+	/* Reset the chip to bring it into configuration mode */
+	reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset",
+					     GPIOD_OUT_HIGH);
+	if (IS_ERR(reset_gpio)) {
+		dev_warn(&i2c->dev, "Failed to request reset GPIO\n");
+		reset_gpio = NULL;
+	}
+	/* Reset timing: Assert for >= 5 us */
+	usleep_range(5, 10);
+
+	/* Lock the bus for >= 1ms while the hub reads the I2C strapping */
+	i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
+
+	if (reset_gpio)
+		gpiod_set_value_cansleep(reset_gpio, 0);
+
+	usleep_range(1000, 2000);
+
+	i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
+
+	/* The hub device needs additional time to boot up */
+	msleep(20);
+
+	val = usb5807_get_ports_field(&i2c->dev, "swap-dx-lanes");
+	if (val) {
+		ret = usb5807_write_reg_u8(i2c, USB5807_REG_LANE_SWAP, val);
+		if (ret < 0)
+			dev_err(&i2c->dev, "Failed writing config: %d\n", ret);
+	}
+
+	/*
+	 * Send the "Attach" command which makes the device disappear from the
+	 * I2C bus and starts USB enumeration.
+	 */
+	ret = usb5807_command(i2c, USB5807_CMD_ATTACH);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed sending ATTACH command: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id usb5807_of_match[] = {
+	{ .compatible = "microchip,usb5807" },
+	{ } /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, usb5807_of_match);
+
+static const struct i2c_device_id usb5807_id[] = {
+	{ "usb5807", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, usb5807_id);
+
+static struct i2c_driver usb5807_i2c_driver = {
+	.driver = {
+		.name = "usb5807",
+		.of_match_table = of_match_ptr(usb5807_of_match),
+	},
+	.probe    = usb5807_i2c_probe,
+	.id_table = usb5807_id,
+};
+
+module_i2c_driver(usb5807_i2c_driver);
+
+MODULE_DESCRIPTION("USB5807 USB 3.1 Hub Controller Driver");
+MODULE_LICENSE("GPL");