diff mbox series

[RFC,v2,24/96] cl8k: add e2p.c

Message ID 20220524113502.1094459-25-viktor.barna@celeno.com
State New
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna May 24, 2022, 11:33 a.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/e2p.c | 771 +++++++++++++++++++++++++
 1 file changed, 771 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.c
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/e2p.c b/drivers/net/wireless/celeno/cl8k/e2p.c
new file mode 100644
index 000000000000..14e9a4498046
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.c
@@ -0,0 +1,771 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+
+#include "chip.h"
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "config.h"
+#include "utils.h"
+#include "e2p.h"
+#include "calib.h"
+#include "debug.h"
+
+#define EEPROM_VERSION 3
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+/* EEPROM Parameters - Suitable for ST-M24256 */
+#define E2P_SIZE       0x8000              /* 32KB = 256Kbit */
+#define E2P_PAGE_SIZE  0x40                /* 64 Bytes */
+#define E2P_PAGE_MASK  (E2P_PAGE_SIZE - 1) /* 0x3F */
+#define E2P_PAGE_SHIFT 0x6
+#else
+/* 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
+#endif
+
+#define PAGE_NUM(addr) ((addr) >> E2P_PAGE_SHIFT)
+#define PAGE_OFF(addr) ((addr) & E2P_PAGE_MASK)
+
+#define CH_LIST_SIZE_CL80X0         59
+#define CH_LIST_SIZE_CL80X6         105
+
+static const u8 chan_list_cl80x0[CH_LIST_SIZE_CL80X0] = {
+	36, 38, 40, 42, 44, 46, 48, 50,
+	52, 54, 56, 58, 60, 62, 64, 100,
+	102, 104, 106, 108, 110, 112, 114, 116,
+	118, 120, 122, 124, 126, 128, 132, 134,
+	136, 138, 140, 142, 144, 149, 151, 153,
+	155, 157, 159, 161, 165, 1, 2, 3,
+	4, 5, 6, 7, 8, 9, 10, 11,
+	12, 13, 14
+};
+
+static const u16 chan_list_cl80x6[CH_LIST_SIZE_CL80X6] = {
+	1, 2, 5, 9, 13, 17, 21, 25,
+	29, 33, 37, 41, 45, 49, 53, 57,
+	61, 65, 69, 73, 77, 81, 85, 89,
+	93, 97, 101, 105, 109, 113, 117, 121,
+	125, 129, 133, 137, 141, 145, 149, 153,
+	157, 161, 165, 169, 173, 177, 181, 185,
+	189, 193, 197, 201, 205, 209, 213, 217,
+	221, 225, 229, 233, 36, 38, 40, 42,
+	44, 46, 48, 50, 52, 54, 56, 58,
+	60, 62, 64, 100, 102, 104, 106, 108,
+	110, 112, 114, 116, 118, 120, 122, 124,
+	126, 128, 132, 134, 136, 138, 140, 142,
+	144, 149, 151, 153, 155, 157, 159, 161,
+	165
+};
+
+enum bit_num {
+	BIT0,
+	BIT1,
+	BIT2,
+	BIT3,
+	BIT4,
+	BIT5,
+	BIT6,
+	BIT7,
+};
+
+struct cl_e2p_work {
+	struct work_struct ws;
+	struct cl_chip *chip;
+};
+
+/*
+ * 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)
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 8) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+#else
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 3) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+#endif
+
+/* E2P_MAX_POLLS should not exceed 12 iterations (attemts) */
+#define E2P_MAX_POLLS 500
+#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 -EBADE;
+}
+
+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 -EBADE;
+}
+
+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)
+{
+	int ret = 0;
+
+	cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(RD) | BIT(ACK));
+	ret = i2c_poll_xfer_no_acked(chip);
+	if (ret < 0)
+		return ret;
+	*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);
+}
+
+/*
+ * helpers for cl_e2p_write_addr_bytes()
+ */
+static inline u16 cl_e2p_addrbyte_lo(u16 v)
+{
+	return v & 0xff;
+}
+
+static inline u16 cl_e2p_addrbyte_hi(u16 v)
+{
+	return (v >> 8) & 0xff;
+}
+
+/*
+ * Helper writing address byte(s) to the eeprom, some eeprom need two
+ * byte address cycles, some need only one.
+ */
+static int cl_e2p_write_addr_bytes(struct cl_chip *chip, u16 addr)
+{
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	int ret = 0;
+
+	/* Addr 8 msbits are 8 bits msb page */
+	i2c_write(chip, cl_e2p_addrbyte_hi(addr));
+
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+#endif
+	/* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+	i2c_write(chip, cl_e2p_addrbyte_lo(addr));
+
+	return i2c_poll_xfer_acked(chip);
+}
+
+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)
+{
+	int ret = 0;
+
+	if (addr > E2P_SIZE) {
+		cl_dbg_chip_err(chip, "Wrong addr or len\n");
+		return -EFAULT;
+	}
+
+	/* Clock in the address to read from. */
+	i2c_write_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_e2p_write_addr_bytes(chip, addr);
+	if (ret)
+		return ret;
+
+	/* Read single byte */
+	i2c_read_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	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 E2P_PAGE_SIZE bytes) operation indicating the offset
+	 * to write to.
+	 */
+	int i;
+	int ret = 0;
+
+	if (num_of_bytes > E2P_PAGE_SIZE)
+		return -EMSGSIZE;
+
+	/* Clock in the address to write to. */
+	i2c_write_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_e2p_write_addr_bytes(chip, addr);
+	if (ret)
+		return ret;
+
+	/* Clock in the data to write. */
+	for (i = 0; i < (num_of_bytes - 1); i++, val++) {
+		i2c_write(chip, *val);
+		ret = i2c_poll_xfer_acked(chip);
+		if (ret)
+			return ret;
+	}
+
+	/* Clock in the last data byte to write */
+	i2c_write_stop(chip, *val);
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	/* Wait for the write to finish */
+	mdelay(6);
+
+	return ret;
+}
+
+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;
+	int ret = 0;
+
+	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;
+
+		ret = e2p_write_page(chip, addr, val, bytes_on_curr_page);
+		if (ret) {
+			cl_dbg_chip_err(chip,
+					"Error writing page %u offset %u, ret %d\n",
+					PAGE_NUM(addr), PAGE_OFF(addr), ret);
+			/* 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;
+}
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+static void cl_e2p_init_calib_ch_bmp_per_bw(struct cl_hw *cl_hw, int data_elem_num,
+					    u16 channel_list[], int bw, int bmp_size,
+					    int bmp_addr, int eeprom_data_size, int data_addr)
+{
+	u8 chan_idx;
+	u8 chan_bmp[SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0] = {0};
+	u8 chan_bmp_prev[SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0] = {0};
+	struct eeprom_calib_data zero_calib = {0};
+	int i;
+
+	for (i = 0; i < data_elem_num; i++) {
+		chan_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel_list[i], bw);
+		if (channel_list[i] && chan_idx != INVALID_CHAN_IDX)
+			chan_bmp[chan_idx / BITS_PER_BYTE] |= (BIT(chan_idx % BITS_PER_BYTE));
+	}
+
+	cl_e2p_read(cl_hw->chip, chan_bmp_prev, bmp_size, bmp_addr);
+	if (memcmp(chan_bmp, chan_bmp_prev, bmp_size))
+		for (i = 0; i < data_elem_num; i++)
+			cl_e2p_write(cl_hw->chip, (u8 *)&zero_calib,
+				     (u16)sizeof(struct eeprom_calib_data),
+				     data_addr + (i *
+				     (u16)sizeof(struct eeprom_calib_data)));
+
+	cl_e2p_write(cl_hw->chip, chan_bmp, bmp_size,
+		     bmp_addr);
+}
+
+static void cl_e2p_init_calib_ch_bmp(struct cl_hw *cl_hw)
+{
+	if (cl_hw->tcv_idx == 0) {
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_20mhz,
+						CHNL_BW_20, SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_40mhz,
+						CHNL_BW_40, SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_80mhz,
+						CHNL_BW_80, SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_160mhz,
+						CHNL_BW_160, SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV0);
+	} else {
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_20mhz,
+						CHNL_BW_20, SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_40mhz,
+						CHNL_BW_40, SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_80mhz,
+						CHNL_BW_80, SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_160mhz,
+						CHNL_BW_160, SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV1);
+	}
+}
+
+static void e2p_read_eeprom_handler(struct work_struct *ws)
+{
+	struct cl_e2p_work *e2p_work = container_of(ws, struct cl_e2p_work, ws);
+	struct cl_chip *chip = e2p_work->chip;
+	u8 *cache = (u8 *)chip->eeprom_cache;
+	u16 i;
+
+	if (chip->conf->ce_eeprom_mode == E2P_MODE_EEPROM)
+		for (i = EEPROM_BASIC_NUM_BYTES; i < EEPROM_NUM_BYTES; i++)
+			if (e2p_read_byte(chip, i, &cache[i]) < 0)
+				return;
+
+	if (chip->cl_hw_tcv0)
+		cl_e2p_init_calib_ch_bmp(chip->cl_hw_tcv0);
+	if (chip->cl_hw_tcv1)
+		cl_e2p_init_calib_ch_bmp(chip->cl_hw_tcv1);
+
+	chip->is_calib_eeprom_loaded = 1;
+}
+
+void cl_e2p_read_eeprom_start_work(struct cl_chip *chip)
+{
+	struct cl_e2p_work *e2p_work = kzalloc(sizeof(*e2p_work), GFP_ATOMIC);
+
+	if (!e2p_work)
+		return;
+
+	e2p_work->chip = chip;
+	INIT_WORK(&e2p_work->ws, e2p_read_eeprom_handler);
+	queue_work(chip->chip_workqueue, &e2p_work->ws);
+}
+#endif
+
+static int e2p_load_from_eeprom(struct cl_chip *chip)
+{
+	u8 *cache = (u8 *)chip->eeprom_cache;
+	u16 i;
+	int ret = 0;
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	u16 eeprom_load_len = EEPROM_BASIC_NUM_BYTES;
+#else
+	u16 eeprom_load_len = EEPROM_NUM_BYTES;
+#endif
+
+	for (i = 0; i < eeprom_load_len; i++) {
+		ret = e2p_read_byte(chip, i, &cache[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int e2p_eeprom_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_eeprom_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_from_bin(struct cl_chip *chip)
+{
+	char filename[CL_FILENAME_MAX];
+	size_t size = 0;
+	char *buf = NULL;
+	int ret = 0;
+
+	if (cl_chip_is_6g(chip))
+		snprintf(filename, sizeof(filename),
+			 "eeprom%u_cl80x6.bin", chip->idx);
+	else
+		snprintf(filename, sizeof(filename),
+			 "eeprom%u_cl80x0.bin", chip->idx);
+
+	size = cl_file_open_and_read(chip, filename,
+				     (char **)&buf);
+
+	if (size < EEPROM_BASIC_NUM_BYTES) {
+		cl_dbg_chip_err(chip,
+				"Invalid EEPROM size - %s (actual %zu) (min size %d)\n",
+				filename, size, EEPROM_BASIC_NUM_BYTES);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (size > EEPROM_NUM_BYTES) {
+		cl_dbg_chip_err(chip,
+				"Invalid EEPROM size - %s (actual %zu) (max size %d)\n",
+				filename, size, EEPROM_NUM_BYTES);
+		ret = -EFBIG;
+		goto err;
+	}
+
+	if (!buf) {
+		cl_dbg_chip_err(chip, "EEPROM data buffer is empty\n");
+
+		ret = -ENODATA;
+		goto err;
+	}
+
+	chip->eeprom_bin_size = size;
+	memcpy(chip->eeprom_cache, buf, size);
+
+err:
+	kfree(buf);
+
+	return ret;
+}
+
+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 > chip->eeprom_bin_size)
+		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)
+{
+	int ret = 0;
+
+	ret = e2p_load_from_bin(chip);
+	if (ret)
+		return ret;
+
+	chip->eeprom_read_block = e2p_bin_read_block;
+	chip->eeprom_write_block = e2p_bin_write_block;
+
+	return ret;
+}
+
+static int cl_e2p_init_eeprom(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	e2p_enable(chip);
+
+	ret = e2p_load_from_eeprom(chip);
+	if (ret)
+		return ret;
+
+	chip->eeprom_read_block = e2p_eeprom_read_block;
+	chip->eeprom_write_block = e2p_eeprom_write_block;
+
+	return ret;
+}
+
+int cl_e2p_init(struct cl_chip *chip)
+{
+	u8 eeprom_mode = chip->conf->ce_eeprom_mode;
+
+	chip->eeprom_cache = kzalloc(EEPROM_NUM_BYTES, GFP_KERNEL);
+	if (!chip->eeprom_cache)
+		return -ENOMEM;
+
+	if (eeprom_mode == E2P_MODE_BIN)
+		return cl_e2p_init_bin(chip);
+	else if (eeprom_mode == E2P_MODE_EEPROM)
+		return cl_e2p_init_eeprom(chip);
+
+	return -EINVAL;
+}
+
+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 -EBADE;
+	}
+
+	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 -EBADE;
+	}
+
+	return 0;
+}