diff --git a/drivers/net/wireless/celeno/cl8k/chip_config.c b/drivers/net/wireless/celeno/cl8k/chip_config.c
new file mode 100644
index 000000000000..c6d60ff685d5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip_config.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip_config.h"
+#include "chip.h"
+#include "utils/file.h"
+#include "config.h"
+
+#define MAX_FIRST_MASK_BIT ((ETH_ALEN * 8) - 1)
+
+static struct cl_chip_conf chip_conf = {
+       .ce_tcv_enabled = {
+               [TCV0] = false,
+               [TCV1] = false
+       },
+       .ce_lmac = "lmacfw.bin",
+       .ce_smac = "smacfw.bin",
+       .ce_umac = "no_load",
+       .ce_irq_smp_affinity = -1,
+       .ce_eeprom_mode = E2P_MODE_BIN,
+       .ce_production_mode = false,
+       .ci_pci_msi_enable = true,
+       .ci_dma_lli_max_chan = {
+               [TCV0] = 6,
+               [TCV1] = 3
+       },
+       .ce_country_code = "EU",
+       .ce_ela_mode = "default",
+       .ci_phy_dev = PHY_DEV_OLYMPUS,
+       .ce_debug_level = DBG_LVL_ERROR,
+       .ce_host_pci_gen_ver = 3,
+       .ce_temp_comp_en = false,
+       .ce_temp_protect_en = TEMP_PROTECT_OFF,
+       .ce_temp_protect_delta = 0,
+       .ce_temp_protect_th_max = 110,
+       .ce_temp_protect_th_min = 100,
+       .ce_temp_protect_tx_period_ms = 50,
+       .ce_temp_protect_radio_off_th = 115,
+       .ce_phys_mac_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       .ce_lam_enable = true,
+       .ce_first_mask_bit = 0,
+       .ci_no_capture_noise_sleep = true,
+       .ci_dcoc_mv_thr = {
+               [CHNL_BW_20] = 150,
+               [CHNL_BW_40] = 100,
+               [CHNL_BW_80] = 100,
+               [CHNL_BW_160] = 100
+       },
+       .ci_lolc_db_thr = -40,
+       .ci_iq_db_thr = -46,
+       .ci_rx_resched_tasklet = false,
+       .ci_rx_skb_max = 10000,
+       .ce_calib_scan_en = false,
+};
+
+static int update_config(struct cl_chip *chip, char *name, char *value)
+{
+       struct cl_chip_conf *conf = chip->conf;
+
+       READ_BOOL_ARR(ce_tcv_enabled, TCV_MAX);
+       READ_STR(ce_lmac);
+       READ_STR(ce_smac);
+       READ_STR(ce_umac);
+       READ_S32(ce_irq_smp_affinity);
+       READ_U8(ce_eeprom_mode);
+       READ_BOOL(ce_production_mode);
+       READ_BOOL(ci_pci_msi_enable);
+       READ_U8_ARR(ci_dma_lli_max_chan, TCV_MAX);
+       READ_STR(ce_country_code);
+       READ_STR(ce_ela_mode);
+       READ_U8(ci_phy_dev);
+       READ_S8(ce_debug_level);
+       READ_U8(ce_host_pci_gen_ver);
+       READ_BOOL(ce_temp_comp_en);
+       READ_U8(ce_temp_protect_en);
+       READ_S8(ce_temp_protect_delta);
+       READ_S16(ce_temp_protect_th_max);
+       READ_S16(ce_temp_protect_th_min);
+       READ_U16(ce_temp_protect_tx_period_ms);
+       READ_S16(ce_temp_protect_radio_off_th);
+       READ_MAC(ce_phys_mac_addr);
+       READ_BOOL(ce_lam_enable);
+       READ_U8(ce_first_mask_bit);
+       READ_BOOL(ci_no_capture_noise_sleep);
+       READ_U8_ARR(ci_dcoc_mv_thr, CHNL_BW_MAX);
+       READ_S8(ci_lolc_db_thr);
+       READ_S8(ci_iq_db_thr);
+       READ_BOOL(ci_rx_resched_tasklet);
+       READ_U32(ci_rx_skb_max);
+       READ_BOOL(ce_calib_scan_en);
+
+       if (!cl_config_is_non_driver_param(name)) {
+               CL_DBG_ERROR_CHIP(chip, "No matching conf for nvram parameter %s\n", name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int post_configuration(struct cl_chip *chip)
+{
+       struct cl_chip_conf *conf = chip->conf;
+
+       if (!conf->ce_tcv_enabled[TCV0] && conf->ce_tcv_enabled[TCV1]) {
+               CL_DBG_ERROR_CHIP(chip,
+                                 "TCV1 can't be enabled without enabling TCV0\n");
+               return -EINVAL;
+       }
+
+       if (conf->ce_eeprom_mode >= E2P_MODE_MAX) {
+               CL_DBG_ERROR_CHIP(chip,
+                                 "Invalid ce_eeprom_mode [%u]. Must be 0 (file) or 1 (eeprom)\n",
+                                 conf->ce_eeprom_mode);
+               return -EINVAL;
+       }
+
+       if (conf->ce_first_mask_bit > MAX_FIRST_MASK_BIT) {
+               CL_DBG_ERROR_CHIP(chip, "Invalid ce_first_mask_bit (%u). Must be <= %u\n",
+                                 conf->ce_first_mask_bit, MAX_FIRST_MASK_BIT);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int set_all_params_from_buf(struct cl_chip *chip, char *buf, loff_t size)
+{
+       char *line = buf;
+       char name[MAX_PARAM_NAME_LENGTH];
+       char value[STR_LEN_256B];
+       char *begin;
+       char *end;
+       int ret = 0;
+       int name_length = 0;
+       int value_length = 0;
+
+       while (line && strlen(line) && (line != (buf + size))) {
+               if ((*line == '#') || (*line == '\n')) {
+                       /* Skip comment or blank line */
+                       line = strstr(line, "\n") + 1;
+               } else if (*line) {
+                       begin = line;
+                       end = strstr(begin, "=");
+
+                       if (!end) {
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       end++;
+                       name_length = end - begin;
+                       value_length = strstr(end, "\n") - end + 1;
+
+                       if (name_length >= MAX_PARAM_NAME_LENGTH) {
+                               cl_dbg_chip_err(chip, "Name too long (%u)\n", name_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+                       if (value_length >= STR_LEN_256B) {
+                               cl_dbg_chip_err(chip, "Value too long (%u)\n", value_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       snprintf(name, name_length, "%s", begin);
+                       snprintf(value, value_length, "%s", end);
+
+                       ret = update_config(chip, name, value);
+                       if (ret)
+                               goto exit;
+
+                       line = strstr(line, "\n") + 1;
+               }
+       }
+
+exit:
+
+       return ret;
+}
+
+int cl_chip_config_read(struct cl_chip *chip)
+{
+       char *buf = NULL;
+       loff_t size = 0;
+       int ret = 0;
+       char filename[CL_FILENAME_MAX] = {0};
+
+       /* Allocate cl_chip_conf */
+       chip->conf = kzalloc(sizeof(*chip->conf), GFP_KERNEL);
+       if (!chip->conf)
+               return -ENOMEM;
+
+       /* Copy default parameters */
+       memcpy(chip->conf, &chip_conf, sizeof(*chip->conf));
+
+       snprintf(filename, sizeof(filename), "cl_chip%u.dat", chip->idx);
+       pr_debug("%s: %s\n", __func__, filename);
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf) {
+               pr_err("read %s failed !!!\n", filename);
+               return -ENODATA;
+       }
+
+       ret = set_all_params_from_buf(chip, buf, size);
+       if (ret) {
+               kfree(buf);
+               return ret;
+       }
+
+       kfree(buf);
+
+       if (!cl_chip_is_enabled(chip)) {
+               cl_dbg_chip_verbose(chip, "Disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       ret = post_configuration(chip);
+
+       return ret;
+}
+
+int cl_chip_config_set(struct cl_chip *chip, char *buf, loff_t size)
+{
+       loff_t new_size = size + 1;
+       char *new_buf = kzalloc(new_size, GFP_KERNEL);
+       int ret;
+
+       if (!new_buf)
+               return -ENOMEM;
+
+       /* Add '\n' at the end of the string, before the NULL */
+       memcpy(new_buf, buf, size);
+       new_buf[size - 1] = '\n';
+
+       ret = set_all_params_from_buf(chip, new_buf, new_size);
+       if (ret == 0)
+               ret = post_configuration(chip);
+
+       kfree(new_buf);
+
+       return ret;
+}
+
+void cl_chip_config_dealloc(struct cl_chip *chip)
+{
+       kfree(chip->conf);
+}
+
+void cl_chip_config_print(struct cl_chip *chip)
+{
+       struct cl_chip_conf *conf = chip->conf;
+
+       pr_debug("=======================\n");
+       pr_debug("  Chip%u configuration\n", chip->idx);
+       pr_debug("=======================\n");
+
+       print_unsigned_arr(ce_tcv_enabled, TCV_MAX);
+       print_str(ce_lmac);
+       print_str(ce_smac);
+       print_str(ce_umac);
+       print_signed(ce_irq_smp_affinity);
+       print_unsigned(ce_eeprom_mode);
+       print_bool(ce_production_mode);
+       print_bool(ci_pci_msi_enable);
+       print_unsigned_arr(ci_dma_lli_max_chan, TCV_MAX);
+       print_str(ce_country_code);
+       print_str(ce_ela_mode);
+       print_unsigned(ci_phy_dev);
+       print_signed(ce_debug_level);
+       print_unsigned(ce_host_pci_gen_ver);
+       print_bool(ce_temp_comp_en);
+       print_unsigned(ce_temp_protect_en);
+       print_signed(ce_temp_protect_delta);
+       print_signed(ce_temp_protect_th_max);
+       print_signed(ce_temp_protect_th_min);
+       print_unsigned(ce_temp_protect_tx_period_ms);
+       print_signed(ce_temp_protect_radio_off_th);
+       print_mac(ce_phys_mac_addr);
+       print_bool(ce_lam_enable);
+       print_unsigned(ce_first_mask_bit);
+       print_bool(ci_no_capture_noise_sleep);
+       print_unsigned_arr(ci_dcoc_mv_thr, CHNL_BW_MAX);
+       print_signed(ci_lolc_db_thr);
+       print_signed(ci_iq_db_thr);
+       print_bool(ci_rx_resched_tasklet);
+       print_unsigned(ci_rx_skb_max);
+       print_bool(ce_calib_scan_en);
+}
+
