diff --git a/drivers/net/wireless/celeno/cl8k/e2p.c b/drivers/net/wireless/celeno/cl8k/e2p.c
new file mode 100644
index 000000000000..0e51d88b042a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include "utils/utils.h"
+#include "utils/file.h"
+#include "chip.h"
+#include "e2p.h"
+#include "reg/reg_access.h"
+#include "config.h"
+
+#define EEPROM_VERSION 2
+
+/* EEPROM Parameters - Suitable for ATMEL AT24C16BN */
+#define E2P_SIZE       0x800               /* 2KB = 16Kbit */
+#define E2P_PAGE_SIZE  0x10                /* 16 Bytes */
+#define E2P_PAGE_MASK  (E2P_PAGE_SIZE - 1) /* 0xF */
+#define E2P_PAGE_SHIFT 0x4
+
+#define PAGE_NUM(addr) ((addr) >> E2P_PAGE_SHIFT)
+#define PAGE_OFF(addr) ((addr) & E2P_PAGE_MASK)
+
+enum bit_num {
+       BIT0,
+       BIT1,
+       BIT2,
+       BIT3,
+       BIT4,
+       BIT5,
+       BIT6,
+       BIT7,
+       BIT8,
+       BIT9,
+       BIT10,
+       BIT11,
+       BIT12,
+       BIT13,
+       BIT14,
+       BIT15,
+       BIT16,
+       BIT17,
+       BIT18,
+       BIT19,
+       BIT20,
+       BIT21,
+       BIT22,
+       BIT23,
+       BIT24,
+       BIT25,
+       BIT26,
+       BIT27,
+       BIT28,
+       BIT29,
+       BIT30,
+       BIT31
+};
+
+/*
+ * MACSYS_I2C:: PRERLO (0x0) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERLO (I2C_REG_BASE_ADDR + 0x0)
+
+/*
+ * MACSYS_I2C:: PRERHI (0x4) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERHI (I2C_REG_BASE_ADDR + 0x4)
+
+/*
+ * MACSYS_I2C:: CTR (0x8) - Control Register
+ * Width: 8, Access: RW, Reset: 0x00.
+ */
+#define I2C_CTR (I2C_REG_BASE_ADDR + 0x8)
+
+#define EN (BIT7) /* ‘1’ the core is enabled. */
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Data
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 TXD */
+#define TXD (BIT0) /* Next byte to transmit via I2C */
+
+#define TXD_MASK (0xFF << TXD)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Address
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXADDR (I2C_REG_BASE_ADDR + 0xC)
+
+/*
+ * 7:1 TXADDR
+ * 0 RDWR
+ */
+#define TXADDR (BIT1) /* I2C Slave Address */
+#define RDWR   (BIT0) /* ‘1’ = reading from slave. ‘0’ = writing to slave. */
+
+#define TXADDR_MASK (0x7F << TXADDR)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Receive Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_RXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 RXD */
+#define RXD (BIT0) /* Last byte received via I2C. */
+#define RXD_MASK (0xFF << RXD)
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Command Register
+ * Width: 8, Access: WC, Reset: 0x00.
+ */
+#define I2C_CR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 STA
+ * 6 STO
+ * 5 RD
+ * 4 WR
+ * 3 ACK
+ * 2:1 RES
+ * 0 IACK
+ */
+#define STA  (BIT7) /* Generate (repeated) start condition. */
+#define STO  (BIT6) /* Generate stop condition. */
+#define RD   (BIT5) /* Read from slave. */
+#define WR   (BIT4) /* Write to slave. */
+#define ACK  (BIT3) /* When a receiver, sent ACK (ACK = ‘0’) or NACK (NACK = ‘1’). */
+#define IACK (BIT0) /* Interrupt acknowledge, When set, clears a pending interrupt. */
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Status Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_SR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 RX_ACK - Received acknowledge from slave - ‘1’ = No acknowledge received.
+ * 6 BUSY - I2C bus busy - ‘1’ after START signal detected. ‘0’ after STOP signal detected.
+ * 5 AL - Arbitration lost - This bit is set when the core lost arbitration.
+ * 4:2 RES
+ * 1 TIP - Transfer in progress. ‘1’ when transferring data. ‘0’ when transfer complete.
+ * 0 IF - Set when interrupt is pending, cause a processor interrupt if the IEN bit is set.
+ */
+#define RX_ACK (BIT7)
+#define BUSY   (BIT6)
+#define AL     (BIT5)
+#define TIP    (BIT1)
+#define IF     (BIT0)
+
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 3) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+
+/* E2P_MAX_POLLS should not exceed 12 iterations (attemts) */
+#define E2P_MAX_POLLS 10
+#define E2P_INITIAL_DELAY 32
+
+static int i2c_poll_xfer_acked(struct cl_chip *chip)
+{
+       u32 val = cl_reg_read_chip(chip, I2C_SR);
+       int cnt = E2P_MAX_POLLS;
+       unsigned long delay = E2P_INITIAL_DELAY;
+
+       while ((val & BIT(TIP)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+       ++cnt;
+
+       while ((val & BIT(RX_ACK)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       if (cnt >= 0)
+               return 0;
+
+       cl_dbg_chip_err(chip, "ACK FAILED\n");
+       cl_dbg_chip_trace(chip, "I2C_POLL_XFER_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+       return -1;
+}
+
+static int i2c_poll_xfer_no_acked(struct cl_chip *chip)
+{
+       u32 val = cl_reg_read_chip(chip, I2C_SR);
+       int cnt = E2P_MAX_POLLS;
+       unsigned long delay = E2P_INITIAL_DELAY;
+
+       while ((val & BIT(TIP)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       ++cnt;
+
+       while (!(val & BIT(RX_ACK)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       if (cnt >= 0)
+               return 0;
+
+       cl_dbg_chip_err(chip, "NO ACK FAILED\n");
+       cl_dbg_chip_trace(chip, "I2C_POLL_XFER_NO_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+       return -1;
+}
+
+static void i2c_write_start(struct cl_chip *chip, u16 page)
+{
+       u32 addr = I2C_EEPROM_ADDR(page) & TXADDR_MASK;
+
+       cl_reg_write_chip(chip, I2C_TXADDR, addr);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static void i2c_write(struct cl_chip *chip, u8 data)
+{
+       cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+       cl_reg_write_chip(chip, I2C_CR, BIT(WR));
+}
+
+static void i2c_write_stop(struct cl_chip *chip, u8 data)
+{
+       cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(WR));
+}
+
+static void i2c_read_start(struct cl_chip *chip, u16 page)
+{
+       u32 addr = (I2C_EEPROM_ADDR(page) & TXADDR_MASK) | BIT(RDWR);
+
+       cl_reg_write_chip(chip, I2C_TXADDR, addr);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static int i2c_read_stop(struct cl_chip *chip, u8 *data)
+{
+       cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(RD) | BIT(ACK));
+       if (i2c_poll_xfer_no_acked(chip) == -1)
+               return -1;
+       *data = cl_reg_read_chip(chip, I2C_RXD) & RXD_MASK;
+       return 0;
+}
+
+static void e2p_reg_set_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+       u32 regval = cl_reg_read_chip(chip, reg);
+
+       regval |= bit;
+       cl_reg_write_chip(chip, reg, regval);
+}
+
+static void e2p_reg_clear_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+       u32 regval = cl_reg_read_chip(chip, reg);
+
+       regval &= ~bit;
+       cl_reg_write_chip(chip, reg, regval);
+}
+
+static void e2p_enable(struct cl_chip *chip)
+{
+       /* Disable I2C Core */
+       e2p_reg_clear_bit(chip, I2C_CTR, BIT(EN));
+
+       /*
+        * Set Pre-Scaler LO
+        * pclk = 240MHz, desired SCL = 400KHz.
+        * Prescale = [240e6 / (5*400e3) ] – 1 = 120 -1 = 119 = 77h
+        */
+       cl_reg_write_chip(chip, I2C_PRERLO, 0x77);
+
+       /* Set Pre-Scaler HI */
+       cl_reg_write_chip(chip, I2C_PRERHI, 0x0);
+
+       /* Enable I2C Core */
+       e2p_reg_set_bit(chip, I2C_CTR, BIT(EN));
+}
+
+static int e2p_read_byte(struct cl_chip *chip, u16 addr, u8 *pbyte)
+{
+       if (addr > E2P_SIZE) {
+               cl_dbg_chip_err(chip, "Wrong addr or len\n");
+               return -1;
+       }
+
+       /* Clock in the address to read from. */
+       i2c_write_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+       i2c_write(chip, addr);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Read single byte */
+       i2c_read_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       return i2c_read_stop(chip, pbyte);
+}
+
+static int e2p_write_page(struct cl_chip *chip, u16 addr, u8 *val, u16 num_of_bytes)
+{
+       /* This is a write page (up to 16 bytes) operation indicating the offset to write to. */
+       int i;
+
+       if (num_of_bytes > E2P_PAGE_SIZE)
+               return -1;
+
+       /* Clock in the address to write to. */
+       i2c_write_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+       i2c_write(chip, addr);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Clock in the data to write. */
+       for (i = 0; i < (num_of_bytes - 1); i++, val++) {
+               i2c_write(chip, *val);
+               if (i2c_poll_xfer_acked(chip) == -1)
+                       return -1;
+       }
+
+       /* Clock in the last data byte to write */
+       i2c_write_stop(chip, *val);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Make sure to wait before moving to another page */
+       mdelay(4);
+
+       return 0;
+}
+
+static int e2p_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       u16 bytes_on_curr_page = 0, bytes_left_to_write = num_of_bytes;
+
+       do {
+               bytes_on_curr_page = E2P_PAGE_SIZE - PAGE_OFF(addr);
+               bytes_on_curr_page = min(bytes_left_to_write, bytes_on_curr_page);
+               bytes_left_to_write -= bytes_on_curr_page;
+
+               if (e2p_write_page(chip, addr, val, bytes_on_curr_page) == -1) {
+                       cl_dbg_chip_err(chip, "Error writing page %u offset %u\n",
+                                       PAGE_NUM(addr), PAGE_OFF(addr));
+                       /* Written less bytes than num_of_bytes */
+                       return 0;
+               }
+
+               addr += bytes_on_curr_page;
+               val += bytes_on_curr_page;
+       } while (bytes_left_to_write);
+
+       return num_of_bytes - bytes_left_to_write;
+}
+
+static int e2p_load_dev(struct cl_chip *chip)
+{
+       u8 *cache = (u8 *)chip->eeprom_cache;
+       u16 i;
+
+       for (i = 0; i < EEPROM_NUM_BYTES; i++)
+               if (e2p_read_byte(chip, i, &cache[i]) == -1)
+                       return -1;
+
+       return 0;
+}
+
+static int e2p_dev_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       void *read_block = NULL;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       read_block = (u8 *)chip->eeprom_cache + addr;
+       memcpy(val, read_block, num_of_bytes);
+
+       return num_of_bytes;
+}
+
+static int e2p_dev_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       int bytes_written = -EIO;
+       void *write_block = NULL;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       bytes_written = e2p_write_block(chip, addr, num_of_bytes, val);
+       write_block = (u8 *)chip->eeprom_cache + addr;
+       memcpy(write_block, val, num_of_bytes);
+
+       return bytes_written;
+}
+
+static int e2p_load_bin(struct cl_chip *chip)
+{
+       char filename[CL_FILENAME_MAX];
+       size_t size = 0;
+
+       if (cl_chip_is_6g(chip))
+               snprintf(filename, sizeof(filename),
+                        "eeprom/eeprom%u_cl80x6.bin", chip->idx);
+       else
+               snprintf(filename, sizeof(filename),
+                        "eeprom/eeprom%u_cl80x0.bin", chip->idx);
+
+       size = cl_file_open_and_read(chip, filename,
+                                    (char **)&chip->eeprom_cache);
+
+       if (size != EEPROM_NUM_BYTES) {
+               cl_dbg_chip_err(chip,
+                               "Invalid EEPROM size - %s (actual %zu) (expected %d)\n",
+                               filename, size, EEPROM_NUM_BYTES);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int e2p_bin_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       return -EOPNOTSUPP;
+}
+
+static int e2p_bin_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       u8 *base;
+       u16 *offset_addr;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       base = (u8 *)chip->eeprom_cache;
+       offset_addr = (u16 *)(base + addr);
+       memmove(val, offset_addr, num_of_bytes);
+
+       return num_of_bytes;
+}
+
+static int cl_e2p_init_bin(struct cl_chip *chip)
+{
+       if (e2p_load_bin(chip))
+               return -1;
+
+       chip->eeprom_read_block = e2p_bin_read_block;
+       chip->eeprom_write_block = e2p_bin_write_block;
+
+       return 0;
+}
+
+static int cl_e2p_init_dev(struct cl_chip *chip)
+{
+       chip->eeprom_cache = kzalloc(EEPROM_NUM_BYTES, GFP_KERNEL);
+
+       if (!chip->eeprom_cache)
+               return -1;
+
+       e2p_enable(chip);
+
+       if (e2p_load_dev(chip))
+               return -1;
+
+       chip->eeprom_read_block = e2p_dev_read_block;
+       chip->eeprom_write_block = e2p_dev_write_block;
+
+       return 0;
+}
+
+int cl_e2p_init(struct cl_chip *chip)
+{
+       u8 mode = chip->conf->ce_eeprom_mode;
+
+       if (mode == E2P_MODE_BIN)
+               return cl_e2p_init_bin(chip);
+       else if (mode == E2P_MODE_EEPROM)
+               return cl_e2p_init_dev(chip);
+
+       return -1;
+}
+
+void cl_e2p_close(struct cl_chip *chip)
+{
+       kfree(chip->eeprom_cache);
+}
+
+int cl_e2p_write(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+       if (size != chip->eeprom_write_block(chip, addr, size, data)) {
+               cl_dbg_chip_err(chip, "Error writing eeprom addr 0x%x\n", addr);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_e2p_read(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+       if (size != chip->eeprom_read_block(chip, addr, size, data)) {
+               cl_dbg_chip_err(chip, "Error reading eeprom addr 0x%x\n", addr);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_e2p_write_version(struct cl_chip *chip)
+{
+       u8 version = EEPROM_VERSION;
+
+       if (chip->eeprom_cache->general.version != version)
+               return cl_e2p_write(chip, &version,
+                                   SIZE_GEN_VERSION, ADDR_GEN_VERSION);
+
+       return 0;
+}
+
+int cl_e2p_get_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       u16 addr = *(u16 *)data;
+       u16 len = *((u16 *)data + 1);
+       int reply_len;
+       struct cl_e2p_get_reply *reply = NULL;
+       struct cl_chip *chip = cl_hw->chip;
+       int ret = 0;
+       u32 end = EEPROM_NUM_BYTES;
+       u8 mode = chip->conf->ce_eeprom_mode;
+
+       reply_len = sizeof(struct cl_e2p_get_reply) + len;
+       reply = kzalloc(reply_len, GFP_KERNEL);
+
+       if (!reply)
+               return -ENOMEM;
+
+       reply->e2p_mode = mode;
+
+       cl_dbg_trace(cl_hw, "addr %u len %u\n", addr, len);
+
+       if (end < (addr + len)) {
+               cl_dbg_err(cl_hw,
+                          "size check failed: last addr = 0x%x, eeprom memory end"
+                          " = 0x%x, eeprom_mode = %u\n", (addr + len),
+                          end, mode);
+               ret = -EINVAL;
+               goto e2p_fail;
+       }
+
+       if (len != chip->eeprom_read_block(chip, addr, len, reply->e2p_data)) {
+               cl_dbg_err(cl_hw, "Error reading eeprom addr 0x%x: len %u\n",
+                          addr, len);
+               ret = -EXDEV;
+               goto e2p_fail;
+       }
+
+       ret = cl_vendor_reply(cl_hw, (void *)reply, reply_len);
+
+e2p_fail:
+       kfree(reply);
+
+       return ret;
+}
+
+int cl_e2p_set_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   const void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       u16 addr = *(u16 *)data;
+       u16 len = *((u16 *)data + 1);
+       u8 *e2p_data = (u8 *)((u16 *)data + 2);
+       u32 end = EEPROM_NUM_BYTES;
+
+       cl_dbg_trace(cl_hw, "addr %u len %u\n", addr, len);
+
+       if (end < (addr + len)) {
+               cl_dbg_err(cl_hw, "Invalid E2P addr 0x%x, valid are: 0 - %u\n",
+                          addr, end);
+               return -EINVAL;
+       }
+
+       return cl_e2p_write(cl_hw->chip, e2p_data, len, addr);
+}
+
+int cl_e2p_set_wiring_id(struct wiphy *wiphy, struct wireless_dev *wdev,
+                        const void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       struct cl_chip *chip = cl_hw->chip;
+       u8 wiring_id = *(u8 *)data;
+
+       return cl_fem_set_wiring_id(chip, wiring_id);
+}
+
+int cl_e2p_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+               void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       char *ret_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       int err = 0;
+
+       if (!ret_buf)
+               return -ENOMEM;
+
+       snprintf(ret_buf, PAGE_SIZE,
+                "usage:\n"
+                "get addr <address> - Read value from specified addr\n"
+                "get mac - Read MAC address\n"
+                "get serial_number - Read serial number\n"
+                "get pwr_table_id - Read power table IDs\n"
+                "get freq_offset - Read frequency offset\n"
+                "get wiring_id - Read wiring ID\n"
+                "get fem_lut- Read FEM look up table\n"
+                "get platform_id - Read platform ID\n"
+                "get calib <ant> <ch> - Read calibrated offset for a given antenna and channel\n"
+                "get hexdump - Read entire eeprom\n"
+                "get table - Read entire eeprom and print in format of table\n"
+                "set addr <address> <value> - Write value to specified address\n"
+                "set mac <macaddr> - Write MAC addr\n"
+                "set serial_number <32 characters> - Write serial number\n"
+                "set pwr_table_id <id tcv0> <id tcv1> - Write power table IDs\n"
+                "set wiring_id <0 - 255> - Write wiring-ID\n"
+                "set fem_lut <type_num> <lut_lna_bypass> <lut_tx> <lut_rx> <lut_off> -"
+                " Write FEM look up table\n"
+                "set platform_id <val> - Write platform-id to eeprom\n"
+                "set freq_offset <0 - 959> - Write frequency offset to eeprom\n"
+                "set calib <antenna> <channel> <power> <offset> <temperature (optional)> -"
+                " Write calibrated power and power offset for a given antenna and channel\n");
+
+       err = cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+       kfree(ret_buf);
+
+       return err;
+}
+
