#include "t7xx_mhccif.h"
 #include "t7xx_modem_ops.h"
 #include "t7xx_pci.h"
+#include "t7xx_pci_rescan.h"
 #include "t7xx_pcie_mac.h"
 #include "t7xx_reg.h"
 #include "t7xx_state_monitor.h"
                return ret;
        }
 
+       t7xx_rescan_done();
        t7xx_pcie_mac_set_int(t7xx_dev, MHCCIF_INT);
        t7xx_pcie_mac_interrupts_en(t7xx_dev);
+       if (!t7xx_dev->hp_enable)
+               pci_ignore_hotplug(pdev);
 
        return 0;
 }
        .shutdown = t7xx_pci_shutdown,
 };
 
-module_pci_driver(t7xx_pci_driver);
+static int __init t7xx_pci_init(void)
+{
+       int ret;
+
+       t7xx_pci_dev_rescan();
+       ret = t7xx_rescan_init();
+       if (ret) {
+               pr_err("Failed to init t7xx rescan work\n");
+               return ret;
+       }
+
+       return pci_register_driver(&t7xx_pci_driver);
+}
+module_init(t7xx_pci_init);
+
+static int t7xx_always_match(struct device *dev, const void *data)
+{
+       return dev->parent->fwnode == data;
+}
+
+static void __exit t7xx_pci_cleanup(void)
+{
+       int remove_flag = 0;
+       struct device *dev;
+
+       dev = driver_find_device(&t7xx_pci_driver.driver, NULL, NULL, t7xx_always_match);
+       if (dev) {
+               pr_debug("unregister t7xx PCIe driver while device is still exist.\n");
+               put_device(dev);
+               remove_flag = 1;
+       } else {
+               pr_debug("no t7xx PCIe driver found.\n");
+       }
+
+       pci_lock_rescan_remove();
+       pci_unregister_driver(&t7xx_pci_driver);
+       pci_unlock_rescan_remove();
+       t7xx_rescan_deinit();
+
+       if (remove_flag) {
+               pr_debug("remove t7xx PCI device\n");
+               pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
+       }
+}
+
+module_exit(t7xx_pci_cleanup);
 
 MODULE_AUTHOR("MediaTek Inc");
 MODULE_DESCRIPTION("MediaTek PCIe 5G WWAN modem T7xx driver");
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, MediaTek Inc.
+ * Copyright (c) 2021-2022, Intel Corporation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":t7xx:%s: " fmt, __func__
+#define dev_fmt(fmt) "t7xx: " fmt
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include "t7xx_pci.h"
+#include "t7xx_pci_rescan.h"
+
+static struct remove_rescan_context g_mtk_rescan_context;
+
+void t7xx_pci_dev_rescan(void)
+{
+       struct pci_bus *b = NULL;
+
+       pci_lock_rescan_remove();
+       while ((b = pci_find_next_bus(b)))
+               pci_rescan_bus(b);
+
+       pci_unlock_rescan_remove();
+}
+
+void t7xx_rescan_done(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&g_mtk_rescan_context.dev_lock, flags);
+       if (g_mtk_rescan_context.rescan_done == 0) {
+               pr_debug("this is a rescan probe\n");
+               g_mtk_rescan_context.rescan_done = 1;
+       } else {
+               pr_debug("this is a init probe\n");
+       }
+       spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+}
+
+static void t7xx_remove_rescan(struct work_struct *work)
+{
+       struct pci_dev *pdev;
+       int num_retries = RESCAN_RETRIES;
+       unsigned long flags;
+
+       spin_lock_irqsave(&g_mtk_rescan_context.dev_lock, flags);
+       g_mtk_rescan_context.rescan_done = 0;
+       pdev = g_mtk_rescan_context.dev;
+       spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+
+       if (pdev) {
+               pci_stop_and_remove_bus_device_locked(pdev);
+               pr_debug("start remove and rescan flow\n");
+       }
+
+       do {
+               t7xx_pci_dev_rescan();
+               spin_lock_irqsave(&g_mtk_rescan_context.dev_lock, flags);
+               if (g_mtk_rescan_context.rescan_done) {
+                       spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+                       break;
+               }
+
+               spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+               msleep(DELAY_RESCAN_MTIME);
+       } while (num_retries--);
+}
+
+void t7xx_rescan_queue_work(struct pci_dev *pdev)
+{
+       unsigned long flags;
+
+       dev_info(&pdev->dev, "start queue_mtk_rescan_work\n");
+       spin_lock_irqsave(&g_mtk_rescan_context.dev_lock, flags);
+       if (!g_mtk_rescan_context.rescan_done) {
+               dev_err(&pdev->dev, "rescan failed because last rescan undone\n");
+               spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+               return;
+       }
+
+       g_mtk_rescan_context.dev = pdev;
+       spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+       queue_work(g_mtk_rescan_context.pcie_rescan_wq, &g_mtk_rescan_context.service_task);
+}
+
+int t7xx_rescan_init(void)
+{
+       spin_lock_init(&g_mtk_rescan_context.dev_lock);
+       g_mtk_rescan_context.rescan_done = 1;
+       g_mtk_rescan_context.dev = NULL;
+       g_mtk_rescan_context.pcie_rescan_wq = create_singlethread_workqueue(MTK_RESCAN_WQ);
+       if (!g_mtk_rescan_context.pcie_rescan_wq) {
+               pr_err("Failed to create workqueue: %s\n", MTK_RESCAN_WQ);
+               return -ENOMEM;
+       }
+
+       INIT_WORK(&g_mtk_rescan_context.service_task, t7xx_remove_rescan);
+
+       return 0;
+}
+
+void t7xx_rescan_deinit(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&g_mtk_rescan_context.dev_lock, flags);
+       g_mtk_rescan_context.rescan_done = 0;
+       g_mtk_rescan_context.dev = NULL;
+       spin_unlock_irqrestore(&g_mtk_rescan_context.dev_lock, flags);
+       cancel_work_sync(&g_mtk_rescan_context.service_task);
+       destroy_workqueue(g_mtk_rescan_context.pcie_rescan_wq);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (c) 2021, MediaTek Inc.
+ * Copyright (c) 2021-2022, Intel Corporation.
+ */
+
+#ifndef __T7XX_PCI_RESCAN_H__
+#define __T7XX_PCI_RESCAN_H__
+
+#define MTK_RESCAN_WQ "mtk_rescan_wq"
+
+#define DELAY_RESCAN_MTIME 1000
+#define RESCAN_RETRIES 35
+
+struct remove_rescan_context {
+       struct work_struct       service_task;
+       struct workqueue_struct *pcie_rescan_wq;
+       spinlock_t              dev_lock; /* protects device */
+       struct pci_dev          *dev;
+       int                     rescan_done;
+};
+
+void t7xx_pci_dev_rescan(void);
+void t7xx_rescan_queue_work(struct pci_dev *pdev);
+int t7xx_rescan_init(void);
+void t7xx_rescan_deinit(void);
+void t7xx_rescan_done(void);
+
+#endif /* __T7XX_PCI_RESCAN_H__ */