diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c b/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c
new file mode 100644
index 000000000000..a9c2eebaeb1f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "hw.h"
+#include "bus/pci/msg_pci.h"
+#include "bus/pci/tx_pci.h"
+#include "bus/pci/rx_pci.h"
+#include "reg/reg_macsys_gcu.h"
+#include "main.h"
+#include "ela.h"
+#include "debug.h"
+
+struct cl_pci_db {
+       u8 device_cntr;
+       struct pci_dev *dev[CHIP_MAX];
+};
+
+static struct cl_pci_db pci_db;
+
+void cl_pci_get_celeno_device(void)
+{
+       /*
+        * Search the PCI for all Celeno devices.
+        * If there are two devices sort them in ascending order.
+        */
+       struct pci_dev *dev = NULL;
+
+       while ((dev = pci_get_device(CL_VENDOR_ID, PCI_ANY_ID, dev))) {
+               pci_db.dev[pci_db.device_cntr] = dev;
+               pci_db.device_cntr++;
+
+               if (pci_db.device_cntr == CHIP_MAX) {
+                       if (pci_db.dev[CHIP0]->device > pci_db.dev[CHIP1]->device)
+                               swap(pci_db.dev[CHIP0], pci_db.dev[CHIP1]);
+
+                       break;
+               }
+       }
+}
+
+static u8 cl_pci_chip_idx(struct pci_dev *pci_dev)
+{
+       if (pci_db.device_cntr == 0)
+               cl_pci_get_celeno_device();
+
+       if (pci_db.device_cntr == 1)
+               return CHIP0;
+
+       return (pci_db.dev[CHIP0] == pci_dev) ? CHIP0 : CHIP1;
+}
+
+static const struct cl_driver_ops drv_ops = {
+       .msg_fw_send = cl_msg_pci_msg_fw_send,
+       .pkt_fw_send = cl_tx_pci_pkt_fw_send,
+};
+
+static int cl_pci_probe(struct pci_dev *pci_dev,
+                       const struct pci_device_id *pci_id)
+{
+       u16 pci_cmd;
+       int ret;
+       u8 chip_idx = cl_pci_chip_idx(pci_dev);
+       u8 step_id;
+       struct cl_chip *chip = cl_chip_alloc(chip_idx);
+
+       if (!chip) {
+               pr_err("Chip [%u] alloc failed\n", chip_idx);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = cl_chip_config_read(chip);
+       if (ret) {
+               cl_chip_dealloc(chip);
+               return 0;
+       }
+
+       chip->pci_dev = pci_dev;
+       chip->dev = &pci_dev->dev;
+       chip->bus_type = CL_BUS_TYPE_PCI;
+
+       pci_set_drvdata(pci_dev, chip);
+
+       /* Hotplug fixups */
+       pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
+       pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+       pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
+       pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
+
+       ret = pci_enable_device(pci_dev);
+       if (ret) {
+               cl_dbg_chip_err(chip, "pci_enable_device failed\n");
+               goto out;
+       }
+
+       if (!dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) {
+               cl_dbg_chip_verbose(chip, "Using 32bit DMA\n");
+       } else {
+               cl_dbg_chip_verbose(chip, "No suitable DMA available\n");
+               goto out_disable_device;
+       }
+
+       pci_set_master(pci_dev);
+
+       ret = pci_request_regions(pci_dev, chip->pci_drv.name);
+       if (ret) {
+               cl_dbg_chip_verbose(chip, "pci_request_regions failed\n");
+               goto out_disable_device;
+       }
+
+       chip->pci_bar0_virt_addr = pci_ioremap_bar(pci_dev, 0);
+       if (!chip->pci_bar0_virt_addr) {
+               cl_dbg_chip_verbose(chip, "pci_ioremap_bar 0 failed\n");
+               ret = -ENOMEM;
+               goto out_release_regions;
+       }
+
+#ifdef CONFIG_PCI_MSI
+       if (chip->conf->ci_pci_msi_enable) {
+               ret = pci_enable_msi(pci_dev);
+               if (ret)
+                       cl_dbg_chip_err(chip, "pci_enable_msi failed (%d)\n", ret);
+       }
+#endif
+
+       step_id = macsys_gcu_chip_version_step_id_getf(chip);
+       if (step_id != 0xB) {
+               cl_dbg_chip_err(chip, "Invalid Step ID: 0x%X\n", step_id);
+               ret = -EOPNOTSUPP;
+               goto out_release_regions;
+       }
+
+       ret = cl_chip_init(chip);
+       if (ret)
+               goto out_chip_deinit;
+
+       ret = cl_main_init(chip, &drv_ops);
+       if (ret)
+               goto out_chip_deinit;
+
+       if (cl_ela_init(chip))
+               cl_dbg_chip_err(chip, "Non-critical: cl_ela_init failed\n");
+
+       return 0;
+
+out_chip_deinit:
+       cl_chip_deinit(chip);
+#ifdef CONFIG_PCI_MSI
+       if (chip->conf->ci_pci_msi_enable)
+               pci_disable_msi(pci_dev);
+#endif
+       iounmap(chip->pci_bar0_virt_addr);
+out_release_regions:
+       pci_release_regions(pci_dev);
+out_disable_device:
+       pci_disable_device(pci_dev);
+out:
+
+       return ret;
+}
+
+static void cl_pci_remove(struct pci_dev *pci_dev)
+{
+       struct cl_chip *chip = pci_get_drvdata(pci_dev);
+
+       if (!chip) {
+               pr_err("%s: failed to find chip\n", __func__);
+               return;
+       }
+
+       cl_ela_deinit(chip);
+
+       cl_main_deinit(chip);
+
+       cl_chip_deinit(chip);
+
+#ifdef CONFIG_PCI_MSI
+       if (chip->conf->ci_pci_msi_enable) {
+               pci_disable_msi(pci_dev);
+               pr_debug("pci_disable_msi\n");
+       }
+#endif
+
+       iounmap(chip->pci_bar0_virt_addr);
+       cl_chip_dealloc(chip);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+}
+
+static const struct pci_device_id cl_pci_id_table[] = {
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8000) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8001) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8040) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8060) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8080) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8046) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8066) },
+       { PCI_DEVICE(CL_VENDOR_ID, 0x8086) },
+       { },
+};
+
+static struct pci_driver cl_pci_driver = {
+       .name = "cl_pci",
+       .id_table = cl_pci_id_table,
+       .probe = cl_pci_probe,
+       .remove = cl_pci_remove,
+};
+
+module_pci_driver(cl_pci_driver);
